Delphi XE7 Android
应用接入支付宝SDK的方法
1 应用场景和准备工作:
- 采用XE系列开发的android apps。
- apps中需要集成支付宝的支付能力。
- 支付到指定的商家(一般就是软件开发商自己啦),商家需要事先在支付宝的开放平台申请开通【支付宝无线快捷支付】,具体请百度。
- 开通【无线快捷支付】后,支付宝应该返回给商家如下几个重要参数:
l PARTNER(商户ID): 一个16为的字符串,应该都是数字。
l SELLER(商户名):多数是商户的邮件地址。
l RSA_PRIVATE(商户私钥 ): 一个848位的字符串,采用pkcs8编码过。
l RSA_PRIVATE(商户私钥 ): 一个848位的字符串。
l RSA_PUBLIC(商户公钥):一个218位的经过pkcs8编码的字符串。这个公钥并没有用到,是支付宝后台用的。
- 5. 以上几个参数,都是支付宝再审核通过后,通过邮件发送给商家的,其中RSA的两个公私钥,需要商户自己根据手册自行生成并上传和保存,具体这一步请务必参考支付宝开放平台的说明。
2 XE7中的开发准备工作:
- 下载一个java2op.exe,备用。
- 建立一个android的应用。
- copy支付宝sdk的三个jar包到工程目录(最好和你的pas文件一个目录,最好也把java2op这个文件copy到这里。
- 在IDE右边的ProjectManager中,添加支付宝SDK(android)的三个jar包,如右图。细心的朋友可能发现多了一个jar包:signutils.jar,这个不是支付宝(alipay)sdk带的,是我自己加上的,用途我们稍后再说。
- 打开一个CMD命令行窗口。
- 从命令行里,CD到你的工程目录,有jar包的地方,执行如下命令:
i. java2op -jar alipaysdk.jar -unit alipaysdk
ii. java2op -jar alipaysecsdk.jar -unit alipaysecsdk
iii. javs2op -jar alipayutdid.jar -unit alipayutdid
- 如果一切顺利,在当前目录应该发现新增的这三个pas文件。如图:
3 XE7中的代码工作:
- 请按照支付宝SDK的要求,在androidmanifest.template.xml文件总,增加sdk中的activity的引用,如图:
- 具体这个xml在什么位置,以及这个activity的字符串从何处得来,我就不费力解释了,相信大家都知道。
- 在支付宝SDK的接入手册中,针对混淆部分的要求,可以忽略,不用关心。
- 在适当的pas文件中,增加对之前生成的三个pas的引用(附带几个要用到的单元,也一并加上吧),如图:
- 注意:在编译的时候,这三个pas文件,会报错,几乎都是某个"property a"重复定义的问题,请直接手动把每个报错的‘a’都改为‘aaaaa’,随便什么即可,删除也行。
- 开始加入最关键的代码,例如我们要在一个按钮下开始支付,支付的商品名称、描述和价格,我们可以用三个edit来作为测试输入,这里就不截图描述了,过程如下:
iv.
在pas某个位置,声明三个常量或者属性备用,这三个属性就是之前支付宝返回的参数。
v. 在所谓的【支付按钮】的事件里,写如下代码:
procedure TForm3.Button1Click(Sender: TObject); var PayTask: JPayTask; PayClass: JPayTaskClass; JOrderInfo: JString; OrderInfo,Sign: String; begin PayClass := TJPayTask.JavaClass; PayTask := PayClass.init(MainActivity); OrderInfo := Self.getOrderInfo('abcd','body','0.01'); sign := Self.Sign(OrderInfo); OrderInfo := OrderInfo + '&sign="'+sign+'"'; OrderInfo := OrderInfo + '&sign_type="RSA"'; Self.Memo1.Lines.Text := OrderInfo; //调试用,你懂的。 JOrderInfo := StringToJString(OrderInfo); PayTask.pay(JOrderInfo); end; |
vi. getOrderInfo: 这个函数文档后面会有,是按照支付宝的要求,对订单信息进行格式化处理的,这个函数中调用了一个getTradeNo,是自定义的,也就是生成订单号的,保证不重复即可,随便写。
vii. Sign函数:这个函数就用到了之前在前面看到的signutils.jar这个包,原本支付宝的sdk是没有这包的,这个包是我自己用java编写并加入到项目中的,原因就是:支付宝sdk要求,需要对订单信息进行rsa签名,这个签名过程比较复杂,熟悉java的,可以下载java的demo来看一下,我尝试用delphi下的一些工具和第三方组件,但都失败了,可能是我还不是很熟悉吧,我就把java中的函数封装到这个jar中,供delphi来调用,很好用,文档的后面也会有这个函数的代码,但具体今后每个开发者用什么方法来给订单做sign的签名,只能大家各自想办法了。文档中,我会链接这个jar给大家。
viii. 如果一切正常,应该可以看到支付宝的界面了,至于调试过程中出现的各种错误,只能百度。
ix. 系统繁忙,请稍后重试:ALI64: 这个错误几乎都是订单信息格式不对,或者支付宝返回的各种参数没有用对,还有可能是没有开通无线快捷支付。
x. 系统繁忙,请稍后重试:ALI10:这个错误主要是sign签名不对。
- 附录代码:
function TForm3.getOrderInfo(subject, body, price: string): string; var s: string; begin // 签约合作者身份ID s := 'partner="' + PARTNER + '"'; // 签约卖家支付宝账号 s := s + '&seller_id="' + SELLER + '"'; // 商户网站唯一订单号 s := s+ '&out_trade_no="' + getOutTradeNo + '"'; // 商品名称 s := s + '&subject="' + subject + '"'; // 商品详情 s := s + '&body="' + body + '"'; // 商品金额 s := s + '&total_fee="' + price + '"'; // 服务器异步通知页面路径 s := s + '¬ify_url="' + 'http://你的业务后台地址,一定要写,要合法"'; // 服务接口名称, 固定值 s := s + '&service="mobile.securitypay.pay"'; // 支付类型, 固定值 s := s + '&payment_type="1"'; // 参数编码, 固定值 s := s + '&_input_charset="utf-8"'; // 设置未付款交易的超时时间 // 默认30分钟,一旦超时,该笔交易就会自动被关闭。 // 取值范围:1m~15d。 // m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。 // 该参数数值不接受小数点,如1.5h,可转换为90m。 s := s + '&it_b_pay="30m"'; // extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付 // orderInfo += "&extern_token=" + """ + extern_token + """; // 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空 s := s + '&return_url="m.alipay.com"'; // 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用) // orderInfo += "&paymethod="expressGateway""; Result := s; end; |
function TForm3.getOutTradeNo: string; var G: TGuid; S: string; begin G := TGuid.NewGuid; S := G.ToString; S := S.Substring(0,15); Result := 'abcdefghijklmn'; end; |
function TForm3.Sign(const Orders: string): string; var SignClass: JSignUtilsClass; Js,jpri: JString; begin Result := ''; try Js := StringToJString(Orders); JPri := StringToJString(RSA_PRIVATE); SignClass := TJSignUtils.JavaClass; SignClass.init; js := SignClass.sign(js,jpri); //js := SignClass.DoURLEncode(js); Result := JStringToString(js); finally end; |
其他:
4 真实业务场景的考虑
按照支付宝或者微信支付的开发手册的说法,一个标准的客户端接入支付业务模型应该是这样的,我忽略时序图,只用文字描述:
- 用户登录客户端,选择商品,然后点击客户端支付。
- 客户端收集商品信息,然后调用自己业务平台的预付款接口。
- 业务平台根据客户端提交的商品信息,生成自己的订单号等内容,并按照第三方支付的要求对订单信息进行拼装组合,并编码和签名。
- 业务平台返回签名后的订单信息给客户端。
- 客户端根据这个签名信息,呼出客户端的第三方支付系统,完成支付。