android 手把手教你实现集成支付宝支付功能

https://blog.csdn.net/mr_jianrong/article/details/71728062

项目需要,需要在客户端集成支付宝接口。第一次集成,过程还是挺简单的,不过由于支付宝官方文档写的不够清晰,也是走了一些弯路,下面把过程写出来分享给大家。就研究了一下:因为使用支付宝接口,就需要到支付宝官网:注册帐号,并申请。下面讲的是申请好之后的操作。登录成功之后,   店家我的商家服务—在页面的下方找到——>签约管理—>找打 移动支付—–>点击下载集成文档—>跳到新的页面,在页面下方—>找到下载开发包,下载移动支付即可。然后解压出来之后一般会得到三个文件夹。


一、申请移动支付权限

首先登录【支付宝开放平台】http://open.alipay.com/platform/home.htm,添加应用,申请移动支付权限。申请开通支付,是需要公司文件的,个人是不允许开始支付的。
具体细节就不再详聊了,下面就讲讲如何将阿里给出的demo运行起来。

二、阿里支付DEMO

1、概述

(1)支付调用页面及测试

支付宝在调用时,会首先看本地是不是存在支付宝客户端,如果有的话,就直接调用客户端进行支付,如果没有,则调用jar包中的H5页面支付。
所以在测试时,需要有测试两种情境:有支付宝客户端和没有支付宝客户端的情况。

(2)、客户端与服务器

在demo中大家可以看到,有客户端的demo也有服务端的demo,大家可能觉得需要服务端写好之后,客户端才能集成,其实并不是。整个流程是这样的:
1,APP客户端通过SDK发送支付请求 (客户端处理)
2,SDK支付成功并同步返回支付结果(客户端处理)
3,支付宝服务器向我们的服务器发送支付结果字符串(服务端处理)
客户端:从上面的流程可以看出,服务端只是用来接出异步返回的支付结果的。而支付与同步结果返回都是在客户端可以直接看得到的。所以在集成支付宝支付接口时,主要功能是在客户端,即便服务端没有做集成,也是可能付款成功的。
服务端:服务端只需要添加一个功能:接口支付结果返回

下面几张图显示了整个demo的运行过程,由于没办法在真机上录制gif,所以只能用图片来代替了。
初始化界面:

点击支付后,跳出确认付款界面:


点击确认付款后,跳出输入密码界面:


最后是支付成功界面:


在看DEMO的代码之前,我们需要先配置几个变量:

2、配置几个变量

这部分会对代码中用到的几个变量的找到方法或生成方法进行讲述,部分资料引自支付宝开放平台。

(1)PID

合作者身份ID(PID)是商户与支付宝签约后,商户获得的支付宝商户唯一识别码。当商户把支付宝功能接入商户网站时会用到PID,以便让支付宝认证商户。
查看PID步骤如下:
1、登录支付宝官方网站b.alipay.com
2、点击导航栏中“商家服务”


3、点击“查询PID、Key”


(2)、APPID、APP SECRET和支付宝公钥

https://openhome.alipay.com/platform/createApp.htm 页面,创建一个应用


完成之后:在我的应用中是可以看得到的:


然后转到帐户基本信息页面:https://openhome.alipay.com/platform/keyManage.htm


在开放平台密钥栏,可以找到APPID,APP SECRET,和支付宝密钥
这三个数据,都是在应用创建后,支付宝为我们生成好的,无法更改!

(3)、生成商户私钥【windows生成方法】

(有关mac的生成方法,下面会再补充)
1、下载DEMO及SDK
到文档中心,查看移动支付对应的文档,文档地址:http://doc.open.alipay.com/doc2/detail?treeId=59&articleId=103563&docType=1
然后,点击(SDK&DEMO下载)下载代码


2、得到原始私钥
在代码中的DEMO/openssl/bin目录下,有openssl.exe文件


打开openssl.exe
输入

[java]  view plain copy
  1. genrsa -out rsa_private_key.pem 1024  
得到生成成功的结果,如下图:

此时,我们可以在bin文件夹中看到一个文件名为rsa_private_key.pem的文件


用记事本方式打开它,可以看到-----BEGIN RSA PRIVATE KEY-----开头,-----END RSA PRIVATE KEY-----结尾的没有换行的字符串,这个就是原始的私钥。


但这段原始私钥代码中是用不到的,我们需要将它转化为PKCS8格式
3、转换为PKCS8格式
在openssl.exe中输入:并回车

[java]  view plain copy
  1. pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt  
得到生成功的结果,这个结果就是PKCS8格式的私钥,如下图:


