Android 集成支付宝支付详解

男儿欲遂平生志,六经勤向窗前读。这篇文章主要讲述Android 集成支付宝支付详解相关的知识,希望能为你提供帮助。
一说到支付宝,相信没有人不知道,生活中付款,转账都会用到。
今天来详细介绍下在Android中如何集成支付宝支付到自己的APP中去。让APP能够拥有方便,快捷的支付功能。
准备工作:
商户在b.alipay.com里进行产品签约
RSA私钥及公钥生成
上传RSA公钥,签名验证
接口调用
一.商户在b.alipay.com里进行产品签约 
商户或者开发者到b.alipay.com进行产品签约,获取商户的PID。

Android 集成支付宝支付详解

文章图片

Android 集成支付宝支付详解

文章图片

   
  二.RSA私钥及公钥生成   生成方式一(推荐):使用支付宝提供的一键生成工具:   Windwos:点击下载 MAC OSX:点击下载
解压打开文件夹,直接运行“支付宝RAS密钥生成器SHAwithRSA1024_V1.0.bat”(WINDOWS)或“SHAwithRSA1024_V1.0.command”(MACOSX),点击“生成RSA密钥”,会自动生成公私钥,然后点击“打开文件位置”,即可找到工具自动生成的密钥。     生成方式二:也可以使用OpenSSL工具命令生成
首先进入OpenSSL工具,再输入以下命令。   [java]  view plain  copy
  1. < span  style="font-size:12px"> OpenSSL>   genrsa  -out  rsa_private_key.pem      1024    #生成私钥   
  2. OpenSSL>   pkcs8  -topk8  -inform  PEM  -in  rsa_private_key.pem  -outform  PEM  -nocrypt  -out  rsa_private_key_pkcs8.pem  #java开发者需要将私钥转换成PKCS8格式   
  3. OpenSSL>   rsa  -in  rsa_private_key.pem  -pubout  -out  rsa_public_key.pem  #生成公钥   
  4. OpenSSL>   exit  #退出OpenSSL程序< /span>    
