写在前面
上一篇简单地讲了 ReactNative
如何接入支付宝支付,那么这一篇就介绍如何接入微信API吧。我们实际用到的一般有微信登录、微信分享、微信支付这三个功能。
准备工作
微信的东西比较支付宝申请起来要略微麻烦点,步骤多,而且有些资质认证要给微信钱,心太黑。废话不多说,登录微信开放平台,创建你的App应用,改填的都填了,提交 —— 审核1~2天 —— 通过 —— 申请微信支付 —— 继续审核 … MD这步一次性通过是有多难 !
商户平台
微信支付申请通过了会收到一份邮件,里面有你的微信支付商户账号的信息(记得保存),然后用这个账号和密码登录微信商户平台。这里关键的一步是:
进入 账户中心 —> API安全 —> 设置一个32位的密钥
具体实现
准备工作都做好了,我们就可以开始开发了。
安装模块
感谢大react-native
社区,为我们这种菜鸟提供了如此全面的微信三方模块react-native-wechat
,完全能满足现阶段的所有微信API需求啊!
- github地址
-
react-native-wechat
交流群 336021910
支持npm
安装:
npm install react-native-wechat --save
让 ReactNative
完全支持ES7
async
和await
是ES7
比较新的提案,让ReactNative
完全支持stage-0
,首先我们需要安装 babel-preset-react-native-stage-0
模块:
npm install babel-preset-react-native-stage-0 --save-dev
并设置 .babelrc
{
"presets": [ "react-native-stage-0" ],
}
link
和配置
上一篇已经介绍了 react-native link
命令,可以把客户端所需的模块链接到IOS
和Android
目录里。
react-native link react-native-wechat
当然,只执行上面的命令还不够。我们还需要手动添加一些配置
IOS
端
微信的配置和支付宝差别不大。
(1)添加下面几个framework
和library
:
SystemConfiguration.framework
CoreTelephony.framework
libsqlite3.0
libc++
libz
注意:CoreTelephony.framework
、libc++z
、libz
,这三项和支付宝模块的重复,引一次就够了。
(2)添加 URL Schema
,值是你应用的微信appid
(3)给 LSApplicationQueriesSchemes
添加三个值 alipay
、weixin
、wechat
或者直接编辑 Info.plist
:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>alipay</string>
<string>weixin</string>
<string>wechat</string>
</array>
注意:如果你不需要支付宝支付, alipay
可以不加
(4)修改 AppDelegate.m
如果你不需要支付宝支付,这个函数可以这么写:
#import "../Libraries/LinkingIOS/RCTLinkingManager.h"
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [RCTLinkingManager application:application openURL:url
sourceApplication:sourceApplication annotation:annotation];
}
如果你既要支付宝支付,也需要微信支付。那么应该这么写:
#import "../Libraries/LinkingIOS/RCTLinkingManager.h"
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
if([[sourceApplication substringToIndex:10] isEqualToString:@"com.alipay"]){
[AlipayModule handleCallback:url];
}
return [RCTLinkingManager application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
}
Android
端
(1) 修改android/settings.gradle
include ':RCTWeChat'
project(':RCTWeChat').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-wechat/android')
(2)修改android/app/build.gradle
dependencies {
compile project(':RCTWeChat')
}
(3)修改MainActivity.java or MainApplication.java
import com.theweflex.react.WeChatPackage;
...
/**
* A list of packages used by the app. If the app uses additional views
* or modules besides the default ones, add more packages here.
*/
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new WeChatPackage()
);
}
(4)创建一个新的package
取名wxapi
,在里面创建class
取名WXEntryActivity
package your.package.wxapi;
import android.app.Activity;
import android.os.Bundle;
import com.theweflex.react.WeChatModule;
public class WXEntryActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WeChatModule.handleIntent(getIntent());
finish();
}
}
(5)修改AndroidManifest.xml
<manifest>
<application>
<activity
android:name=".wxapi.WXEntryActivity"
android:label="@string/app_name"
android:exported="true"
/>
</application>
</manifest>
(6)修改 proguard-rules.pro
-keep class com.tencent.mm.sdk.** {
*;
}
初始化模块
react-native-wechat
使用前必须初始化一次(有且仅一次)。建议放在项目的入口文件里:
// ...省略
componentDidMount() {
WeChat.registerApp('你的appid')
}
微信登录
微信登录需要用到的是 WeChat.sendAuthRequest
这个方法。
获取微信CODE
首先介绍一下它参数:
-
scope
(必需) 应用授权作用域,如获取用户个人信息则填写 snsapi_userinfo
-
state
(非必需) 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验
执行 WeChat.sendAuthRequest
获取CODE:
let code = await WeChat.sendAuthRequest("snsapi_userinfo", "123");
该方法会返回一个字符串,类似 0114sg4t1F1Rc90jSw6t1Cf44t14sg4-
一串CODE。
获取微信access_token
包装一个 GET
类型的fetch
请求,URL如下:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
这个接口会返回 access_token
和 用户的 openid
。示例如下:
{
"access_token": "JWk5IxV5bFGOdTm2A4zhuGuIB_xGRM5cPbU5nYbkuEihHu6FClMn5zjVZ6QCTYrMv_oCMxW8szuNAOadYIYo6wiOObeesEeNgHeWNvkJolQ",
"expires_in": 7200,
"refresh_token": "WPhskoRBAmDyM1EbrPRvWSCU8LL3Ndn0Brong9ZG434L1Imkxugu2JKOghfIuP1P3JqcCyB2anxAwXRuFr7EMxP_rygeWy1Noi0zPJue_YU",
"openid": "oDwRbw9zFEO36l3Vcq6bHXFWB13k",
"scope": "snsapi_userinfo",
"unionid": "o3KCIw-vFiuq0SBHe-3bhjbCQY3o"
}
获取微信授权后的用户信息
包装一个 GET
类型的fetch
请求,URL如下:
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
这个接口会返回 授权用户的微信基本信息,示例如下:
{
"openid": "oDwRbw9zFEO36l3Vcq6bHXFWB13k",
"nickname": "思^_^诚",
"sex": 1,
"language": "zh_CN",
"city": "Hangzhou",
"province": "Zhejiang",
"country": "CN",
"headimgurl": "http://wx.qlogo.cn/mmopen/PiajxSqBRaEKujUoq5z4PScxKqQESxMxj6VDYnIHT4ZibVDMmSb69dq6EbLPAUJ15mMH9pIxFNu9JZszyx1F6ibcw/0",
"privilege": [],
"unionid": "o3KCIw-vFiuq0SBHe-3bhjbCQY3o"
}
微信分享
微信分享用到的是 WeChat.shareToTimeline(opt)
(分享到朋友圈) 和 WeChat.shareToSession(opt)
(分享给微信好友或微信群),这两个方法的入参是一样的。
为了方便,微信分享我做成了一个react-native
组件, 感兴趣的可以点击看看 github地址
入参列表
-
thumbImage
分享出去的预览图 -
title
分享标题 -
webpageUrl
分享出去的网页地址
核心代码
/**
* [分享到朋友圈]
* @param {[Object]} opt 入参对象
* @example { thumbImage:'', title: '', webpageUrl: '' }
*/
async handleShareWeixinCircle(opt) {
this.lock = true
try {
let result = await WeChat.shareToTimeline({
type: "news",
...opt,
});
} catch (e) {
console.error(e)
} finally {
this.lock = false
this.close()
}
}
/**
* [分享给微信好友或微信群]
* @param {[Object]} opt 入参对象
* @example { thumbImage:'', title: '', webpageUrl: '' }
*/
async handleShareWeixinFriend(opt) {
this.lock = true
try {
let result = await WeChat.shareToSession({
type: "news",
...opt,
});
} catch (e) {
console.error(e)
} finally {
this.lock = false
this.close()
}
}
- 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
我这里用到的是分享网页,更多分享功能参见 react-native-wechat
微信支付
微信支付用到的是 WeChat.pay(opt)
方法
后端的工作
后端需要为我们提供一个支付接口 去调取微信支付的 “统一下单” 接口,然后返回下面这些东西: 点击查看官方文档
{
appid: '',
partnerid: '',
prepayid: '',
noncestr: '',
timestamp: '',
package: '',
sign: ''
}
注意:后端要严格区分大小写,这几个变量必须都小写。否则会报 “支付签名验证失败” 这类的错误
前端的工作
有了react-native-wechat
,微信支付其实也就调用一个方法的事情。类似支付宝支付的action
,下面是最原始的实现代码(建议把fetch
封装一下)。
export function weixinPay(opt) {
return (dispatch) => {
const uri = `http:`; /*支付接口*/
const headers = {
...CONFIG.HEADERS,
'Authorization': opt.token,
};
/*发起支付请求*/
fetch(uri, { method: 'POST', headers: headers, body: JSON.stringify(opt.body)})
.then((response) => {
if (response.status === 200) {
return response.json()
} else {
return {code: response.status}
}
})
.then((data) => {
if (String(data.code) == '0') {
/*打开微信进行支付*/
pay(data.result, opt.success, opt.fail)
} else {
/*预支付失败的后续操作*/
opt.error && opt.error(data.error.message)
}
})
}
}
async function pay(res, success, fail) {
try {
let result = await WeChat.pay({
partnerId: res.partnerid, /*商家向财付通申请的商家id*/
prepayId: res.prepayid, /*预支付订单*/
nonceStr: res.noncestr, /*随机串,防重发*/
timeStamp: res.timestamp, /*时间戳,防重发*/
package: res.package, /*商家根据财付通文档填写的数据和签名*/
sign: res.sign, /*商家根据微信开放平台文档对数据做的签名*/
});
/*支付成功的后续操作*/
success && success()
} catch (error) {
/*支付失败的后续操作*/
fail && fail( error ===-2 ? "用户取消" : "订单支付失败")
}
}
- 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
写在前面
重申一下,ReactNative
开发的App
是NativeApp
,不是WebApp
或者HybridApp
,所以我们需要开通的是支付宝的App支付功能,别申请错了。申请完成之后就可以接下去开发了。
支付宝支付
接入支付宝支付前建议先查看 支付宝官方文档,先按照要求创建应用并完成配置。不过要注意以下两点:
第一,App支付不能在沙箱做测试,所以我们需要先 “上线” 应用,这个过程会有1天的审核时间。
第二,调试时建议添加个一分钱的商品作为测试商品,开发免不了要支付几次。
安装模块
支付宝支付我们使用了ReactNative
社区推荐的 react-native-yunpeng-alipay
模块,可以使用 npm
安装
npm install react-native-yunpeng-alipay --save
link引用
最新版 React Native
(>=0.31) 已经支持 link
命令,不需要再使用三方的 rnpm
来 link
引用了。
react-native link react-native-yunpeng-alipay
这个操作会把 react-native-yunpeng-alipay
模块下的客户端模块自动映射到 ReactNative工程的对应的 IOS和 Android目录里。 注意,自动link
并不是万能的,有些模块我们需要再手动添加一些引用。
IOS端配置
对于IOS端,除了上面的link
操作之外,我们还需要手动做下面的三件事:
添加Frameworks和Libraries
打开xcode,TARGET
-> General
-> Linked Frameworks and Libraries
,添加
-
CoreMotion.framework
-
CoreTelephony.framework
-
libc++
-
libz
添加 URL Schema
打开 Info.plist
,添加一项URL types
:
触发回调
打开 AppDelegate.m
,添加一个函数来触发支付完成后的回调
#import "AlipayModule.h"
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
[AlipayModule handleCallback:url];
return YES;
}
Android端配置
Android
端配置比较简单,除了上面的link
操作外,我们还需要修改Manifest
文件
修改Manifest
在商户应用工程的AndroidManifest.xml
文件里面添加声明:
<activity
android:name="com.alipay.sdk.app.H5PayActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind" >
</activity>
<activity
android:name="com.alipay.sdk.auth.AuthActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind" >
</activity>
和权限声明:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
添加混淆规则
在商户应用工程的proguard-project.txt
里添加以下相关规则:
-libraryjars libs/alipaySDK-20150602.jar
-keep class com.alipay.android.app.IAlixPay{*
-keep class com.alipay.android.app.IAlixPay$Stub{*
-keep class com.alipay.android.app.IRemoteServiceCallback{*
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*
-keep class com.alipay.sdk.app.PayTask{ public *
-keep class com.alipay.sdk.app.AuthTask{ public *
Action封装
我们的App开发采用的是redux
框架,为了方便使用,我把支付宝支付封装成了Action
,你可以参考一下。
/**
* @desc 三方支付
* @author Jafeney
* @detetime 2016-11-08
**/
import Alipay from 'react-native-yunpeng-alipay'
import * as CONFIG from '../config'
export function alipay(opt) {
return (dispatch) => {
const uri = `http:`; /*支付接口*/
const headers = {
...CONFIG.HEADERS,
Authorization: opt.token
};
/*调用支付接口*/
fetch(uri, {method: 'POST', headers: headers, body: JSON.stringify(opt.body)})
.then((response) => {
if (response.status === 200) {
return response.json()
} else {
return {code: response.status}
}
})
.then((data) => {
if (String(data.code) == '0') {
/*打开支付宝进行支付*/
Alipay.pay(data.result).then((data) => {
if (data.length && data[0].resultStatus) {
/*处理支付结果*/
switch (data[0].resultStatus) {
case "9000":
opt.success && opt.success(data)
break;
case "8000":
opt.fail && opt.fail('支付结果未知,请查询订单状态')
break;
case "4000":
opt.fail && opt.fail('订单支付失败')
break;
case "5000":
opt.fail && opt.fail('重复请求')
break;
case "6001":
opt.fail && opt.fail('用户中途取消')
break;
case "6002":
opt.fail && opt.fail('网络连接出错')
break;
case "6004":
opt.fail && opt.fail('支付结果未知,请查询订单状态')
break;
default:
opt.fail && opt.fail('其他失败原因')
break;
}
} else {
opt.fail && opt.fail('其他失败原因')
}
}, (err) => {
opt.fail && opt.fail('支付失败,请重新支付')
}
)
} else {
opt.error && opt.error('支付参数错误')
}
})
}
}
- 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
- 71
@欢迎关注我的 github 和 个人博客 -Jafeney