注意,私钥是红框包括的那部分,是不包含BEGIN PRIVATE KEY和END PRIVATE KEY这两行的。

右键点击openssl窗口上边边缘,选择编辑→标记,选中要复制的文字(如上图),
此时继续右键点击openssl窗口上边边缘,选择编辑→复制,
把复制的内容粘土进一个新的记事本中,可随便命名,只要知道这个是PKCS8格式的私钥即可。

(4)、生成商户私钥【MAC生成方法】

这里来讲一下mac端如何生成用户私钥的,由于mac系统是自带openssl的,所以只需要打开终端,利用cd 命令切到任意一个想存放生成Key的文件夹下:
比如,切到下载目录下


然后运行下面的命令来生成私钥原始密钥

[java]  view plain copy
  1. openssl genrsa -out rsa_private_key.pem 1024  
然后运行下面的命令来生成转换的PCKS8格式的命令。
[java]  view plain copy
  1. openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt  
然后将生成的私钥复制保存起来。
从上面的命令可以看出,与windows相比,mac上需要在前面添加openssl指定运行的是openssl命令。其它命令是完全一致的。

(5)、生成用户公钥及网页填充

1、生成公钥
同样对于windows用户而言,直接在openssl.exe中输入下面的命令:
[java]  view plain copy
  1. rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem  
同样,如果是Mac的同学,输入的命令应该是如下:
[java]  view plain copy
  1. openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem  
得到生成成功的结果,如下图:

此时,我们可以在bin文件夹中看到一个文件名为rsa_public_key.pem的文件,用记事本方式打开它,可以看到-----BEGIN PUBLIC KEY-----开头,
-----END PUBLIC KEY-----结尾的没有换行的字符串,这个就是公钥。



在生成网页以后,复制----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----之间的部分,即那段纯代码,不要把----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----给复制进去了。中间的这部分就是公钥。
2、网页填充

上传RSA公钥,在“合作伙伴密钥管理”下,点击“RSA加密”后的“添加密钥”,把自己的公钥复制进去。注意不能有空格,换行之类的。

  

点击确认上传,若是提示上传成功。则就是成功。

这个时候就可查看支付宝公钥了。如图:


至此,将对应的私钥与公钥填到相应位置我们的Demo  就可一运行了。到这里,所有的准备工作都已经结束了。下面就是配置DEMO的过程了

3、配置DEMO

在刚才下载的sdk&demo的源码中,打开DEMO/客户端demo/支付宝Android 15.0.1/alipay_demo工程

第一步:

将Demo中libs 文件夹下面的支付宝jar 包拷贝到 所需要引入的项目中的libs 文件下,如果没有此文件,可以自己在项目中新建libs 文件,并将sdk的jar包引入其中。

第二步:

配置AndroidManifest.xml文件。此文件大都是配置信息的。集成支付宝,当然也不例外。下面的代码也是从Demo中拷贝过来的,信息如下:

<span class="comment" style="color: rgb(153, 153, 136); font-style: italic;"><!-- alipay sdk begin --></span>
<span class="tag" style="color: rgb(0, 0, 128);"><<span class="title">activity
<span class="indent">  </span>android:name="com.alipay.sdk.app.H5PayActivity"
<span class="indent">  </span>android:configChanges="orientation|keyboardHidden|navigation"
<span class="indent">  </span>android:exported="false"
<span class="indent">  </span>android:screenOrientation="behind"
<span class="indent">  </span>android:windowSoftInputMode="adjustResize|stateHidden"</span> ></span>
<span class="tag" style="color: rgb(0, 0, 128);"></<span class="title">activity</span>></span>
<span class="comment" style="color: rgb(153, 153, 136); font-style: italic;"><!-- alipay sdk end --></span>

可以看到的是这是一个Activity.配置文件。就如平常的注册Activity 一样,放在application节点之中即可。下面是权限的配置:

