Android 集成支付宝支付详解


一说到支付宝,相信没有人不知道,生活中付款,转账都会用到。

今天来详细介绍下在android中如何集成支付宝支付到自己的APP中去。让APP能够拥有方便,快捷的支付功能。

准备工作:

  • 商户在b.alipay.com里进行产品签约
  • RSA私钥及公钥生成
  • 上传RSA公钥,签名验证
  • 接口调用
一.商户在 b.alipay.com 里进行产品签约


商户或者开发者到b.alipay.com进行产品签约,获取商户的PID。

Android 集成支付宝支付详解_第1张图片

Android 集成支付宝支付详解_第2张图片


二.RSA私钥及公钥生成

生成方式一(推荐):使用支付宝提供的一键生成工具:

Windwos:点击下载
MAC OSX:点击下载
解压打开文件夹,直接运行“支付宝RAS密钥生成器SHAwithRSA1024_V1.0.bat”(WINDOWS)或“SHAwithRSA1024_V1.0.command”(MACOSX),点击“生成RSA密钥”,会自动生成公私钥,然后点击“打开文件位置”,即可找到工具自动生成的密钥。


生成方式二:也可以使用OpenSSL工具命令生成
首先进入OpenSSL工具,再输入以下命令。

OpenSSL> genrsa -out rsa_private_key.pem   1024  #生成私钥OpenSSL> pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -out rsa_private_key_pkcs8.pem #Java开发者需要将私钥转换成PKCS8格式OpenSSL> rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem #生成公钥OpenSSL> exit #退出OpenSSL程序

经过以上步骤,开发者可以在当前文件夹中(OpenSSL运行文件夹),看到rsa_private_key.pem(RSA私钥)、rsa_private_key_pkcs8.pem(pkcs8格式RSA私钥)和rsa_public_key.pem(对应RSA公钥)3个文件。开发者将私钥保留,将公钥提交给支付宝网关,用于验证签名。以下为私钥文件和公钥文件示例。

注意:对于使用Java的开发者,将pkcs8在console中输出的私钥去除头尾、换行和空格,作为开发者私钥,对于.NET和PHP的开发者来说,无需进行pkcs8命令行操作。

PKCS8处理后的私钥文件示例:

-----BEGIN PRIVATE KEY-----MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAN0yqPkLXlnhM+2H/57aHsYHaHXazr9pFQun907TMvmbR04wHChVsKVgGUF1hC0FN9hfeYT5v2SXg1WJSg2tSgk7F29SpsF0I36oSLCIszxdu7ClO7c22mxEVuCjmYpJdqb6XweAZzv4Is661jXP4PdrCTHRdVTU5zR9xUByiLSVAgMBAAECgYEAhznORRonHylm9oKaygEsqQGkYdBXbnsOS6busLi6xA+iovEUdbAVIrTCG9t854z2HAgaISoRUKyztJoOtJfI1wJaQU+XL+U3JIh4jmNx/k5UzJijfvfpT7Cv3ueMtqyAGBJrkLvXjiS7O5ylaCGuB0Qz711bWGkRrVoosPM3N6ECQQD8hVQUgnHEVHZYtvFqfcoq2g/onPbSqyjdrRu35a7PvgDAZx69Mr/XggGNTgT3jJn7+2XmiGkHM1fd1Ob/3uAdAkEA4D7aE3ZgXG/PQqlm3VbE/+4MvNl8xhjqOkByBOY2ZFfWKhlRziLEPSSAh16xEJ79WgY9iti+guLRAMravGrs2QJBAOmKWYeaWKNNxiIoF7/4VDgrcpkcSf3uRB44UjFSn8kLnWBUPo6WV+x1FQBdjqRviZ4NFGIP+KqrJnFHzNgJhVUCQFzCAukMDV4PLfeQJSmna8PFz2UKva8fvTutTryyEYu+PauaX5laDjyQbc4RIEMU0Q29CRX3BA8WDYg7YPGRdTkCQQCG+pjU2FB17ZLuKRlKEdtXNV6zQFTmFc1TKhlsDTtCkWs/xwkoCfZKstuV3Uc5J4BNJDkQOGm38pDRPcUDUh2/-----END PRIVATE KEY-----

公钥文件示例:

-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQWiDVZ7XYxa4CQsZoB3n7bfxLDkeGKjyQPt2FUtm4TWX9OYrd523iw6UUqnQ+Evfw88JgRnhyXadp+vnPKP7unormYQAfsM/CxzrfMoVdtwSiGtIJB4pfyRXjA+KL8nIa2hdQy5nLfgPVGZN4WidfUY/QpkddCVXnZ4bAUaQjXQIDAQAB-----END PUBLIC KEY-----

三.上传RSA公钥,签名验证

