ReactNative接入微信API 接入支付宝支付

写在前面

上一篇简单地讲了 ReactNative 如何接入支付宝支付,那么这一篇就介绍如何接入微信API吧。我们实际用到的一般有微信登录微信分享微信支付这三个功能。

准备工作

微信的东西比较支付宝申请起来要略微麻烦点,步骤多,而且有些资质认证要给微信钱,心太黑。废话不多说,登录微信开放平台,创建你的App应用,改填的都填了,提交 —— 审核1~2天 —— 通过 —— 申请微信支付 —— 继续审核 … MD这步一次性通过是有多难 !

商户平台

微信支付申请通过了会收到一份邮件,里面有你的微信支付商户账号的信息(记得保存),然后用这个账号和密码登录微信商户平台。这里关键的一步是:

进入 账户中心 —> API安全 —> 设置一个32位的密钥

具体实现

准备工作都做好了,我们就可以开始开发了。

安装模块

感谢大react-native社区,为我们这种菜鸟提供了如此全面的微信三方模块react-native-wechat,完全能满足现阶段的所有微信API需求啊!

支持npm安装:

npm install react-native-wechat --save 
 
 
  • 1

让 ReactNative完全支持ES7

asyncawaitES7比较新的提案,让ReactNative完全支持stage-0,首先我们需要安装 babel-preset-react-native-stage-0 模块:

npm install babel-preset-react-native-stage-0 --save-dev 
 
 
  • 1

并设置 .babelrc

{
  "presets": [ "react-native-stage-0" ],
}
 
 
  • 1
  • 2
  • 3

link和配置

上一篇已经介绍了 react-native link 命令,可以把客户端所需的模块链接到IOSAndroid目录里。

react-native link react-native-wechat 
 
 
  • 1

当然,只执行上面的命令还不够。我们还需要手动添加一些配置

IOS

微信的配置和支付宝差别不大。

(1)添加下面几个frameworklibrary

SystemConfiguration.framework
CoreTelephony.framework
libsqlite3.0
libc++
libz
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

xcode截图

注意:CoreTelephony.frameworklibc++zlibz,这三项和支付宝模块的重复,引一次就够了。

(2)添加 URL Schema ,值是你应用的微信appid

xcode截图

(3)给 LSApplicationQueriesSchemes 添加三个值 alipayweixinwechat

Xcode截图

或者直接编辑 Info.plist

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>alipay</string>
    <string>weixin</string>
    <string>wechat</string>
</array>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意:如果你不需要支付宝支付, 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];
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果你既要支付宝支付,也需要微信支付。那么应该这么写:

#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];
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Android

(1) 修改android/settings.gradle

include ':RCTWeChat'
project(':RCTWeChat').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-wechat/android')
 
 
  • 1
  • 2

(2)修改android/app/build.gradle

dependencies {
  compile project(':RCTWeChat')    // Add this line only.
}
 
 
  • 1
  • 2
  • 3

(3)修改MainActivity.java or MainApplication.java

import com.theweflex.react.WeChatPackage;       // Add this line before public class MainActivity
...

/**
 * 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()        // Add this line
  );
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

(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();
  }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

(5)修改AndroidManifest.xml

<manifest>
  <application>
    <!-- 微信Activity -->
    <activity
      android:name=".wxapi.WXEntryActivity"
      android:label="@string/app_name"
      android:exported="true"
      />
  </application>
</manifest>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

(6)修改 proguard-rules.pro

-keep class com.tencent.mm.sdk.** {
   *;
}
 
 
  • 1
  • 2
  • 3

初始化模块

react-native-wechat 使用前必须初始化一次(有且仅一次)。建议放在项目的入口文件里:

// ...省略
componentDidMount() {
  WeChat.registerApp('你的appid')
}
 
 
  • 1
  • 2
  • 3
  • 4

微信登录

微信登录需要用到的是 WeChat.sendAuthRequest 这个方法。

获取微信CODE

首先介绍一下它参数:

  • scope (必需) 应用授权作用域,如获取用户个人信息则填写 snsapi_userinfo
  • state (非必需) 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验

执行 WeChat.sendAuthRequest获取CODE:

let code = await WeChat.sendAuthRequest("snsapi_userinfo", "123");
 
 
  • 1

微信授权

该方法会返回一个字符串,类似 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
 
 
  • 1

这个接口会返回 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"
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

获取微信授权后的用户信息

包装一个 GET类型的fetch请求,URL如下:

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
 
 
  • 1

这个接口会返回 授权用户的微信基本信息,示例如下:

{
  "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"
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

微信分享

微信分享用到的是 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: '',  //应用id
  partnerid: '', // 商家向财付通申请的商家id
  prepayid: '', // 预支付订单
  noncestr: '', // 随机串,防重发
  timestamp: '', // 时间戳,防重发
  package: '', // 商家根据财付通文档填写的数据和签名
  sign: '' // 商家根据微信开放平台文档对数据做的签名
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

注意:后端要严格区分大小写,这几个变量必须都小写。否则会报 “支付签名验证失败” 这类的错误

前端的工作

有了react-native-wechat,微信支付其实也就调用一个方法的事情。类似支付宝支付的action,下面是最原始的实现代码(建议把fetch封装一下)。

export function weixinPay(opt) {
  return (dispatch) => {
    const uri = `http://${CONFIG.API_URI}/wx/pay`;  /*支付接口*/
    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开发的AppNativeApp,不是WebApp或者HybridApp,所以我们需要开通的是支付宝的App支付功能,别申请错了。申请完成之后就可以接下去开发了。

支付宝支付

接入支付宝支付前建议先查看 支付宝官方文档,先按照要求创建应用并完成配置。不过要注意以下两点:

第一,App支付不能在沙箱做测试,所以我们需要先 “上线” 应用,这个过程会有1天的审核时间。 
第二,调试时建议添加个一分钱的商品作为测试商品,开发免不了要支付几次。

安装模块

支付宝支付我们使用了ReactNative社区推荐的 react-native-yunpeng-alipay 模块,可以使用 npm 安装

npm install react-native-yunpeng-alipay --save 
 
 
  • 1

link引用

最新版 React Native (>=0.31) 已经支持 link 命令,不需要再使用三方的 rnpm来 link 引用了。

react-native link react-native-yunpeng-alipay
 
 
  • 1

这个操作会把 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

xcode截图

添加 URL Schema

打开 Info.plist,添加一项URL types

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;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

和权限声明:

<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" />
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

添加混淆规则

在商户应用工程的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 *;}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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://${ CONFIG.API_URI }/alipay/pay`;  /*支付接口*/
    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



  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值