<span class="tag" style="color: rgb(0, 0, 128);"><<span class="title">uses-permission</span> <span class="attribute" style="color: rgb(0, 128, 128);">android:name</span>=<span class="value" style="color: rgb(221, 17, 68);">"android.permission.INTERNET"</span> /></span>
    <span class="tag" style="color: rgb(0, 0, 128);"><<span class="title">uses-permission</span> <span class="attribute" style="color: rgb(0, 128, 128);">android:name</span>=<span class="value" style="color: rgb(221, 17, 68);">"android.permission.WRITE_EXTERNAL_STORAGE"</span> /></span>
    <span class="tag" style="color: rgb(0, 0, 128);"><<span class="title">uses-permission</span> <span class="attribute" style="color: rgb(0, 128, 128);">android:name</span>=<span class="value" style="color: rgb(221, 17, 68);">"android.permission.ACCESS_NETWORK_STATE"</span> /></span>
    <span class="tag" style="color: rgb(0, 0, 128);"><<span class="title">uses-permission</span> <span class="attribute" style="color: rgb(0, 128, 128);">android:name</span>=<span class="value" style="color: rgb(221, 17, 68);">"android.permission.READ_PHONE_STATE"</span> /></span>
    <span class="tag" style="color: rgb(0, 0, 128);"><<span class="title">uses-permission</span> <span class="attribute" style="color: rgb(0, 128, 128);">android:name</span>=<span class="value" style="color: rgb(221, 17, 68);">"android.permission.ACCESS_WIFI_STATE"</span> /></span>

这是必要的权限,如果添加过的,就不需要重新添加了。没有的,则需要添加到里面。

第三步:

拷贝Java文件,同样是Demo 文件中,在你需要引入支付宝的项目中新建一个包,来存放必须要的Java 文件。分别是下面几个文件: Base64.java,PayResult.java与SignUtils.java 文件,我下载的是alipaySDK.jar 的jar 包。只需要引入这些文件即可。

第四步:

下面就是主要Activity的代码的引入了。主要代码如下:

<span class="keyword" style="font-weight: bold;">public</span> <span class="keyword" style="font-weight: bold;">static</span> <span class="keyword" style="font-weight: bold;">final</span> String PARTNER = <span class="string" style="color: rgb(221, 17, 68);">"注册账户的PID"</span>;
<span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 商户收款账号</span>
<span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> <span class="keyword" style="font-weight: bold;">static</span> <span class="keyword" style="font-weight: bold;">final</span> String SELLER = <span class="string" style="color: rgb(221, 17, 68);">"支付宝收款账户"</span>;
<span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 商户私钥,pkcs8格式</span>
<span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> <span class="keyword" style="font-weight: bold;">static</span> <span class="keyword" style="font-weight: bold;">final</span> String RSA_PRIVATE = <span class="string" style="color: rgb(221, 17, 68);">"商户私钥"</span>;
<span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 支付宝公钥</span>
<span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> <span class="keyword" style="font-weight: bold;">static</span> <span class="keyword" style="font-weight: bold;">final</span> String RSA_PUBLIC = <span class="string" style="color: rgb(221, 17, 68);">"支付宝公钥"</span>;

<span class="indent">  </span><span class="keyword" style="font-weight: bold;">private</span> <span class="keyword" style="font-weight: bold;">static</span> <span class="keyword" style="font-weight: bold;">final</span> <span class="keyword" style="font-weight: bold;">int</span> SDK_PAY_FLAG = <span class="number" style="color: rgb(0, 153, 153);">1</span>;

<span class="indent">  </span><span class="keyword" style="font-weight: bold;">private</span> <span class="keyword" style="font-weight: bold;">static</span> <span class="keyword" style="font-weight: bold;">final</span> <span class="keyword" style="font-weight: bold;">int</span> SDK_CHECK_FLAG = <span class="number" style="color: rgb(0, 153, 153);">2</span>;

