Andorid端代码
1、使用android studio 打开react native 中的android目录
2、漫长的编译等待后。。。在app/src/main/java/com/.shopapp目录下新建一个名为‘wxapi’的package。
3、在wxapi下面创建三个java类,如下:
WxApiConfig.java
package com.shopapp.wxapi;
/**
* Created by CR
*/
public class WxApiConfig {
public final static String WX_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 微信统一下单接口
public final static String NOTIFY_URL = "http://www.weixin.qq.com/wxpay/pay.php"; // 回调接口
}
WxApiModule.java
package com.shopapp.wxapi;
import android.util.Log;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.shopapp.common.SystemUtils;
import com.tencent.mm.opensdk.modelpay.PayReq;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.xml.sax.InputSource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
import javax.annotation.Nullable;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
/**
* Created by CR on 2017/12/25.
* 微信支付集成
*/
public class WxApiModule extends ReactContextBaseJavaModule {
private final ReactApplicationContext reactContext;
private IWXAPI msgApi;
private static String appId;
private static String appKey;
private static final String LOF_TAG = "WxApiModule";
public WxApiModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}
public ReactApplicationContext getCurrentContext() {
return reactContext;
}
@Override
public String getName() {
return "WxApi";
}
@Nullable
@Override
public Map<String, Object> getConstants() {
return super.getConstants();
}
/**
* @Author CR
* @Date 2017/12/25
* 初始化微信接口
*/
@ReactMethod
public void initWxApi(String aid) {
appId = aid;
msgApi = WXAPIFactory.createWXAPI(reactContext, appId);
}
/**
* @Author CR
* @Date 2017/12/25
* 启动微信
*/
@ReactMethod
public void startWx(com.facebook.react.bridge.Callback successCallback) {
try {
msgApi.openWXApp();
successCallback.invoke("success",111);
}catch (Exception e){
e.printStackTrace();
Log.v(LOF_TAG, e.toString());
}
}
/**
* @Author CR
* @Date 2017/12/25
* 微信支付调用
*/
@ReactMethod
public void doWxPay(ReadableMap readableMap, com.facebook.react.bridge.Callback successCallback) {
Log.v(LOF_TAG, "请求的参数是:" + readableMap.toString());
// 封装处理请求参数
final String mch_id = readableMap.getString("mch_id"); // 商户号
Log.v(LOF_TAG, "接收到的商户号是:" + mch_id);
String nonce_str = UUID.randomUUID().toString(); // 随.机字符串,不长于32位。
// String device_info = "WEB"; // 终端设备号(门店号或收银设备ID),默认请传"WEB"。
String body = "某某某公司-测试收款";// 商品描述交易字段格式根据不同的应用场景按照以下格式:APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。
String out_trade_no = readableMap.getString("out_trade_no"); //商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
Log.v(LOF_TAG, "接收到的内部订单号是:" + out_trade_no);
int total_fee = readableMap.getInt("total_fee"); // 订单总金额,单位为分
Log.v(LOF_TAG, "接收到的订单总金额:" + total_fee);
String spbill_create_ip = SystemUtils.getIPAddress(reactContext); // 用户端实际ip
Log.v(LOF_TAG, "IP地址是:" + spbill_create_ip);
String trade_type = "APP"; // 支付类型
String notify_url = WxApiConfig.NOTIFY_URL; // 接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
SortedMap<String, Object> params = new TreeMap<String, Object>();
params.put("appid", appId);
params.put("mch_id", mch_id);
params.put("nonce_str", nonce_str);
params.put("body", body);
params.put("out_trade_no", out_trade_no);
params.put("total_fee", total_fee);
params.put("spbill_create_ip", spbill_create_ip);
params.put("trade_type", trade_type);
params.put("notify_url", notify_url);
String mySign = createSign(params);
params.put("sign", mySign);
// 调用统一下单接口
SystemUtils.PostUrl(WxApiConfig.WX_ORDER_URL, params, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.v(LOF_TAG, "请求失败");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
final String responseStr = response.body().string();
Log.v(LOF_TAG, "请求成功");
Log.v(LOF_TAG, "返回信息:" + responseStr);
//
Map<String, String> map = readStringXmlOut(responseStr);
String return_code = map.get("return_code");
String return_msg = map.get("return_msg");
String result_code = map.get("result_code");
if("SUCCESS".equals(result_code) && "SUCCESS".equals(return_code)){
String prepay_id = map.get("result_code");
// 调起微信支付
PayReq req = new PayReq();
SortedMap<String, Object> paramsPay = new TreeMap<String, Object>();
paramsPay.put("appId",appId);
paramsPay.put("partnerId",mch_id);
paramsPay.put("prepayId",prepay_id);
paramsPay.put("packageValue","Sign=WXPay");
String nonce_str_pay = UUID.randomUUID().toString();
String timeStamp = System.currentTimeMillis()+"";
paramsPay.put("nonceStr",nonce_str_pay);
req.appId = appId;
req.partnerId = mch_id;
req.prepayId = prepay_id;
req.packageValue = "Sign=WXPay";
req.nonceStr = nonce_str_pay;
req.timeStamp = timeStamp;
String signPay = createSign(paramsPay);
req.sign = signPay;
msgApi.sendReq(req);
}
Log.v(LOF_TAG, "return_code=" + return_code);
Log.v(LOF_TAG, "return_msg=" + return_msg);
}
});
}
/**
* @Author CR
* @Date 2017/12/25
* 微信支付签名算法
*/
@SuppressWarnings("unchecked")
private static String createSign(SortedMap<String, Object> parameters) {
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
if (null != v && !"".equals(v)
&& !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + appKey);
String sign = new String(Hex.encodeHex(DigestUtils.md5(sb.toString())));
return sign.toUpperCase();
}
private static Map<String, String> readStringXmlOut(String xml) {
Map<String, String> map = new HashMap<String, String>();
SAXBuilder builder = new SAXBuilder(false);
try {
Document document = builder.build(new InputSource(new ByteArrayInputStream(xml.getBytes("utf-8"))));
Element xmls = document.getRootElement();
List xmlList = xmls.getChildren();
for (int i = 0, len = xmlList.size(); i < len; i++) {
Element e = (Element) xmlList.get(i);
map.put(e.getName(), e.getText());
}
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
}
WxApiPackage.java
package com.shopapp.wxapi;
import com.facebook.react.ReactPackage;
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 CR on 2017/12/25.
*/
public class WxApiPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new WxApiModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
4、在MainApplication文件中的getPackages()方法中添加new WxApiPackage(),代码如下:
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RCTCameraPackage(),
new WxApiPackage()
);
}
5、在AndroidManifest.xml文件中加入对应的wifi权限,如下
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
6、在com.shopapp目录下还有一个公共代码模块common包,代码如下:
SystemUtils.java
package com.shopapp.common;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.util.Log;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.Map;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
/**
* Created by CR on 2017/12/26.
* 系统工具类
*/
public class SystemUtils {
private static final String LOG_TAG = "SystemUtils";
public static String getIPAddress(Context context) {
NetworkInfo info = ((ConnectivityManager) context
.getSystemService(context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
if (info != null && info.isConnected()) {
if (info.getType() == ConnectivityManager.TYPE_MOBILE) {//当前使用2G/3G/4G网络
try {
//Enumeration<NetworkInterface> en=NetworkInterface.getNetworkInterfaces();
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
return inetAddress.getHostAddress();
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
} else if (info.getType() == ConnectivityManager.TYPE_WIFI) {//当前使用无线网络
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String ipAddress = intIP2StringIP(wifiInfo.getIpAddress());//得到IPV4地址
return ipAddress;
}
} else {
//当前无网络连接,请在设置中打开网络
Log.v(LOG_TAG, "当前无网络连接,请在设置中打开网络");
}
return null;
}
/**
* 将得到的int类型的IP转换为String类型
*
* @param ip
* @return
*/
private static String intIP2StringIP(int ip) {
return (ip & 0xFF) + "." +
((ip >> 8) & 0xFF) + "." +
((ip >> 16) & 0xFF) + "." +
(ip >> 24 & 0xFF);
}
public static void PostUrl(String url, Map<String, Object> paramsMap, Callback callback) {
try {
OkHttpClient okHttpClient = new OkHttpClient();
FormBody.Builder formBodyBuilder = new FormBody.Builder();
for (String key : paramsMap.keySet()) {
formBodyBuilder.add(key, paramsMap.get(key).toString());
}
FormBody formBody = formBodyBuilder.build();
final Request request = new Request.Builder()
.url(url)
.post(formBody)
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(callback);
} catch (Exception e) {
Log.e(LOG_TAG, e.toString());
}
}
}
7、此处用到的一些jar包gradle路径如下:
android/app/build.gradle
dependencies {
compile project(':react-native-camera')
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:+" // From node_modules
compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'
compile group: 'commons-codec', name: 'commons-codec', version: '1.10'
compile group: 'jdom', name: 'jdom', version: '1.0'
}
react native端代码
在根目录下新增modulesImport.js,代码如下:
'use strict';
import {NativeModules} from 'react-native';
module.exports = {
WxApi: NativeModules.WxApi
}
在index.js入口文件中初始化微信api,如下:
import {WxApi} from './modulesImport';
WxApi.initWxApi("这里是微信appid,可以写到配置文件然后引入");
AppRegistry.registerComponent('xxx', () => App);
然后在其他页面就可以通过引入WxApi这个模块进行后台自定义方法的调用,如:
例如WxDemo.js页面
import React, { Component } from 'react';
import {
Image,
Alert,
Button,
Text,
View
} from 'react-native';
import {WxApi} from '../../modulesImport';
export default class WxDemo extends Component<{}> {
render() {
return (
<View>
<Button
onPress={()=>{
//WxApi.startWx(null);
//这里展示下回调函数的使用
WxApi.startWx((param1,param2)=>{
console.log(param1);
console.log(param2);
});
}}
title="点击启动微信"
color="#841584"
/>
</View>
);
}
}
这样就可以调用android中自定义的各种方法了。
后续功能持续更新中…