想不到大厂的文档居然也写的像shit一样
如果你之前没有接触过原生开发也没有微信支付对接经验,一定会昏。

概览

申请AppID相关材料

主要材料有 APPID,微信商户ID, API密钥

  • 微信开放平台 申请账号,
  • 创建移动应用(Android的应用签名后面可以修改,只要你能保证你release的包签名跟这里填的一致即可. 签名获取:Gen_Signature_Android2)。
  • 审核通过后就有了AppID
  • 开发者资质认证,通过后申请支付权限
  • 开通支付后续会引导你注册一个商户账号, 也就是微信支付-商户平台
  • 商户ID 账户中心-个人信息-账号信息-登录账号
  • API密钥 账户中心-账户设置-API安全-设置API密钥

准备Web后端API

WEB后端生成UnifiOrder订单, 获得订单的prepay_id, 对app端调用SDK的请求进行sign签名

微信支付SDK列表

以PHP SDK为例 WxpayAPI_php

创建配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

class AppWxPayConfig extends \WxPayConfigInterface
{
public function GetAppId()
{
return 'wxee2f1dfe860a1569';
}
public function GetMerchantId()
{
return '1535521678';
}

public function GetNotifyUrl()
{
return "http://xx.cn/paynotify";
}
public function GetSignType()
{
return "MD5";
}

public function GetProxy(&$proxyHost, &$proxyPort)
{
$proxyHost = "0.0.0.0";
$proxyPort = 0;
}


public function GetReportLevenl()
{
return 1;
}


//=======【商户密钥信息-需要业务方继承】===================================
/*
* KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置), 请妥善保管, 避免密钥泄露
* 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert
*
* APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置), 请妥善保管, 避免密钥泄露
* 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
* @var string
*/
public function GetKey()
{
return '';
}

public function GetAppSecret()
{
return '';
}

//=======【证书路径设置-需要业务方继承】=====================================
/**
* TODO:设置商户证书路径
* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载,
* API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书)
* 注意:
* 1.证书文件不能放在web服务器虚拟目录,应放在有访问权限控制的目录中,防止被他人下载;
* 2.建议将证书文件名改为复杂且不容易猜测的文件名;
* 3.商户服务器要做好病毒和木马防护工作,不被非法侵入者窃取证书文件。
* @var path
*/
public function GetSSLCertPath(&$sslCertPath, &$sslKeyPath)
{
$sslCertPath = '../cert/apiclient_cert.pem';
$sslKeyPath = '../cert/apiclient_key.pem';
}
}

统一下单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$productName = "会员收费";
$orderId = time();
$fee = 1 * 100;

$config = new AppWxPayConfig();
$input = new \WxPayUnifiedOrder();
$input->SetBody($productName);
$input->SetAttach($productName);
$input->SetOut_trade_no($orderId);
$input->SetTotal_fee($fee);
$input->SetTime_start(date("YmdHis"));
$input->SetTime_expire(date("YmdHis", time() + 600));
$input->SetGoods_tag($productName);
$input->SetNotify_url($config->GetNotifyUrl());
$input->SetTrade_type("APP");
$input->SetProduct_id("123456789");

$result = \WxPayApi::unifiedOrder($config, $input);
$res = array();

$res['appid'] = $config->GetAppId();
$res['partnerid'] = $config->GetMerchantId();
$res['package'] = 'Sign=WXPay';
$res["prepay_id"] = $result["prepay_id"];
$res['nonce_str'] = $result['nonce_str'];
$res['timestamp'] = time();

$str = 'appid='.$res['appid'].'&noncestr='.$res['nonce_str'].'&package='.$res['package'].'&partnerid='.$res['partnerid'].'&prepayid='.$res['prepay_id'].'&timestamp='.$data['timestamp'];

// 重新生成签名
$res['sign'] = strtoupper(md5($str.'&key='.$config->GetKey()));

提交下单,获得prepay_id, 生成给App端发起支付的签名。
这里的加密方式要和配置类的GetSignType一致
这个签名也可以在客户端生成,但是有泄漏key的风险

第三方包选择

fluwx 是由JarvanMo提供对Wechat SDK封装的一个包,文档不是特别完善。

安装完之后你还需要设置一些东西

Android

需要提供一个WXPayEntryActivity来接收支付结果的回调, 在package下创建一个wxapi目录WXPayEntryActivity.java

1
2
3
import com.jarvan.fluwx.wxapi.FluwxWXEntryActivity;
public class WXPayEntryActivity extends FluwxWXEntryActivity {
}

并在AndroidManifest.xml中export

1
2
3
4
5
6
7
8
9
10
<activity
android:name=".wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="wxee2f1dfe860a9174"/>
</intent-filter>
</activity>

iOS

  • 在TARGETS-Info中加入URL Types identifier=weixin URL Schemes=你的appID
  • Info.plist增加 LSApplicationQueriesSchemes
1
2
3
4
5
<key>LSApplicationQueriesSchemes</key>
<array>
<string>wechat</string>
<string>weixin</string>
</array>

发起支付请求

App端调用Wechat SDK并发起支付请求,获得支付结果errCode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 初始化SDK
fluwx.register(appId:"wxee2f1dfe860a1569");

// 监听支付结果
fluwx.responseFromPayment.listen((data) {
setState(() {
print(data.errStr);
print(data.errCode);
if(data.errCode == 0){
Scaffold.of(_scaffoldInside).showSnackBar(
SnackBar(content: Text('支付成功'))
);
}else{
Scaffold.of(_scaffoldInside).showSnackBar(
SnackBar(content: Text('支付失败'))
);
}
});
});


// 调用后端API
var res = await createOrder();
var payRes = await fluwx.pay(
appId: res['appid'],
partnerId: res['partnerid'],
prepayId: res['prepay_id'],
packageValue: res['package'],
nonceStr: res['nonce_str'],
timeStamp: res['timestamp'],
sign: res['sign'],
signType: '',
extData: ''
);

print(payRes);

常见问题

errcode=-1

  • Android 唤起支付后闪退,adb 能看到com.tencent.mm/.plugin.wallet_index.ui.OrderHandlerUI要么是没有正确配置回调WXPayEntryActivity, 或者App签名校验不一致。
  • iOS 一般要么你没设置URL Types或者就是没有加weixin的LSApplicationQueriesSchemes
  • 如果不是以上情况,还有种可能就是提交UnifiedOrder的签名方式 和 唤起微信App发起支付请求的签名方式不一致 (我在这里坑了几天. 下单用的hmac,sdk请求签名用的md5, 实际需要保持一致)

微信开放平台 https://open.weixin.qq.com/cgi-bin/index
微信支付-商户平台 https://pay.weixin.qq.com
Gen_Signature_Android2 https://res.wx.qq.com/open/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android2.apk
微信支付SDK列表 https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1
WxpayAPI_php https://pay.weixin.qq.com/wiki/doc/api/download/WxpayAPI_php.zip
fluwx https://github.com/OpenFlutter/fluwx