<span class="indent">  </span><span class="keyword" style="font-weight: bold;">private</span> Handler mHandler = <span class="keyword" style="font-weight: bold;">new</span> Handler() {
<span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> <span class="keyword" style="font-weight: bold;">void</span> handleMessage(Message msg) {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">switch</span> (msg.what) {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">case</span> SDK_PAY_FLAG: {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>PayResult payResult = <span class="keyword" style="font-weight: bold;">new</span> PayResult((String) msg.obj);

<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 支付宝返回此次支付结果及加签,建议对支付宝签名信息拿签约时支付宝提供的公钥做验签</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>String resultInfo = payResult.getResult();

<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>String resultStatus = payResult.getResultStatus();

<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 判断resultStatus 为“9000”则代表支付成功,具体状态码代表含义可参考接口文档</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">if</span> (TextUtils.equals(resultStatus, <span class="string" style="color: rgb(221, 17, 68);">"9000"</span>)) {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>Toast.makeText(PayDemoActivity.<span class="keyword" style="font-weight: bold;">this</span>, <span class="string" style="color: rgb(221, 17, 68);">"支付成功"</span>,
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>Toast.LENGTH_SHORT).show();
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>} <span class="keyword" style="font-weight: bold;">else</span> {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 判断resultStatus 为非“9000”则代表可能支付失败</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// “8000”代表支付结果因为支付渠道原因或者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准(小概率状态)</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">if</span> (TextUtils.equals(resultStatus, <span class="string" style="color: rgb(221, 17, 68);">"8000"</span>)) {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>Toast.makeText(PayDemoActivity.<span class="keyword" style="font-weight: bold;">this</span>, <span class="string" style="color: rgb(221, 17, 68);">"支付结果确认中"</span>,
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>Toast.LENGTH_SHORT).show();

<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>} <span class="keyword" style="font-weight: bold;">else</span> {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 其他值就可以判断为支付失败,包括用户主动取消支付,或者系统返回的错误</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>Toast.makeText(PayDemoActivity.<span class="keyword" style="font-weight: bold;">this</span>, <span class="string" style="color: rgb(221, 17, 68);">"支付失败"</span>,
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>Toast.LENGTH_SHORT).show();

<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>}
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>}
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">break</span>;
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>}
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">case</span> SDK_CHECK_FLAG: {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>Toast.makeText(PayDemoActivity.<span class="keyword" style="font-weight: bold;">this</span>, <span class="string" style="color: rgb(221, 17, 68);">"检查结果为:"</span> + msg.obj,
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>Toast.LENGTH_SHORT).show();
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">break</span>;
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>}
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">default</span>:
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">break</span>;
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>}
<span class="indent">  </span><span class="indent">  </span>};
<span class="indent">  </span>};

这段代码,是一个Handler,放在Java 文件的顶部。

<span class="javadoc" style="color: rgb(153, 153, 136); font-style: italic;">/**
<span class="indent">  </span> * call alipay sdk pay. 调用SDK支付
<span class="indent">  </span> *
<span class="indent">  </span> */</span>
<span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> <span class="keyword" style="font-weight: bold;">void</span> pay() {
<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 订单</span>
<span class="indent">  </span><span class="indent">  </span>String orderInfo = getOrderInfo(<span class="string" style="color: rgb(221, 17, 68);">"测试的商品"</span>, <span class="string" style="color: rgb(221, 17, 68);">"该测试商品的详细描述"</span>, <span class="string" style="color: rgb(221, 17, 68);">"0.01"</span>);

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 对订单做RSA 签名</span>
<span class="indent">  </span><span class="indent">  </span>String sign = sign(orderInfo);
<span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">try</span> {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 仅需对sign 做URL编码</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>sign = URLEncoder.encode(sign, <span class="string" style="color: rgb(221, 17, 68);">"UTF-8"</span>);
<span class="indent">  </span><span class="indent">  </span>} <span class="keyword" style="font-weight: bold;">catch</span> (UnsupportedEncodingException e) {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>e.printStackTrace();
<span class="indent">  </span><span class="indent">  </span>}

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 完整的符合支付宝参数规范的订单信息</span>
<span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">final</span> String payInfo = orderInfo + <span class="string" style="color: rgb(221, 17, 68);">"&sign=\""</span> + sign + <span class="string" style="color: rgb(221, 17, 68);">"\"&"</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>+ getSignType();

<span class="indent">  </span><span class="indent">  </span>Runnable payRunnable = <span class="keyword" style="font-weight: bold;">new</span> Runnable() {

<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="annotation">@Override</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> <span class="keyword" style="font-weight: bold;">void</span> run() {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 构造PayTask 对象</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>PayTask alipay = <span class="keyword" style="font-weight: bold;">new</span> PayTask(PayDemoActivity.<span class="keyword" style="font-weight: bold;">this</span>);
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 调用支付接口,获取支付结果</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>String result = alipay.pay(payInfo);

<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>Message msg = <span class="keyword" style="font-weight: bold;">new</span> Message();
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>msg.what = SDK_PAY_FLAG;
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>msg.obj = result;
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>mHandler.sendMessage(msg);
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>}
<span class="indent">  </span><span class="indent">  </span>};

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 必须异步调用</span>
<span class="indent">  </span><span class="indent">  </span>Thread payThread = <span class="keyword" style="font-weight: bold;">new</span> Thread(payRunnable);
<span class="indent">  </span><span class="indent">  </span>payThread.start();
<span class="indent">  </span>}

