男儿欲遂平生志,六经勤向窗前读。这篇文章主要讲述Android 集成支付宝支付详解相关的知识,希望能为你提供帮助。
一说到支付宝,相信没有人不知道,生活中付款,转账都会用到。
今天来详细介绍下在Android中如何集成支付宝支付到自己的APP中去。让APP能够拥有方便,快捷的支付功能。
准备工作:
商户在b.alipay.com里进行产品签约
RSA私钥及公钥生成
上传RSA公钥,签名验证
接口调用
一.商户在b.alipay.com里进行产品签约
商户或者开发者到b.alipay.com进行产品签约,获取商户的PID。
文章图片
文章图片
二.RSA私钥及公钥生成 生成方式一(推荐):使用支付宝提供的一键生成工具: Windwos:点击下载 MAC OSX:点击下载
解压打开文件夹,直接运行“支付宝RAS密钥生成器SHAwithRSA1024_V1.0.bat”(WINDOWS)或“SHAwithRSA1024_V1.0.command”(MACOSX),点击“生成RSA密钥”,会自动生成公私钥,然后点击“打开文件位置”,即可找到工具自动生成的密钥。 生成方式二:也可以使用OpenSSL工具命令生成
首先进入OpenSSL工具,再输入以下命令。 [java] view plain copy
- < span style="font-size:12px"> 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程序< /span>
注意:对于使用Java的开发者,将pkcs8在console中输出的私钥去除头尾、换行和空格,作为开发者私钥,对于.NET和php的开发者来说,无需进行pkcs8命令行操作。
PKCS8处理后的私钥文件示例:
[java] view plain copy
- < span style="font-size:12px"> -----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-----< /span>
【Android 集成支付宝支付详解】公钥文件示例:
[java] view plain copy
- < span style="font-size:12px"> -----BEGIN PUBLIC KEY-----
- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQWiDVZ7XYxa4CQsZoB3n7bfxLDkeGKjyQPt2FUtm4TWX9OYrd523iw6UUqnQ+Evfw88JgRnhyXadp+vnPKP7unormYQAfsM/CxzrfMoVdtwSiGtIJB4pfyRXjA+KL8nIa2hdQy5nLfgPVGZN4WidfUY/QpkddCVXnZ4bAUaQjXQIDAQAB
- -----END PUBLIC KEY-----< /span>
三.上传RSA公钥,签名验证登录支付宝官方网站b.alipay.com,点击导航栏中“我的商家服务”,点击“查询PID、Key”,在“合作伙伴密钥管理”下(根据不同的产品选择对应的入口),点击“RSA加密”后的“添加密钥”,把自己的公钥复制进去
文章图片
文章图片
注意:上传的公钥是一行格式,不允许有注释、空格、换行等! 点击“确认上传”,提示:上传成功,说明已经成功上传。
文章图片
四.接口调用 首先,导入需要的支付宝SDK资源放入商户应用工程的libs目录下
文章图片
右键 Build Path,将libs目录下的alipaySDK-20150602.jar导入,选中Order and Export,勾选alipaySDK-20151014.jar
文章图片
拷贝sdk提供的类到工程下:
文章图片
这几个类也很简单,不需要做打的修改,只改动pay.java里面的就好了 [java] view plain copy
- < span style="font-size:12px"> // 商户PID
- public static final String PARTNER = "";
- // 商户收款账号
- public static final String SELLER = "";
- // 商户私钥,pkcs8格式
- public static final String RSA_PRIVATE = ""; < /span>
添加上对应的参数,java私钥一定要是pkcs8格式的。 [java] view plain copy
- < span style="font-size:12px"> public class Pay {
- // 商户PID
- public 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() {
- @Override
- public 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) {
- // 签约合作者身份ID
- String 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\"";
- }
- }< /span>
// 服务器异步通知页面路径 orderInfo += "?ify_url=" + "\"" + "notify_URL" + "\""; 这里要填写真实的回到地址,是支付宝回调通知服务器的。 orderInfo += "& it_b_pay=\"30m\""; 交易的超时时间默认30分钟,可以自己设置。 其余地方不用太大改动。 [java] view plain copy
- < span style="font-size:12px"> public class AppActivity extends Activity {
- @Override
- protected 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() {
- @Override
- public void onClick(View v) {
- Pay pay = new Pay(AppActivity.this);
- pay.pay("商户名称", "商品计费名称", "订单号", "1", handler);
- }
- });
- }
- Handler handler = new Handler() {
- @Override
- public 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;
- }
- }
- }
- };
- }< /span>
这里是模拟调用支付,点击按钮开始跳转支付,handler收到消息后判断支付状态。9000为支付成功,8000为支付确认中,其余支付失败。 支付时出现偶尔出现java.security.spec.InvalidKeySpecException: java.lang.RuntimeException错误,需要调整一下RSA签名私钥,SignUtils 类 把KeyFactory keyf = KeyFactory.getInstance("RSA"); 改成KeyFactory keyf = KeyFactory.getInstance("RSA", "BC"); [java] view plain copy
- < span style="font-size:12px"> 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;
- }
- }< /span>
文章图片
在商户应用工程的androidManifest.xml文件里面添加声明: [java] view plain copy
- < span style="font-size:12px">
- < /span>
- < span style="font-size:12px">
- < /span>
特别注意事项:
文章图片
测试场景一定注意,安装支付宝钱包则直接跳转app支付,没安装则进入H5网页支付。 未安装支付宝钱包测试如下:
文章图片
文章图片
文章图片
文章图片
文章图片
[java] view plain copy
- Button btn_pay = (Button) findViewById(R.id.btn_pay);
- btn_pay.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Pay pay = new Pay(AppActivity.this);
- pay.pay("商户名称", "商品计费名称", "1231321321", "1", handler);
- }
- });
传入参数是我任意填写的。 点击“支付按钮”,开始支付,未安装支付宝钱包,会自动跳转H5网页支付,第一次会输入手机号获取验证码,自动记录。再次进入时直接到确认付款页面,支付中途取消返回结果码为6001。
推荐阅读
- Android的热修复-微信Tinker
- android 图像的一些操作处理
- 关于Android6.0之后的权限问题
- android权限大全
- Android SurfaceView 绘图覆盖刷新及脏矩形刷新方法
- Android主题换肤 无缝切换
- android 换肤模式总结
- android保存照片到相册的一些事
- Android 蓝牙开发之搜索配对连接通信大全