网上关于RN的支付宝支付组件大部分都是IOS的,Android要实现支付宝支付只剩下走原生这一步了。
整体思路:
1、在蚂蚁金服开放平台申请应用
2、在android原生集成支付宝
3、封装android原生
4、RN与android的通信
一、准备工作
1、在蚂蚁金服开放平台https://docs.open.alipay.com/204/105051/ 按照官方提示创建应用,添加app支付的功能。
2、在审核通过后可以拿到调用支付所需要的参数。
3、下载官方的Demo和SDKhttps://docs.open.alipay.com/54/104509
解压项目,用Android Studio打开alipay_demo项目,核心代码都在这个文件夹中。
二、项目操作
1、初始化zfbDemo的RN项目。并用Android Studio打开android部分。
2、在zfbDemo/android/app/目录下新建libs文件夹,将官网下载的alipay_demo中的libs下的sdk复制到新建的libs文件夹下。并右键 Add as Library添加到项目中。
3、在AndroidManifest.xml文件中加入注册声明:
和权限声明:
4、我们直接实现点击RN中的按钮调出支付宝支付页面。
创建一个类继承ReactContextBaseJavaModule,这个类放入被RN调用的方法封装成有个原生模块
新建一个MyNativeModule的类,内容:
package com.zfbdemo;
import android.content.Context;
import android.content.Intent;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
/**
* Created by admin on 2017/11/3.
*/
public class MyNativeModule extends ReactContextBaseJavaModule {
private Context mContext;
//构造方法
public MyNativeModule(ReactApplicationContext reactContext) {
super(reactContext);
mContext = reactContext;
}
@Override
public String getName() {
//MyNativeModule 需要此名字来调用该类方法
return "MyNativeModule";
}
//函数不能有返回值,被调用的原生代码是异步的,原生代码执行结束之后只能通过回调函数发送消息给RN
//rnCallNative为RN需要调用的方法
@ReactMethod
public void rnCallNative(){
}
}
创建一个类实现接口ReactPackage包管理器,把上面一步创建的类添加到原生模块(nativeModule)列表里
新建一个MyReactPackge的类,内容:
package com.zfbdemo;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Created by admin on 2017/11/3.
*/
public class MyReactPackge implements ReactPackage {
@Override
public List createNativeModules(ReactApplicationContext reactContext) {
List modules = new ArrayList<>();
modules.add(new MyNativeModule(reactContext));
return modules;
}
@Override
public List> createJSModules() {
return Collections.emptyList();
}
@Override
public List createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
在MainApplication中加入new MyReactPackge()
@Override
protected List getPackages() {
return Arrays.asList(
new MainReactPackage(),
new MyReactPackge()//添加这一句
);
}
到现在,RN调用的原生Android方法就封装好了,下一步就需要在方法里面调用支付了,不再一一叙述,直接贴代码:
tip:这一块只是为了实现支付功能的演示,真正的项目是需要后台加密返回orderInfo的。
先引入一些文件:
将官方demo中的这些文件复制过来,然后逐个打开,有包名之类的错误的改正。
将MyNativeModule.Java文件改为以下内容:
package com.zfbdemo;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.alipay.sdk.app.PayTask;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.zfbdemo.util.OrderInfoUtil2_0;
import java.util.Map;
/**
* Created by admin on 2017/11/3.
*/
public class MyNativeModule extends ReactContextBaseJavaModule {
/** 支付宝支付业务:入参app_id */
public static final String APPID = "申请的appid";
/** 支付宝账户登录授权业务:入参pid值 */
public static final String PID = "申请的pid";
/** 支付宝账户登录授权业务:入参target_id值 */
public static final String TARGET_ID = "";
/** 商户私钥,pkcs8格式 */
/** 如下私钥,RSA2_PRIVATE 或者 RSA_PRIVATE 只需要填入一个 */
/** 如果商户两个都设置了,优先使用 RSA2_PRIVATE */
/** RSA2_PRIVATE 可以保证商户交易在更加安全的环境下进行,建议使用 RSA2_PRIVATE */
/** 获取 RSA2_PRIVATE,建议使用支付宝提供的公私钥生成工具生成, */
/** 工具地址:https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=106097&docType=1 */
public static final String RSA2_PRIVATE = "申请应用中的私钥";
public static final String RSA_PRIVATE = "";
private static final int SDK_PAY_FLAG = 1;
private static final int SDK_AUTH_FLAG = 2;
private Context mContext;
//构造方法
public MyNativeModule(ReactApplicationContext reactContext) {
super(reactContext);
mContext = reactContext;
}
@Override
public String getName() {
//MyNativeModule 需要此名字来调用该类方法
return "MyNativeModule";
}
//函数不能有返回值,被调用的原生代码是异步的,原生代码执行结束之后只能通过回调函数发送消息给RN
//rnCallNative为RN需要调用的方法
@ReactMethod
public void rnCallNative(){
payV2();
}
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler(Looper.getMainLooper()) {
@SuppressWarnings("unused")
public void handleMessage(Message msg) {
switch (msg.what) {
case SDK_PAY_FLAG: {
@SuppressWarnings("unchecked")
PayResult payResult = new PayResult((Map) msg.obj);
/**
对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
*/
String resultInfo = payResult.getResult();// 同步返回需要验证的信息
String resultStatus = payResult.getResultStatus();
// 判断resultStatus 为9000则代表支付成功
if (TextUtils.equals(resultStatus, "9000")) {
// 该笔订单是否真实支付成功,需要依赖服务端的异步通知。
Toast.makeText(mContext, "支付成功", Toast.LENGTH_SHORT).show();
} else {
// 该笔订单真实的支付结果,需要依赖服务端的异步通知。
Toast.makeText(mContext, "支付失败", Toast.LENGTH_SHORT).show();
}
break;
}
case SDK_AUTH_FLAG: {
@SuppressWarnings("unchecked")
AuthResult authResult = new AuthResult((Map) msg.obj, true);
String resultStatus = authResult.getResultStatus();
// 判断resultStatus 为“9000”且result_code
// 为“200”则代表授权成功,具体状态码代表含义可参考授权接口文档
if (TextUtils.equals(resultStatus, "9000") && TextUtils.equals(authResult.getResultCode(), "200")) {
// 获取alipay_open_id,调支付时作为参数extern_token 的value
// 传入,则支付账户为该授权账户
Toast.makeText(mContext,
"授权成功\n" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT)
.show();
} else {
// 其他状态值则为授权失败
Toast.makeText(mContext,
"授权失败" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT).show();
}
break;
}
default:
break;
}
};
};
public void payV2() {
/**
* 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
* 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
* 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
*
* orderInfo的获取必须来自服务端;
*/
boolean rsa2 = (RSA2_PRIVATE.length() > 0);
Map params = OrderInfoUtil2_0.buildOrderParamMap(APPID, rsa2);
String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
String privateKey = rsa2 ? RSA2_PRIVATE : RSA_PRIVATE;
String sign = OrderInfoUtil2_0.getSign(params, privateKey, rsa2);
final String orderInfo = orderParam + "&" + sign;
Runnable payRunnable = new Runnable() {
@Override
public void run() {
PayTask alipay = new PayTask(getCurrentActivity());
Map result = alipay.payV2(orderInfo, true);
Log.i("msp", result.toString());
Message msg = new Message();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
Thread payThread = new Thread(payRunnable);
payThread.start();
}
}
在JS中:
import {
AppRegistry,
StyleSheet,
Text,
View,
NativeModules,
TouchableOpacity
} from 'react-native';
{
NativeModules.MyNativeModule.rnCallNative()
}}>
调用支付
再次提醒orderInfo必须从后台获得(防止信息泄密)
当手机安装了支付宝会调用支付宝支付,如果没有支付宝会登录网页版的支付宝。
需要注意一点,当应用设置了状态栏沉浸模式,网页版的支付宝的activity会被提上来影响美观,需要在AndroidManifest.xml中加一句:
android:theme="@android:style/Theme"