Android
申请微信appidhttp://open.weixin.qq.com/
- 引入sdk
android/app/build.gradle
dependencies {
...
api 'com.tencent.mm.opensdk:wechat-sdk-android:+'
...
}
- 添加权限
android/app/src/main/AndroidMainifest.xml
- 添加代码混淆规则
# 微信
-keep class com.tencent.mm.opensdk.**{*;}
-keep class com.tencent.wxop.** {*;}
-keep class com.tencent.mm.sdk.** {*;}
- 写android原生
在android/app/src/main/java/com/xxx 文件里创建文件夹wechat
创建WechatModule.java
package com.xxx.wechat;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Promise;
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.facebook.react.bridge.WritableMap;
import com.facebook.datasource.DataSource;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.common.ResizeOptions;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.common.references.CloseableReference;
import com.facebook.common.executors.UiThreadImmediateExecutorService;
import com.facebook.common.util.UriUtil;
import com.tencent.mm.opensdk.constants.Build;
import com.tencent.mm.opensdk.modelmsg.SendAuth; // sendAuth
import com.tencent.mm.opensdk.modelpay.PayReq;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
import com.tencent.mm.opensdk.modelmsg.SendMessageToWX;
import com.tencent.mm.opensdk.modelmsg.WXFileObject;
import com.tencent.mm.opensdk.modelmsg.WXImageObject;
import com.tencent.mm.opensdk.modelmsg.WXMediaMessage;
import com.tencent.mm.opensdk.modelmsg.WXMusicObject;
import com.tencent.mm.opensdk.modelmsg.WXTextObject;
import com.tencent.mm.opensdk.modelmsg.WXVideoObject;
import com.tencent.mm.opensdk.modelmsg.WXWebpageObject;
import com.tencent.mm.opensdk.modelmsg.WXMiniProgramObject;
import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram;
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.UUID;
public class WechatModule extends ReactContextBaseJavaModule {
private static ReactApplicationContext reactContext;
private final static String NOT_REGISTERED = "未安装微信";
private IWXAPI api = null;
private String appId;
public static Promise promise;
public WechatModule(ReactApplicationContext context) {
super(context);
reactContext = context;
}
@Override
public String getName() {
return "Wechat";
}
// 注册appId
@ReactMethod
private void registerApp(String appId, Promise promise) {
try {
this.appId = appId;
api = WXAPIFactory.createWXAPI(reactContext.getApplicationContext(), null, false);
promise.resolve(api.registerApp(appId));
} catch (Exception e) {
promise.reject("-1", e.getMessage());
}
}
private static byte[] bitmapResizeGetBytes(Bitmap image, int size){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 质量压缩方法,这里100表示第一次不压缩,把压缩后的数据缓存到 baos
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 100;
// 循环判断压缩后依然大于 32kb 则继续压缩
while (baos.toByteArray().length / 1024 > size) {
// 重置baos即清空baos
baos.reset();
if (options > 10) {
options -= 8;
} else {
return bitmapResizeGetBytes(Bitmap.createScaledBitmap(image, 280, image.getHeight() / image.getWidth() * 280, true), size);
}
// 这里压缩options%,把压缩后的数据存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
}
return baos.toByteArray();
}
// 判断是否安装客户端
@ReactMethod
private void isWxInstalled(Promise promise) {
try {
if (api == null) {
throw new Exception(NOT_REGISTERED);
}
promise.resolve(api.isWXAppInstalled());
} catch (Exception e) {
promise.reject("-1", e.getMessage());
}
}
// 打开微信客户端
@ReactMethod
public void openWxApp(Promise promise) {
try {
if (api == null) {
throw new Exception(NOT_REGISTERED);
}
promise.resolve(api.openWXApp());
} catch (Exception e) {
promise.reject("-1", e.getMessage());
}
}
// 打开微信小程序
@ReactMethod
public void openMiniProgram(String appId, String path, Promise promise) {
try {
if (api == null) {
throw new Exception(NOT_REGISTERED);
}
WXLaunchMiniProgram.Req req = new WXLaunchMiniProgram.Req();
req.userName = appId;
req.path = path;
req.miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE;
promise.resolve(api.sendReq(req));
} catch (Exception e) {
promise.reject("-1", e.getMessage());
}
}
// 获取微信版本号
@ReactMethod
private void getAppVersion(Promise promise) {
try {
if (api == null) {
throw new Exception(NOT_REGISTERED);
}
promise.resolve(api.getWXAppSupportAPI());
} catch (Exception e) {
promise.reject("-1", e.getMessage());
}
}
// 微信授权登录
@ReactMethod
public void sendAuthRequest(String scope, String state, Promise promise) {
try {
if (api == null) {
throw new Exception(NOT_REGISTERED);
}
SendAuth.Req req = new SendAuth.Req();
req.scope = scope;
req.state = state;
promise.resolve(api.sendReq(req));
} catch (Exception e) {
promise.reject("-1", e.getMessage());
}
}
// 微信支付
@ReactMethod
private void pay(ReadableMap request, Promise promise) {
WechatModule.promise = promise;
PayReq req = new PayReq();
req.appId = request.getString("appid");
req.partnerId = request.getString("partnerid");
req.prepayId = request.getString("prepayid");
req.packageValue = "Sign=WXPay";
req.nonceStr = request.getString("nonceStr");
req.timeStamp = request.getString("timestamp");
req.sign = request.getString("sign");
int wxSdkVersion = api.getWXAppSupportAPI();
if (wxSdkVersion>= Build.PAY_INSURANCE_SDK_INT) {
api.sendReq(req);
} else if (wxSdkVersion == 0) {
WritableMap map = Arguments.createMap();
map.putInt("errCode", -3);
WechatModule.promise.resolve(map);
} else {
WritableMap map = Arguments.createMap();
map.putInt("errCode", -4);
WechatModule.promise.resolve(map);
}
}
// 分享小程序小程序
@ReactMethod
public void shareMiniProgram(ReadableMap data, Promise promise){
if (api == null) {
callback.invoke(NOT_REGISTERED);
return;
}
WXMiniProgramObject miniProgramObj = new WXMiniProgramObject();
// 兼容低版本的网页链接
miniProgramObj.webpageUrl = data.hasKey("webpageUrl") ? data.getString("webpageUrl") : null;
// 正式版:0,测试版:1,体验版:2
miniProgramObj.miniprogramType = data.hasKey("miniProgramType") ? data.getInt("miniProgramType") : WXMiniProgramObject.MINIPTOGRAM_TYPE_RELEASE;
// 小程序原始id
miniProgramObj.userName = data.hasKey("userName") ? data.getString("userName") : null;
// 小程序页面路径;对于小游戏,可以只传入 query 部分,来实现传参效果,如:传入 "?foo=bar"
miniProgramObj.path = data.hasKey("path") ? data.getString("path") : null;
final WXMediaMessage msg = new WXMediaMessage(miniProgramObj);
// 小程序消息 title
msg.title = data.hasKey("title") ? data.getString("title") : null;
// 小程序消息 desc
msg.description = data.hasKey("description") ? data.getString("description") : null;
String thumbImageUrl = data.hasKey("hdImageUrl") ? data.getString("hdImageUrl") : data.hasKey("thumbImageUrl") ? data.getString("thumbImageUrl") : null;
if (thumbImageUrl != null && !thumbImageUrl.equals("")) {
this._getImage(Uri.parse(thumbImageUrl), null, new ImageCallback() {
@Override
public void invoke(@Nullable Bitmap bmp) {
// 小程序消息封面图片,小于128k
if (bmp != null) {
msg.thumbData = bitmapResizeGetBytes(bmp, 128);
}
// 构造一个Req
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = "miniProgram";
req.message = msg;
req.transaction = UUID.randomUUID().toString();
req.scene = data.hasKey("scene") ? data.getInt("scene") : SendMessageToWX.Req.WXSceneSession;
callback.invoke(null, api.sendReq(req));
}
});
} else {
// 构造一个Req
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = "miniProgram";
req.message = msg;
req.transaction = UUID.randomUUID().toString();
req.scene = data.hasKey("scene") ? data.getInt("scene") : SendMessageToWX.Req.WXSceneSession;
callback.invoke(null, api.sendReq(req));
}
}
// 分享到朋友圈
@ReactMethod
public void shareToTimeline(ReadableMap data, Callback callback) {
if (api == null) {
callback.invoke(NOT_REGISTERED);
return;
}
_share(SendMessageToWX.Req.WXSceneTimeline, data, callback);
}
// 分享到朋友或群
@ReactMethod
public void shareToSession(ReadableMap data, Callback callback) {
if (api == null) {
callback.invoke(NOT_REGISTERED);
return;
}
_share(SendMessageToWX.Req.WXSceneSession, data, callback);
}
// 收藏
@ReactMethod
public void shareToFavorite(ReadableMap data, Callback callback) {
if (api == null) {
callback.invoke(NOT_REGISTERED);
return;
}
_share(SendMessageToWX.Req.WXSceneFavorite, data, callback);
}
private void _share(final int scene, final ReadableMap data, final Callback callback) {
Uri uri = null;
if (data.hasKey("thumbImage")) {
String imageUrl = data.getString("thumbImage");
try {
uri = Uri.parse(imageUrl);
if (uri.getScheme() == null) {
uri = getResourceDrawableUri(getReactApplicationContext(), imageUrl);
}
} catch (Exception e) {
}
}
if (uri != null) {
this._getImage(uri, new ResizeOptions(100, 100), new ImageCallback() {
@Override
public void invoke(@Nullable Bitmap bitmap) {
WechatModule.this._share(scene, data, bitmap, callback);
}
});
} else {
this._share(scene, data, null, callback);
}
}
private void _getImage(Uri uri, ResizeOptions resizeOptions, final ImageCallback imageCallback) {
BaseBitmapDataSubscriber dataSubscriber = new BaseBitmapDataSubscriber() {
@Override
protected void onNewResultImpl(Bitmap bitmap) {
if (bitmap != null) {
if (bitmap.getConfig() != null) {
bitmap = bitmap.copy(bitmap.getConfig(), true);
imageCallback.invoke(bitmap);
} else {
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
imageCallback.invoke(bitmap);
}
} else {
imageCallback.invoke(null);
}
}
@Override
protected void onFailureImpl(DataSource> dataSource) {
imageCallback.invoke(null);
}
};
ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
if (resizeOptions != null) {
builder = builder.setResizeOptions(resizeOptions);
}
ImageRequest imageRequest = builder.build();
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);
dataSource.subscribe(dataSubscriber, UiThreadImmediateExecutorService.getInstance());
}
private static Uri getResourceDrawableUri(Context context, String name) {
if (name == null || name.isEmpty()) {
return null;
}
name = name.toLowerCase().replace("-", "_");
int resId = context.getResources().getIdentifier(
name,
"drawable",
context.getPackageName());
if (resId == 0) {
return null;
} else {
return new Uri.Builder()
.scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
.path(String.valueOf(resId))
.build();
}
}
private void _share(final int scene, final ReadableMap data, final Bitmap thumbImage, final Callback callback) {
if (!data.hasKey("type")) {
callback.invoke(INVALID_ARGUMENT);
return;
}
String type = data.getString("type");
WXMediaMessage.IMediaObject mediaObject = null;
if (type.equals("news")) {
mediaObject = _jsonToWebpageMedia(data);
} else if (type.equals("text")) {
mediaObject = _jsonToTextMedia(data);
} else if (type.equals("imageUrl") || type.equals("imageResource")) {
__jsonToImageUrlMedia(data, new MediaObjectCallback() {
@Override
public void invoke(@Nullable WXMediaMessage.IMediaObject mediaObject) {
if (mediaObject == null) {
callback.invoke(INVALID_ARGUMENT);
} else {
WechatModule.this._share(scene, data, thumbImage, mediaObject, callback);
}
}
});
return;
} else if (type.equals("imageFile")) {
__jsonToImageFileMedia(data, new MediaObjectCallback() {
@Override
public void invoke(@Nullable WXMediaMessage.IMediaObject mediaObject) {
if (mediaObject == null) {
callback.invoke(INVALID_ARGUMENT);
} else {
WechatModule.this._share(scene, data, thumbImage, mediaObject, callback);
}
}
});
return;
} else if (type.equals("video")) {
mediaObject = __jsonToVideoMedia(data);
} else if (type.equals("audio")) {
mediaObject = __jsonToMusicMedia(data);
} else if (type.equals("file")) {
mediaObject = __jsonToFileMedia(data);
}
if (mediaObject == null) {
callback.invoke(INVALID_ARGUMENT);
} else {
_share(scene, data, thumbImage, mediaObject, callback);
}
}
private void _share(int scene, ReadableMap data, Bitmap thumbImage, WXMediaMessage.IMediaObject mediaObject, Callback callback) {
WXMediaMessage message = new WXMediaMessage();
message.mediaObject = mediaObject;
if (thumbImage != null) {
message.setThumbImage(thumbImage);
}
if (data.hasKey("title")) {
message.title = data.getString("title");
}
if (data.hasKey("description")) {
message.description = data.getString("description");
}
if (data.hasKey("mediaTagName")) {
message.mediaTagName = data.getString("mediaTagName");
}
if (data.hasKey("messageAction")) {
message.messageAction = data.getString("messageAction");
}
if (data.hasKey("messageExt")) {
message.messageExt = data.getString("messageExt");
}
SendMessageToWX.Req req = new SendMessageToWX.Req();
req.message = message;
req.scene = scene;
req.transaction = UUID.randomUUID().toString();
callback.invoke(null, api.sendReq(req));
}
private WXTextObject _jsonToTextMedia(ReadableMap data) {
if (!data.hasKey("description")) {
return null;
}
WXTextObject ret = new WXTextObject();
ret.text = data.getString("description");
return ret;
}
private WXWebpageObject _jsonToWebpageMedia(ReadableMap data) {
if (!data.hasKey("webpageUrl")) {
return null;
}
WXWebpageObject ret = new WXWebpageObject();
ret.webpageUrl = data.getString("webpageUrl");
if (data.hasKey("extInfo")) {
ret.extInfo = data.getString("extInfo");
}
return ret;
}
private void __jsonToImageMedia(String imageUrl, final MediaObjectCallback callback) {
Uri imageUri;
try {
imageUri = Uri.parse(imageUrl);
if (imageUri.getScheme() == null) {
imageUri = getResourceDrawableUri(getReactApplicationContext(), imageUrl);
}
} catch (Exception e) {
imageUri = null;
}
if (imageUri == null) {
callback.invoke(null);
return;
}
this._getImage(imageUri, null, new ImageCallback() {
@Override
public void invoke(@Nullable Bitmap bitmap) {
callback.invoke(bitmap == null ? null : new WXImageObject(bitmap));
}
});
}
private void __jsonToImageUrlMedia(ReadableMap data, MediaObjectCallback callback) {
if (!data.hasKey("imageUrl")) {
callback.invoke(null);
return;
}
String imageUrl = data.getString("imageUrl");
__jsonToImageMedia(imageUrl, callback);
}
private void __jsonToImageFileMedia(ReadableMap data, MediaObjectCallback callback) {
if (!data.hasKey("imageUrl")) {
callback.invoke(null);
return;
}
String imageUrl = data.getString("imageUrl");
if (!imageUrl.toLowerCase().startsWith("file://")) {
imageUrl = "file://" + imageUrl;
}
__jsonToImageMedia(imageUrl, callback);
}
private WXMusicObject __jsonToMusicMedia(ReadableMap data) {
if (!data.hasKey("musicUrl")) {
return null;
}
WXMusicObject ret = new WXMusicObject();
ret.musicUrl = data.getString("musicUrl");
return ret;
}
private WXVideoObject __jsonToVideoMedia(ReadableMap data) {
if (!data.hasKey("videoUrl")) {
return null;
}
WXVideoObject ret = new WXVideoObject();
ret.videoUrl = data.getString("videoUrl");
return ret;
}
private WXFileObject __jsonToFileMedia(ReadableMap data) {
if (!data.hasKey("filePath")) {
return null;
}
return new WXFileObject(data.getString("filePath"));
}
private interface ImageCallback {
void invoke(@Nullable Bitmap bitmap);
}
private interface MediaObjectCallback {
void invoke(@Nullable WXMediaMessage.IMediaObject mediaObject);
}
}
创建WechatPackage.java
package com.xxx.wechat;
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;
public class WechatPackage implements ReactPackage {
@Override
public List createNativeModules(ReactApplicationContext reactContext) {
List modules = new ArrayList<>();
modules.add(new WechatModule(reactContext));
return modules;
}
public List> createJSModules() {
return Collections.emptyList();
}
@Override
public List createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
- 添加模块
android/app/src/main/java/com/xxx/MainApplication.java
...
import com.xxx.wechat.WechatPackage;
...
public class MainApplication extends Application implements ReactApplication {
...
protected List getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List packages = new PackageList(this).getPackages();
...
packages.add(new WechatPackage());
return packages;
}
...
IOS
React Native
import {NativeModules, Platform} from 'react-native';
const WechatModule = NativeModules.Wechat;
class Wechat {
// 注册微信
public registerApp = (appId: string, universalLink?: string) => {
if (Platform.OS === "android") {
return WechatModule.registerApp(appId);
} else {
return WechatModule.registerApp(appId, universalLink);
}
};
// 微信登录
public sendAuthWxLogin = (options: {
scope: string
state: string
}) => {
return WechatModule.sendAuthRequest(options.scope, options.state);
};
//打开微信app
public openWxApp = () => {
return WechatModule.openWxApp();
};
//打开微信小程序
public openMiniProgram = (id: string, path: string) => {
return WechatModule.openMiniProgram(id, path);
};
public shareMini = (data: {
// 标题
title: string;
// 小程序
miniName: PLATNAME_TYPE;
// 分享的路径 pages/index/index?foo=bar
path?: string;
// 兼容低版本的网页链接(官网)
webpageUrl?: string;
// 描述
description?: string;
// 图片
thumbImageUrl: string;
// 正式版:0,测试版:1,体验版:2
miniprogramType?: 0 | 1 | 2;
}) => {
return new Promise((resolve) => {
WechatModule.shareMiniProgram({
miniprogramType: data.miniprogramType || 0,
webpageUrl: data.webpageUrl || 'https://www.xxxx.com', // 官网
userName: APPID[data.miniName].originalId,
path: data.path || '',
description: data.description || '',
thumbImageUrl: data.thumbImageUrl,
scene: 0,
title: data.title
}, () => {
resolve();
});
});
};
// 分享给好友
public shareToSession = (data: {
type: 'news' | 'text' | 'imageUrl' | 'imageFile' | 'imageResource' | 'video' | 'audio' | 'file'
title?: string;
thumbImage?: string
webpageUrl?: string
imageUrl?: string
videoUrl?: string
musicUrl?: string
filePath?: string
fileExtension?: string
description?: string
extInfo?: string
}) => {
return new Promise((resolve) => {
WechatModule.shareToSession(data, () => {
resolve();
})
});
};
// 分享到朋友圈
public shareToTimeline = (data: {
type: 'news' | 'text' | 'imageUrl' | 'imageFile' | 'imageResource' | 'video' | 'audio' | 'file'
title?: string;
thumbImage?: string
webpageUrl?: string
imageUrl?: string
videoUrl?: string
musicUrl?: string
filePath?: string
fileExtension?: string
description?: string
extInfo?: string
}) => {
return Promise((resolve) => {
WechatModule.shareToTimeline(data, () => {
resolve();
});
})
};
// 支付
public pay = (options: {
appid: string;
partnerid: string; // 商家向财付通申请的商家id
prepayid: string; // 预支付订单
noncestr: string; // 随机串,防重发
timestamp: number; // 时间戳,防重发.
package: string; // 商家根据财付通文档填写的数据和签名
sign: string; // 商家根据微信开放平台文档对数据做的签名
}) => {
return WechatModule.pay(options);
};
}