登录支付宝官方网站b.alipay.com,点击导航栏中“我的商家服务”,点击“查询PID、Key”,在“合作伙伴密钥管理”下(根据不同的产品选择对应的入口),点击“RSA加密”后的“添加密钥”,把自己的公钥复制进去

Android 集成支付宝支付详解_第3张图片

Android 集成支付宝支付详解_第4张图片


注意: 上传的公钥是一行格式,不允许有注释、空格、换行等!
点击“确认上传”,提示:上传成功,说明已经成功上传。

Android 集成支付宝支付详解_第5张图片


四.接口调用
首先,导入需要的支付宝SDK资源放入商户应用工程的libs目录下


右键 Build Path,将libs目录下的alipaySDK-20150602.jar导入,选中Order and Export,勾选alipaySDK-20151014.jar

Android 集成支付宝支付详解_第6张图片


拷贝sdk提供的类到工程下:
Android 集成支付宝支付详解_第7张图片
这几个类也很简单,不需要做打的修改,只改动pay.java里面的就好了
// 商户PIDpublic static final String PARTNER = "";// 商户收款账号public static final String SELLER = "";// 商户私钥,pkcs8格式public static final String RSA_PRIVATE = "";

添加上对应的参数,java私钥一定要是pkcs8格式的。


public class Pay {// 商户PIDpublic static final String PARTNER = "";// 商户收款账号public static final String SELLER = "";// 商户私钥,pkcs8格式public static final String RSA_PRIVATE = "";private static final int SDK_PAY_FLAG = 1;private Activity activity;public Pay(Activity activity) {this.activity = activity;}/** * call alipay sdk pay. 调用SDK支付 *  */public void pay(String name, String msg, String orderno, String money,final Handler handler) {// 订单String orderInfo = getOrderInfo(name, msg, orderno, money);// 对订单做RSA 签名String sign = sign(orderInfo);try {// 仅需对sign 做URL编码sign = URLEncoder.encode(sign, "UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}// 完整的符合支付宝参数规范的订单信息final String payInfo = orderInfo + "&sign=\"" + sign + "\"&"+ getSignType();Runnable payRunnable = new Runnable() {@Overridepublic void run() {// 构造PayTask 对象PayTask alipay = new PayTask(activity);// 调用支付接口,获取支付结果String result = alipay.pay(payInfo);Message msg = new Message();msg.what = SDK_PAY_FLAG;msg.obj = result;handler.sendMessage(msg);}};// 必须异步调用Thread payThread = new Thread(payRunnable);payThread.start();}/** * create the order info. 创建订单信息 *  */public String getOrderInfo(String subject, String body, String orderno,String price) {// 签约合作者身份IDString orderInfo = "partner=" + "\"" + PARTNER + "\"";// 签约卖家支付宝账号orderInfo += "&seller_id=" + "\"" + SELLER + "\"";// 商户网站唯一订单号orderInfo += "&out_trade_no=" + "\"" + orderno + "\"";// 商品名称orderInfo += "&subject=" + "\"" + subject + "\"";// 商品详情orderInfo += "&body=" + "\"" + body + "\"";// 商品金额orderInfo += "&total_fee=" + "\"" + price + "\"";// 服务器异步通知页面路径orderInfo += "¬ify_url=" + "\"" + "notify_URL" + "\"";// 服务接口名称, 固定值orderInfo += "&service=\"mobile.securitypay.pay\"";// 支付类型, 固定值orderInfo += "&payment_type=\"1\"";// 参数编码, 固定值orderInfo += "&_input_charset=\"utf-8\"";// 设置未付款交易的超时时间// 默认30分钟,一旦超时,该笔交易就会自动被关闭。// 取值范围:1m~15d。// m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。// 该参数数值不接受小数点,如1.5h,可转换为90m。orderInfo += "&it_b_pay=\"30m\"";// extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付// orderInfo += "&extern_token=" + "\"" + extern_token + "\"";// 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空orderInfo += "&return_url=\"m.alipay.com\"";// 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用)// orderInfo += "&paymethod=\"expressGateway\"";return orderInfo;}/** * get the out_trade_no for an order. 生成商户订单号,该值在商户端应保持唯一(可自定义格式规范) *  */public String getOutTradeNo() {SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss",Locale.getDefault());Date date = new Date();String key = format.format(date);Random r = new Random();key = key + r.nextInt();key = key.substring(0, 15);return key;}/** * sign the order info. 对订单信息进行签名 *  * @param content *            待签名订单信息 */public String sign(String content) {return SignUtils.sign(content, RSA_PRIVATE);}/** * get the sign type we use. 获取签名方式 *  */public String getSignType() {return "sign_type=\"RSA\"";}}

其中public void pay(String name, String msg, String orderno, String money,final Handler handler) 方法是调用支付是用到的,传的参数为商户的名字,商品计费名称,订单号和价格,最后一个Handler handler参数是用来接收支付回调发送消息的
支付的线程必须异步调用

// 服务器异步通知页面路径
orderInfo += "¬ify_url=" + "\"" + "notify_URL" + "\"";  这里要填写真实的回到地址,是支付宝回调通知服务器的。
orderInfo += "&it_b_pay=\"30m\"";  交易的超时时间默认30分钟,可以自己设置。 其余地方不用太大改动。


public class AppActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btn_pay = (Button) findViewById(R.id.btn_pay);btn_pay.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Pay pay = new Pay(AppActivity.this);pay.pay("商户名称", "商品计费名称", "订单号", "1", handler);}});}Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case 1: {PayResult payResult = new PayResult((String) msg.obj);// 支付宝返回此次支付结果及加签,建议对支付宝签名信息拿签约时支付宝提供的公钥做验签// String resultInfo = payResult.getResult();String resultStatus = payResult.getResultStatus();if (TextUtils.equals(resultStatus, "9000")) {Toast.makeText(AppActivity.this, "支付成功",Toast.LENGTH_SHORT).show();} else {// “8000”代表支付结果因为支付渠道原因或者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准(小概率状态)if (TextUtils.equals(resultStatus, "8000")) {Toast.makeText(AppActivity.this, "支付结果确认中",Toast.LENGTH_SHORT).show();} else {Toast.makeText(AppActivity.this, "支付失败",Toast.LENGTH_LONG).show();}}break;}}}};}

这里是模拟调用支付,点击按钮开始跳转支付,handler收到消息后判断支付状态。9000为支付成功,8000为支付确认中,其余支付失败

支付时出现偶尔出现java.security.spec.InvalidKeySpecException: java.lang.RuntimeException错误,需要调整一下RSA签名私钥,SignUtils 类
把KeyFactory keyf = KeyFactory.getInstance("RSA"); 改成KeyFactory keyf = KeyFactory.getInstance("RSA", "BC");
public class SignUtils {private static final String ALGORITHM = "RSA";private static final String SIGN_ALGORITHMS = "SHA1WithRSA";private static final String DEFAULT_CHARSET = "UTF-8";public static String sign(String content, String privateKey) {try {PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey));KeyFactory keyf = KeyFactory.getInstance("RSA", "BC");PrivateKey priKey = keyf.generatePrivate(priPKCS8);java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);signature.initSign(priKey);signature.update(content.getBytes(DEFAULT_CHARSET));byte[] signed = signature.sign();return Base64.encode(signed);} catch (Exception e) {e.printStackTrace();}return null;}}