<span class="indent">  </span><span class="javadoc" style="color: rgb(153, 153, 136); font-style: italic;">/**
<span class="indent">  </span> * check whether the device has authentication alipay account.
<span class="indent">  </span> * 查询终端设备是否存在支付宝认证账户
<span class="indent">  </span> *
<span class="indent">  </span> */</span>
<span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> <span class="keyword" style="font-weight: bold;">void</span> check(View v) {
<span class="indent">  </span><span class="indent">  </span>Runnable checkRunnable = <span class="keyword" style="font-weight: bold;">new</span> Runnable() {

<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="annotation">@Override</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> <span class="keyword" style="font-weight: bold;">void</span> run() {
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 构造PayTask 对象</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>PayTask payTask = <span class="keyword" style="font-weight: bold;">new</span> PayTask(PayDemoActivity.<span class="keyword" style="font-weight: bold;">this</span>);
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 调用查询接口,获取查询结果</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">boolean</span> isExist = payTask.checkAccountIfExist();

<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>Message msg = <span class="keyword" style="font-weight: bold;">new</span> Message();
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>msg.what = SDK_CHECK_FLAG;
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>msg.obj = isExist;
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>mHandler.sendMessage(msg);
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>}
<span class="indent">  </span><span class="indent">  </span>};

<span class="indent">  </span><span class="indent">  </span>Thread checkThread = <span class="keyword" style="font-weight: bold;">new</span> Thread(checkRunnable);
<span class="indent">  </span><span class="indent">  </span>checkThread.start();

<span class="indent">  </span>}

<span class="indent">  </span><span class="javadoc" style="color: rgb(153, 153, 136); font-style: italic;">/**
<span class="indent">  </span> * get the sdk version. 获取SDK版本号
<span class="indent">  </span> *
<span class="indent">  </span> */</span>
<span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> <span class="keyword" style="font-weight: bold;">void</span> getSDKVersion() {
<span class="indent">  </span><span class="indent">  </span>PayTask payTask = <span class="keyword" style="font-weight: bold;">new</span> PayTask(<span class="keyword" style="font-weight: bold;">this</span>);
<span class="indent">  </span><span class="indent">  </span>String version = payTask.getVersion();
<span class="indent">  </span><span class="indent">  </span>Toast.makeText(<span class="keyword" style="font-weight: bold;">this</span>, version, Toast.LENGTH_SHORT).show();
<span class="indent">  </span>}

<span class="indent">  </span><span class="javadoc" style="color: rgb(153, 153, 136); font-style: italic;">/**
<span class="indent">  </span> * create the order info. 创建订单信息
<span class="indent">  </span> *
<span class="indent">  </span> */</span>
<span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> String getOrderInfo(String subject, String body, String price) {
<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 签约合作者身份ID</span>
<span class="indent">  </span><span class="indent">  </span>String orderInfo = <span class="string" style="color: rgb(221, 17, 68);">"partner="</span> + <span class="string" style="color: rgb(221, 17, 68);">"\""</span> + PARTNER + <span class="string" style="color: rgb(221, 17, 68);">"\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 签约卖家支付宝账号</span>
<span class="indent">  </span><span class="indent">  </span>orderInfo += <span class="string" style="color: rgb(221, 17, 68);">"&seller_id="</span> + <span class="string" style="color: rgb(221, 17, 68);">"\""</span> + SELLER + <span class="string" style="color: rgb(221, 17, 68);">"\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 商户网站唯一订单号</span>
<span class="indent">  </span><span class="indent">  </span>orderInfo += <span class="string" style="color: rgb(221, 17, 68);">"&out_trade_no="</span> + <span class="string" style="color: rgb(221, 17, 68);">"\""</span> + getOutTradeNo() + <span class="string" style="color: rgb(221, 17, 68);">"\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 商品名称</span>
<span class="indent">  </span><span class="indent">  </span>orderInfo += <span class="string" style="color: rgb(221, 17, 68);">"&subject="</span> + <span class="string" style="color: rgb(221, 17, 68);">"\""</span> + subject + <span class="string" style="color: rgb(221, 17, 68);">"\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 商品详情</span>
<span class="indent">  </span><span class="indent">  </span>orderInfo += <span class="string" style="color: rgb(221, 17, 68);">"&body="</span> + <span class="string" style="color: rgb(221, 17, 68);">"\""</span> + body + <span class="string" style="color: rgb(221, 17, 68);">"\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 商品金额</span>
<span class="indent">  </span><span class="indent">  </span>orderInfo += <span class="string" style="color: rgb(221, 17, 68);">"&total_fee="</span> + <span class="string" style="color: rgb(221, 17, 68);">"\""</span> + price + <span class="string" style="color: rgb(221, 17, 68);">"\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 服务器异步通知页面路径</span>
<span class="indent">  </span><span class="indent">  </span>orderInfo += <span class="string" style="color: rgb(221, 17, 68);">"¬ify_url="</span> + <span class="string" style="color: rgb(221, 17, 68);">"\""</span> + <span class="string" style="color: rgb(221, 17, 68);">"http://notify.msp.hk/notify.htm"</span>
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>+ <span class="string" style="color: rgb(221, 17, 68);">"\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 服务接口名称, 固定值</span>
<span class="indent">  </span><span class="indent">  </span>orderInfo += <span class="string" style="color: rgb(221, 17, 68);">"&service=\"mobile.securitypay.pay\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 支付类型, 固定值</span>
<span class="indent">  </span><span class="indent">  </span>orderInfo += <span class="string" style="color: rgb(221, 17, 68);">"&payment_type=\"1\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 参数编码, 固定值</span>
<span class="indent">  </span><span class="indent">  </span>orderInfo += <span class="string" style="color: rgb(221, 17, 68);">"&_input_charset=\"utf-8\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 设置未付款交易的超时时间</span>
<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 默认30分钟,一旦超时,该笔交易就会自动被关闭。</span>
<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 取值范围:1m~15d。</span>
<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。</span>
<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 该参数数值不接受小数点,如1.5h,可转换为90m。</span>
<span class="indent">  </span><span class="indent">  </span>orderInfo += <span class="string" style="color: rgb(221, 17, 68);">"&it_b_pay=\"30m\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付</span>
<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// orderInfo += "&extern_token=" + "\"" + extern_token + "\"";</span>

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空</span>
<span class="indent">  </span><span class="indent">  </span>orderInfo += <span class="string" style="color: rgb(221, 17, 68);">"&return_url=\"m.alipay.com\""</span>;

<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用)</span>
<span class="indent">  </span><span class="indent">  </span><span class="comment" style="color: rgb(153, 153, 136); font-style: italic;">// orderInfo += "&paymethod=\"expressGateway\"";</span>