经过以上步骤,开发者可以在当前文件夹中(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处理后的私钥文件示例:
 
[java]  view plain  copy
  1. < span  style="font-size:12px"> -----BEGIN  PRIVATE  KEY-----   
  2. MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAN0yqPkLXlnhM+2H/57aHsYHaHXazr9pFQun907TMvmbR04wHChVsKVgGUF1hC0FN9hfeYT5v2SXg1WJSg2tSgk7F29SpsF0I36oSLCIszxdu7ClO7c22mxEVuCjmYpJdqb6XweAZzv4Is661jXP4PdrCTHRdVTU5zR9xUByiLSVAgMBAAECgYEAhznORRonHylm9oKaygEsqQGkYdBXbnsOS6busLi6xA+iovEUdbAVIrTCG9t854z2HAgaISoRUKyztJoOtJfI1wJaQU+XL+U3JIh4jmNx/k5UzJijfvfpT7Cv3ueMtqyAGBJrkLvXjiS7O5ylaCGuB0Qz711bWGkRrVoosPM3N6ECQQD8hVQUgnHEVHZYtvFqfcoq2g/onPbSqyjdrRu35a7PvgDAZx69Mr/XggGNTgT3jJn7+2XmiGkHM1fd1Ob/3uAdAkEA4D7aE3ZgXG/PQqlm3VbE/+4MvNl8xhjqOkByBOY2ZFfWKhlRziLEPSSAh16xEJ79WgY9iti+guLRAMravGrs2QJBAOmKWYeaWKNNxiIoF7/4VDgrcpkcSf3uRB44UjFSn8kLnWBUPo6WV+x1FQBdjqRviZ4NFGIP+KqrJnFHzNgJhVUCQFzCAukMDV4PLfeQJSmna8PFz2UKva8fvTutTryyEYu+PauaX5laDjyQbc4RIEMU0Q29CRX3BA8WDYg7YPGRdTkCQQCG+pjU2FB17ZLuKRlKEdtXNV6zQFTmFc1TKhlsDTtCkWs/xwkoCfZKstuV3Uc5J4BNJDkQOGm38pDRPcUDUh2/   
  3. -----END  PRIVATE  KEY-----< /span>    
 
【Android 集成支付宝支付详解】公钥文件示例:
 
[java]  view plain  copy
  1. < span  style="font-size:12px"> -----BEGIN  PUBLIC  KEY-----   
  2. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQWiDVZ7XYxa4CQsZoB3n7bfxLDkeGKjyQPt2FUtm4TWX9OYrd523iw6UUqnQ+Evfw88JgRnhyXadp+vnPKP7unormYQAfsM/CxzrfMoVdtwSiGtIJB4pfyRXjA+KL8nIa2hdQy5nLfgPVGZN4WidfUY/QpkddCVXnZ4bAUaQjXQIDAQAB   
  3. -----END  PUBLIC  KEY-----< /span>    
 
三.上传RSA公钥,签名验证登录支付宝官方网站b.alipay.com,点击导航栏中“我的商家服务”,点击“查询PID、Key”,在“合作伙伴密钥管理”下(根据不同的产品选择对应的入口),点击“RSA加密”后的“添加密钥”,把自己的公钥复制进去
Android 集成支付宝支付详解

文章图片

 
Android 集成支付宝支付详解

文章图片

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

文章图片

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

文章图片
  右键 Build Path,将libs目录下的alipaySDK-20150602.jar导入,选中Order and Export,勾选alipaySDK-20151014.jar  
Android 集成支付宝支付详解

文章图片
    拷贝sdk提供的类到工程下:  
Android 集成支付宝支付详解

文章图片
  这几个类也很简单,不需要做打的修改,只改动pay.java里面的就好了   [java]  view plain  copy
  1. < span  style="font-size:12px"> //  商户PID   
  2. public  static  final  String  PARTNER  =  "";    
  3. //  商户收款账号   
  4. public  static  final  String  SELLER  =  "";    
  5. //  商户私钥,pkcs8格式   
  6. public  static  final  String  RSA_PRIVATE  =  ""; < /span>    

添加上对应的参数,java私钥一定要是pkcs8格式的。     [java]  view plain  copy
  1. < span  style="font-size:12px"> public  class  Pay  {   
  2.         //  商户PID   
  3.         public  static  final  String  PARTNER  =  "";    
  4.         //  商户收款账号   
  5.         public  static  final  String  SELLER  =  "";    
  6.         //  商户私钥,pkcs8格式   
  7.         public  static  final  String  RSA_PRIVATE  =  "";    
  8.         private  static  final  int  SDK_PAY_FLAG  =  1;    
  9.         private  Activity  activity;    
  10.    
  11.         public  Pay(Activity  activity)  {   
  12.                 this.activity  =  activity;    
  13.         }   
  14.    
  15.         /** 
  16.           *  call  alipay  sdk  pay.  调用SDK支付 
  17.           *   
  18.           */   
  19.         public  void  pay(String  name,  String  msg,  String  orderno,  String  money,   
  20.                         final  Handler  handler)  {   
  21.                 //  订单   
  22.                 String  orderInfo  =  getOrderInfo(name,  msg,  orderno,  money);    
  23.                 //  对订单做RSA  签名   
  24.                 String  sign  =  sign(orderInfo);    
  25.                 try  {   
  26.                         //  仅需对sign  做URL编码   
  27.                         sign  =  URLEncoder.encode(sign,  "UTF-8");    
  28.                 }  catch  (UnsupportedEncodingException  e)  {   
  29.                         e.printStackTrace();    
  30.                 }   
  31.    
  32.                 //  完整的符合支付宝参数规范的订单信息   
  33.                 final  String  payInfo  =  orderInfo  +  "& sign=\""  +  sign  +  "\"& "   
  34.                                 +  getSignType();    
  35.    
  36.                 Runnable  payRunnable  =  new  Runnable()  {   
  37.    
  38.                         @Override   
  39.                         public  void  run()  {   
  40.                                 //  构造PayTask  对象   
  41.                                 PayTask  alipay  =  new  PayTask(activity);    
  42.                                 //  调用支付接口,获取支付结果   
  43.                                 String  result  =  alipay.pay(payInfo);    
  44.    
  45.                                 Message  msg  =  new  Message();    
  46.                                 msg.what  =  SDK_PAY_FLAG;    
  47.                                 msg.obj  =  result;    
  48.                                 handler.sendMessage(msg);    
  49.                         }   
  50.                 };    
  51.    
  52.                 //  必须异步调用   
  53.                 Thread  payThread  =  new  Thread(payRunnable);    
  54.                 payThread.start();    
  55.         }   
  56.    
  57.         /** 
  58.           *  create  the  order  info.  创建订单信息 
  59.           *   
  60.           */   
  61.         public  String  getOrderInfo(String  subject,  String  body,  String  orderno,   
  62.                         String  price)  {   
  63.    
  64.                 //  签约合作者身份ID   
  65.                 String  orderInfo  =  "partner="  +  "\""  +  PARTNER  +  "\"";    
  66.    
  67.                 //  签约卖家支付宝账号   
  68.                 orderInfo  +=  "& seller_id="  +  "\""  +  SELLER  +  "\"";    
  69.    
  70.                 //  商户网站唯一订单号   
  71.                 orderInfo  +=  "& out_trade_no="  +  "\""  +  orderno  +  "\"";    
  72.    
  73.                 //  商品名称   
  74.                 orderInfo  +=  "& subject="  +  "\""  +  subject  +  "\"";    
  75.    
  76.                 //  商品详情   
  77.                 orderInfo  +=  "& body="  +  "\""  +  body  +  "\"";    
  78.    
  79.                 //  商品金额   
  80.                 orderInfo  +=  "& total_fee="  +  "\""  +  price  +  "\"";    
  81.    
  82.                 //  服务器异步通知页面路径   
  83.                 orderInfo  +=  "?ify_url="  +  "\""  +  "notify_URL"  +  "\"";    
  84.    
  85.                 //  服务接口名称,  固定值   
  86.                 orderInfo  +=  "& service=\"mobile.securitypay.pay\"";    
  87.    
  88.                 //  支付类型,  固定值   
  89.                 orderInfo  +=  "& payment_type=\"1\"";    
  90.    
  91.                 //  参数编码,  固定值   
  92.                 orderInfo  +=  "& _input_charset=\"utf-8\"";    
  93.    
  94.                 //  设置未付款交易的超时时间   
  95.                 //  默认30分钟,一旦超时,该笔交易就会自动被关闭。   
  96.                 //  取值范围:1m~15d。   
  97.                 //  m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。   
  98.                 //  该参数数值不接受小数点,如1.5h,可转换为90m。   
  99.                 orderInfo  +=  "& it_b_pay=\"30m\"";    
  100.    
  101.                 //  extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付   
  102.                 //  orderInfo  +=  "& extern_token="  +  "\""  +  extern_token  +  "\"";    
  103.    
  104.                 //  支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空   
  105.                 orderInfo  +=  "& return_url=\"m.alipay.com\"";    
  106.    
  107.                 //  调用银行卡支付,需配置此参数,参与签名,  固定值  (需要签约《无线银行卡快捷支付》才能使用)   
  108.                 //  orderInfo  +=  "& paymethod=\"expressGateway\"";    
  109.    
  110.                 return  orderInfo;    
  111.         }   
  112.    
  113.         /** 
  114.           *  get  the  out_trade_no  for  an  order.  生成商户订单号,该值在商户端应保持唯一(可自定义格式规范) 
  115.           *   
  116.           */   
  117.         public  String  getOutTradeNo()  {   
  118.                 SimpleDateFormat  format  =  new  SimpleDateFormat("MMddHHmmss",   
  119.                                 Locale.getDefault());    
  120.                 Date  date  =  new  Date();    
  121.                 String  key  =  format.format(date);    
  122.    
  123.                 Random  r  =  new  Random();    
  124.                 key  =  key  +  r.nextInt();    
  125.                 key  =  key.substring(0,  15);    
  126.                 return  key;    
  127.         }   
  128.    
  129.         /** 
  130.           *  sign  the  order  info.  对订单信息进行签名 
  131.           *   
  132.           *  @param  content 
  133.           *                        待签名订单信息 
  134.           */   
  135.         public  String  sign(String  content)  {   
  136.                 return  SignUtils.sign(content,  RSA_PRIVATE);    
  137.         }   
  138.    
  139.         /** 
  140.           *  get  the  sign  type  we  use.  获取签名方式 
  141.           *   
  142.           */   
  143.         public  String  getSignType()  {   
  144.                 return  "sign_type=\"RSA\"";    
  145.         }   
  146.    
  147. }< /span>    
  其中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分钟,可以自己设置。 其余地方不用太大改动。     [java]  view plain  copy
  1. < span  style="font-size:12px"> public  class  AppActivity  extends  Activity  {   
  2.    
  3.         @Override   
  4.         protected  void  onCreate(Bundle  savedInstanceState)  {   
  5.                 super.onCreate(savedInstanceState);    
  6.                 setContentView(R.layout.activity_main);    
  7.                 Button  btn_pay  =  (Button)  findViewById(R.id.btn_pay);    
  8.                 btn_pay.setOnClickListener(new  OnClickListener()  {   
  9.    
  10.                         @Override   
  11.                         public  void  onClick(View  v)  {   
  12.                                 Pay  pay  =  new  Pay(AppActivity.this);    
  13.                                 pay.pay("商户名称",  "商品计费名称",  "订单号",  "1",  handler);    
  14.    
  15.                         }   
  16.                 });    
  17.    
  18.         }   
  19.    
  20.         Handler  handler  =  new  Handler()  {   
  21.                    
  22.                 @Override   
  23.                 public  void  handleMessage(Message  msg)  {   
  24.                         super.handleMessage(msg);    
  25.                         switch  (msg.what)  {   
  26.                         case  1:  {   
  27.                                 PayResult  payResult  =  new  PayResult((String)  msg.obj);    
  28.                                 //  支付宝返回此次支付结果及加签,建议对支付宝签名信息拿签约时支付宝提供的公钥做验签   
  29.                                 //  String  resultInfo  =  payResult.getResult();    
  30.                                 String  resultStatus  =  payResult.getResultStatus();    
  31.                                 if  (TextUtils.equals(resultStatus,  "9000"))  {   
  32.                                         Toast.makeText(AppActivity.this,  "支付成功",   
  33.                                                         Toast.LENGTH_SHORT).show();    
  34.                                 }  else  {   
  35.                                         //  “8000”代表支付结果因为支付渠道原因或者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准(小概率状态)   
  36.                                         if  (TextUtils.equals(resultStatus,  "8000"))  {   
  37.                                                 Toast.makeText(AppActivity.this,  "支付结果确认中",   
  38.                                                                 Toast.LENGTH_SHORT).show();    
  39.                                         }  else  {   
  40.                                                 Toast.makeText(AppActivity.this,  "支付失败",   
  41.                                                                 Toast.LENGTH_LONG).show();    
  42.                                         }   
  43.                                 }   
  44.                                 break;    
  45.                         }   
  46.                         }   
  47.                 }   
  48.         };    
  49.    
  50. }< /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
  1. < span  style="font-size:12px"> public  class  SignUtils  {   
  2.    
  3.         private  static  final  String  ALGORITHM  =  "RSA";    
  4.    
  5.         private  static  final  String  SIGN_ALGORITHMS  =  "SHA1WithRSA";    
  6.    
  7.         private  static  final  String  DEFAULT_CHARSET  =  "UTF-8";    
  8.    
  9.         public  static  String  sign(String  content,  String  privateKey)  {   
  10.                 try  {   
  11.                         PKCS8EncodedKeySpec  priPKCS8  =  new  PKCS8EncodedKeySpec(   
  12.                                         Base64.decode(privateKey));    
  13.                         KeyFactory  keyf  =  KeyFactory.getInstance("RSA",  "BC");    
  14.                         PrivateKey  priKey  =  keyf.generatePrivate(priPKCS8);    
  15.    
  16.                         java.security.Signature  signature  =  java.security.Signature   
  17.                                         .getInstance(SIGN_ALGORITHMS);    
  18.    
  19.                         signature.initSign(priKey);    
  20.                         signature.update(content.getBytes(DEFAULT_CHARSET));    
  21.    
  22.                         byte[]  signed  =  signature.sign();    
  23.    
  24.                         return  Base64.encode(signed);    
  25.                 }  catch  (Exception  e)  {   
  26.                         e.printStackTrace();    
  27.                 }   
  28.    
  29.                 return  null;    
  30.         }   
  31.    
  32. }< /span>    
  公钥私钥一定要传正确才能签名成功。   另外的Base64.java和PayResult.java两个类就不用做修改了。   常见的支付错误码如下:
Android 集成支付宝支付详解

文章图片
    在商户应用工程的androidManifest.xml文件里面添加声明:   [java]  view plain  copy
  1. < span  style="font-size:12px">    
  2.    
  3.    
  4.   < /span>    
[java]  view plain  copy
  1. < span  style="font-size:12px">    
  2.    
  3.    
  4.    
  5. < /span>    

特别注意事项:
Android 集成支付宝支付详解

文章图片

  测试场景一定注意,安装支付宝钱包则直接跳转app支付,没安装则进入H5网页支付。   未安装支付宝钱包测试如下:  
Android 集成支付宝支付详解

文章图片
Android 集成支付宝支付详解

文章图片
Android 集成支付宝支付详解

文章图片
Android 集成支付宝支付详解

文章图片
Android 集成支付宝支付详解

文章图片
    [java]  view plain  copy
  1. Button  btn_pay  =  (Button)  findViewById(R.id.btn_pay);    
  2.                 btn_pay.setOnClickListener(new  OnClickListener()  {   
  3.    
  4.                         @Override   
  5.                         public  void  onClick(View  v)  {   
  6.                                 Pay  pay  =  new  Pay(AppActivity.this);    
  7.                                 pay.pay("商户名称",  "商品计费名称",  "1231321321",  "1",  handler);    
  8.    
  9.                         }   
  10.                 });    

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
















    推荐阅读