公钥私钥一定要传正确才能签名成功
另外的Base64.java和PayResult.java两个类就不用做修改了。
常见的支付错误码如下: Android 集成支付宝支付详解_第8张图片


在商户应用工程的AndroidManifest.xml文件里面添加声明:

 

特别注意事项:
Android 集成支付宝支付详解_第9张图片

测试场景一定注意,安装支付宝钱包则直接跳转app支付,没安装则进入H5网页支付。
未安装支付宝钱包测试如下:
Android 集成支付宝支付详解_第10张图片 Android 集成支付宝支付详解_第11张图片 Android 集成支付宝支付详解_第12张图片 Android 集成支付宝支付详解_第13张图片 Android 集成支付宝支付详解_第14张图片


Button btn_pay = (Button) findViewById(R.id.btn_pay);btn_pay.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Pay pay = new Pay(AppActivity.this);pay.pay("商户名称", "商品计费名称", "1231321321", "1", handler);}});

传入参数是我任意填写的。
点击“支付按钮”,开始支付,未安装支付宝钱包,会自动跳转H5网页支付,第一次会输入手机号获取验证码,自动记录。再次进入时直接到确认付款页面,支付中途取消返回结果码为6001。


更多相关文章

  1. Android H5和App交互以及打开图库上传图片并显示
  2. Android中的Adapter 详解(三)
  3. android:background="@drawable/"图片拉伸问题
  4. Android UI框架 Android UI控件类简介 android5大布局详解
  5. Android图片资源的缩放问题
  6. Android大图片导致内存问题小结
  7. okhttp的应用详解与源码解析--okhttp客户端应用
  8. Android开发笔记之【Android API】Android 4.1 API官方文档详解
  9. Android 网络请求详解

随机推荐

  1. mysql 8.0.11 MSI版安装配置图文教程
  2. Windows10下mysql 8.0.12 解压版安装图文
  3. mysql server 5.7.20 安装配置方法图文教
  4. 如何安装MySQL Community Server 5.6.39
  5. mysql中影响数据库性能的因素讲解
  6. MySQL 数据备份与还原的示例代码
  7. mysql5.7.20第一次登录失败的快速解决方
  8. MySql总弹出mySqlInstallerConsole窗口的
  9. Windows10下mysql 5.7.21 Installer版安
  10. mysql5.7.20 安装配置方法图文教程(win10