<span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">return</span> orderInfo;
<span class="indent">  </span>}

<span class="indent">  </span><span class="javadoc" style="color: rgb(153, 153, 136); font-style: italic;">/**
<span class="indent">  </span> * get the out_trade_no for an order. 生成商户订单号,该值在商户端应保持唯一(可自定义格式规范)
<span class="indent">  </span> *
<span class="indent">  </span> */</span>
<span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> String getOutTradeNo() {
<span class="indent">  </span><span class="indent">  </span>SimpleDateFormat format = <span class="keyword" style="font-weight: bold;">new</span> SimpleDateFormat(<span class="string" style="color: rgb(221, 17, 68);">"MMddHHmmss"</span>,
<span class="indent">  </span><span class="indent">  </span><span class="indent">  </span><span class="indent">  </span>Locale.getDefault());
<span class="indent">  </span><span class="indent">  </span>Date date = <span class="keyword" style="font-weight: bold;">new</span> Date();
<span class="indent">  </span><span class="indent">  </span>String key = format.format(date);

<span class="indent">  </span><span class="indent">  </span>Random r = <span class="keyword" style="font-weight: bold;">new</span> Random();
<span class="indent">  </span><span class="indent">  </span>key = key + r.nextInt();
<span class="indent">  </span><span class="indent">  </span>key = key.substring(<span class="number" style="color: rgb(0, 153, 153);">0</span>, <span class="number" style="color: rgb(0, 153, 153);">15</span>);
<span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">return</span> key;
<span class="indent">  </span>}

<span class="indent">  </span><span class="javadoc" style="color: rgb(153, 153, 136); font-style: italic;">/**
<span class="indent">  </span> * sign the order info. 对订单信息进行签名
<span class="indent">  </span> *
<span class="indent">  </span> * <span class="javadoctag">@param</span> content
<span class="indent">  </span> *            待签名订单信息
<span class="indent">  </span> */</span>
<span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> String sign(String content) {
<span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">return</span> SignUtils.sign(content, RSA_PRIVATE);
<span class="indent">  </span>}

<span class="indent">  </span><span class="javadoc" style="color: rgb(153, 153, 136); font-style: italic;">/**
<span class="indent">  </span> * get the sign type we use. 获取签名方式
<span class="indent">  </span> *
<span class="indent">  </span> */</span>
<span class="indent">  </span><span class="keyword" style="font-weight: bold;">public</span> String getSignType() {
<span class="indent">  </span><span class="indent">  </span><span class="keyword" style="font-weight: bold;">return</span> <span class="string" style="color: rgb(221, 17, 68);">"sign_type=\"RSA\""</span>;
<span class="indent">  </span>}

}
这一段代码要和上一段代码放在一个Java 文件中,需要注意的一个方法是。 pay() 方法和getOrderInfo(); 需要注意的是,在我们选择支付宝支付的按钮中调用的 是 pay() 方法。而放在pay()方法中则需要调用getOrderInfo(),仔细发现,getOrderInfo()方法里面的三个参数。其中price 参数就是我们要消费的金额,当我们调用pay()方法的时候,就需要传入一个price 的参数,就是我们需要支付的金额。具体的金额怎么传入,计算,要根据项目需要来自己获取了,这样项目集成支付宝就圆满结束了。

