安卓端唤起支付宝支付所需的 orderInfo 从哪里获取?
结论
安卓端 PayTask.payV2() 需要的 orderInfo,是服务端调用 alipay.trade.app.pay 后生成的完整支付参数字符串。
使用支付宝 Java SDK 时,通过 alipayClient.sdkExecute(request) 获取签名后的订单串,再把 response.getBody() 原样传给安卓端:
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderInfo = response.getBody();
orderstr 一般不需要再次签名,也不需要进行 URL 编解码、Base64 编码或其他格式转换。安卓端收到完整字符串后,直接传入:
PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderInfo, true);
如果无法唤起支付宝,应检查服务端的调用方式、订单串是否完整,以及传输过程中是否发生了转义或截断。
orderInfo 是如何生成的
orderInfo 不应由安卓端自行拼接,更不能在客户端使用商户私钥签名。正确流程如下:
- 安卓端请求业务服务端创建支付宝订单。
- 服务端生成商户订单号、金额、标题等业务参数。
- 服务端通过支付宝 SDK 调用
alipay.trade.app.pay。 - SDK 使用商户私钥为请求参数签名,生成完整订单串。
- 服务端将订单串原样返回给安卓端。
- 安卓端将该字符串传入
PayTask.payV2()。 - 支付结束后,服务端根据支付宝异步通知确认最终支付状态。
商户私钥必须保存在服务端,不能放入 APK。
服务端示例
下面以支付宝 Java SDK 的常见调用方式为例。具体依赖版本和类名,应以项目当前使用的 SDK 为准:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setNotifyUrl("https://example.com/pay/alipay/notify");
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setSubject("商品名称");
model.setOutTradeNo("ORDER_202609080001");
model.setTotalAmount("99.00");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if (response.isSuccess()) {
String orderInfo = response.getBody();
// 将 orderInfo 原样返回给安卓端
} else {
// 记录 subCode、subMsg 等信息,排查参数或配置问题
}
这里要注意使用 sdkExecute()。App 支付需要的是供客户端 SDK 使用的签名订单串,不是普通网关接口返回的 JSON 结果。
服务端可以使用 JSON 将订单串返回给客户端:
{
"code": 0,
"orderInfo": "app_id=...&biz_content=...&sign=...&sign_type=RSA2&..."
}
JSON 序列化时,引号等字符被转义是正常的。安卓端完成 JSON 反序列化后,得到的应该是原始订单字符串。
安卓端调用示例
支付调用不要放在主线程中执行:
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderInfo, true);
activity.runOnUiThread(() -> {
String resultStatus = result.get("resultStatus");
String memo = result.get("memo");
String resultData = result.get("result");
// 客户端结果仅用于界面提示
// 最终支付状态应由服务端查询或异步通知确认
});
});
假设服务端返回的数据结构是:
{
"orderInfo": "app_id=...&method=alipay.trade.app.pay&sign=..."
}
安卓端只需读取 orderInfo 字段:
String orderInfo = responseObject.getString("orderInfo");
不要再执行以下处理:
URLDecoder.decode(orderInfo, "UTF-8");
URLEncoder.encode(orderInfo, "UTF-8");
Base64.decode(orderInfo, Base64.DEFAULT);
这些操作可能改变 +、%、&、= 或签名内容,导致验签失败。
无法唤起支付时如何排查
1. 确认拿到的是 sdkExecute() 的结果
正确写法是:
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderInfo = response.getBody();
如果使用普通的 execute(),得到的可能是网关响应,而不是安卓支付 SDK 可以直接使用的订单串。
2. 检查订单串是否完整
正常的 orderInfo 通常是一整段由 & 连接的参数,其中包含类似内容:
app_id=...&biz_content=...&charset=UTF-8&method=alipay.trade.app.pay&sign_type=RSA2×tamp=...&version=1.0&sign=...
实际参数顺序可能不同,代码不应依赖固定顺序。如果安卓端收到的是空字符串、普通 JSON、缺少 sign 的内容,或者只有 biz_content,就无法直接发起支付。
3. 检查传输过程中是否被修改
常见问题包括:
- 将订单串放在 URL 查询参数中传输,导致
+被解析为空格。 - 对整个订单串重复进行 URL 编码或解码。
- 手动替换反斜杠、双引号或百分号。
- 按
&拆分后重新拼接,破坏原始签名参数。 - 日志系统限制输出长度,使订单串看起来像被截断。
- 从服务端响应中取错字段,把整个 JSON 当成
orderInfo。
建议通过 HTTPS 传输,并将订单串放在 JSON 响应字段中。客户端应使用 JSON 解析器读取该字段,不要手工截取字符串。
4. 检查服务端支付配置
需要逐项确认:
appId与开放平台中的应用一致。- 商户私钥与上传到支付宝开放平台的公钥匹配。
- 配置的是支付宝公钥,不是应用公钥。
- 签名算法配置一致,例如
RSA2。 - 正式环境与沙箱环境的网关、账号和密钥没有混用。
product_code为QUICK_MSECURITY_PAY。out_trade_no在商户系统中保持唯一。- 金额格式合法,并且与服务端实际订单一致。
notify_url是支付宝服务器能够访问的 HTTPS 地址。
5. 检查安卓端接入
如果调用后界面完全没有变化,还需要检查:
- 支付宝 Android SDK 是否正确引入。
orderInfo是否为null或空字符串。payV2()是否在后台线程执行。- 当前
Activity是否有效。 - 混淆和打包配置是否影响支付宝 SDK。
- 是否可以正常拉起支付宝 App。未安装支付宝时,SDK 是否进入预期的收银台流程。
resultStatus和memo是否包含可用于排查的错误信息。
orderstr 与 orderInfo 的关系
在这个场景中,orderstr 和 orderInfo 通常只是不同代码或接口对同一份数据的命名:
服务端 response.getBody()
↓
orderstr
↓ 原样传输
安卓端 orderInfo
↓
PayTask.payV2(orderInfo, true)
问题通常不在于少了一次格式转换,而是订单串的获取方式有误,或者内容在传输过程中发生了变化。只要服务端通过 sdkExecute() 正确生成订单串,安卓端收到完整原文后就能直接使用。最终支付状态仍应以支付宝异步通知或服务端主动查询结果为准,不能只依据客户端返回值。
备注:内容仅供参考。