配置的具体操作:

在PayDemoActivity中配置几个变量:

[java]  view plain copy
  1. //PID  
  2. public static final String PARTNER = "";  
在这里填上我们上面找到的PID;
[java]  view plain copy
  1. // 商户收款账号  
  2. public static final String SELLER = "[email protected]";  
然后在SELLER上写上我们支付宝的登录帐户,即那个你申请移动支付的支付宝账号
[java]  view plain copy
  1. // 支付宝公钥  
  2. public static final String RSA_PUBLIC ="";  
然后在RSA_PUBLIC这里填上支付宝公钥
[java]  view plain copy
  1. // 商户私钥,pkcs8格式  
  2. public static final String RSA_PRIVATE = "";  
最后是填上RSA_PRIVATE对应的商户私钥,注意是PKCS8格式的。
私钥这部分,注意是----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----之间的部分,即那段纯代码,不要把----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----给复制进去了。中间的这部分就是公钥。

现在运行demo就直接可以支付了。

本文中对应的DEMO在文章底部给出。

4、代码讲解

通过上面的配置,demo应该就直接可以运行了,但这里所涉及的代码,我们再仔细看看
主要的支付与结果返回就是pay()这个函数,这里完成了支付所需要的所有功能。代码如下:

[java]  view plain copy
  1. public void pay(View v) {  
  2.     …………  
  3.     // 订单信息  
  4.     String orderInfo = getOrderInfo("测试的商品""该测试商品的详细描述""0.01");  
  5.   
  6.     // 对订单做RSA 签名  
  7.     String sign = sign(orderInfo);  
  8.     try {  
  9.         // 仅需对sign 做URL编码  
  10.         sign = URLEncoder.encode(sign, "UTF-8");  
  11.     } catch (UnsupportedEncodingException e) {  
  12.         e.printStackTrace();  
  13.     }  
  14.   
  15.     // 完整的符合支付宝参数规范的订单信息  
  16.     final String payInfo = orderInfo + "&sign=\"" + sign + "\"&"  
  17.             + getSignType();  
  18.   
  19.     Runnable payRunnable = new Runnable() {  
  20.   
  21.         @Override  
  22.         public void run() {  
  23.             // 构造PayTask 对象  
  24.             PayTask alipay = new PayTask(PayDemoActivity.this);  
  25.             // 调用支付接口,获取支付结果  
  26.             String result = alipay.pay(payInfo);  
  27.   
  28.             Message msg = new Message();  
  29.             msg.what = SDK_PAY_FLAG;  
  30.             msg.obj = result;  
  31.             mHandler.sendMessage(msg);  
  32.         }  
  33.     };  
  34.   
  35.     // 必须异步调用  
  36.     Thread payThread = new Thread(payRunnable);  
  37.     payThread.start();  
  38. }  

这里总是分了四步来完成支付与结果接收。

第一步:构造定单信息:

[java]  view plain copy
  1. String orderInfo = getOrderInfo("测试的商品""该测试商品的详细描述""0.01");  
主要是这句,即在getOrderInfo()函数中完成定单信息的构造:(这里对getOrderInfo函数做的精减,更多字段及意义参考源码)

有关paymethod的方法使用,参考:https://cshall.alipay.com/support/help_detail.htm?help_id=476935
各个字段的意义及取值参考:http://doc.open.alipay.com/doc2/detail?treeId=59&articleId=103663&docType=1

[java]  view plain copy
  1. public String getOrderInfo(String subject, String body, String price) {  
  2.   
  3.     // 签约合作者身份ID  
  4.     String orderInfo = "partner=" + "\"" + PARTNER + "\"";  
  5.   
  6.     // 签约卖家支付宝账号  
  7.     orderInfo += "&seller_id=" + "\"" + SELLER + "\"";  
  8.   
  9.     // 商户网站唯一订单号  
  10.     orderInfo += "&out_trade_no=" + "\"" + getOutTradeNo() + "\"";  
  11.   
  12.     // 商品名称  
  13.     orderInfo += "&subject=" + "\"" + subject + "\"";  
  14.   
  15.     // 商品详情  
  16.     orderInfo += "&body=" + "\"" + body + "\"";  
  17.   
  18.     // 商品金额  
  19.     orderInfo += "&total_fee=" + "\"" + price + "\"";  
  20.   
  21.     // 服务器异步通知页面路径  
  22.     orderInfo += "&notify_url=" + "\"" + "http://notify.msp.hk/notify.htm"  
  23.             + "\"";  
  24.   
  25.     …………  
  26.     return orderInfo;  
  27. }  
这里就是通过我们的提供的商家ID,产品信息,价格等信息来构造定单及回调页面,这里需要非常注意的一个地方:
[java]  view plain copy
  1. // 服务器异步通知页面路径  
  2. orderInfo += "&noify_url=" + "\"" + "http://notify.msp.hk/notify.htm"  
  3.         + "\"";  
服务器异步通知页面路径,首先我们用支付宝支付之后,支付宝会返回给我们两个通知,一个是同步的,就是我们点击支付后支付宝直接反馈给我们客户端的信息,我们可以直接拿到,根据反馈的结果可以初步判定该次交易是否成功,第二个就是服务器异步的通知,这个异步的通知是支付宝的服务器端发给我们服务器端的信息,我们在客户端是直接获取不了的,那支付宝的服务器怎么知道我们服务器的路径呢,那就是这参数的作用了,我们给支付宝服务器一个路径,它就会在订单状态改变的时候给我们服务器端一个反馈,告诉服务器这次交易的状态,如果服务器结果判定该次交易成功了,就必须返给支付宝服务器一个success,要不服务器会一直给我们异步通知,因为它不知道该次交易是否完成了(一般情况下25小时内8次通知,频率一般是2m 10m 10m 1h 2h 6h 15h),我们一般会在收到异步通知时,对订单的状态进行更新。
其它的就不讲了,通过看源码都能看得懂,比如构造订单号啥的。

第二步:对订单字符串做RSA签名

为什么要签名呢?当然是防止传输出错了,这可是跟钱相关的,如果orderInfo传输过程中出错了,那怎么样来校验它是不是出错了呢,只有通过签名算法来了。所以这里就需要对订单字符串做签名。
具体签名算法就不讲了,直接应用到项目中就行,不需要理解,如果想看看怎么实现的,里面有对应的源码,可以去研究一下。

[java]  view plain copy
  1. // 对订单做RSA 签名  
  2. String sign = sign(orderInfo);  
  3. try {  
  4.     // 仅需对sign 做URL编码  
  5.     sign = URLEncoder.encode(sign, "UTF-8");  
  6. catch (UnsupportedEncodingException e) {  
  7.     e.printStackTrace();  
  8. }  

第三步:构造完成的请求字符串

在订单字符串和签名做完以后,就可以用他们来构造完整的请求字符串了:
[java]  view plain copy
  1. // 完整的符合支付宝参数规范的订单信息  
  2. final String payInfo = orderInfo + "&sign=\"" + sign + "\"&"  
  3.         + getSignType();  

第四步:请求与结果返回

最后是发送请求,代码如下:

[java]  view plain copy
  1. Runnable payRunnable = new Runnable() {  
  2.   
  3.     @Override  
  4.     public void run() {  
  5.         // 构造PayTask 对象  
  6.         PayTask alipay = new PayTask(PayDemoActivity.this);  
  7.         // 调用支付接口,获取支付结果  
  8.         String result = alipay.pay(payInfo);  
  9.   
  10.         Message msg = new Message();  
  11.         msg.what = SDK_PAY_FLAG;  
  12.         msg.obj = result;  
  13.         mHandler.sendMessage(msg);  
  14.     }  
  15. };  
  16.   
  17. // 必须异步调用  
  18. Thread payThread = new Thread(payRunnable);  
  19. payThread.start();  
最关键的部分在这里:
[java]  view plain copy
  1. PayTask alipay = new PayTask(PayDemoActivity.this);  
  2. // 调用支付接口,获取支付结果  
  3. String result = alipay.pay(payInfo);  
  4.   
  5. Message msg = new Message();  
  6. msg.what = SDK_PAY_FLAG;  
  7. msg.obj = result;  
  8. mHandler.sendMessage(msg);  
在String result = alipay.pay(payInfo);中,就直接获得了支付结果;
然后通过handler将结果发送出去。
这就是同步的方式获取支付结果的方式。
版权声明:本文为博主原创文章,未经博主允许不得

猜你喜欢

转载自blog.csdn.net/leansmall/article/details/80466715