微信分享前端开发全程详解含iOS、安卓、H5、ReactNative以及微信开放标签的适配和使用
编者按: 红宝书第5版2024年12月1日出炉了,涵盖了JS最新版本ES15的特性,感兴趣的可以去看看,https://u.jd.com/saQw1vP 2024年9月,本人在做微信分享前端部分的iOS、安卓和H5的页面和功能时踩了不少坑,于是写了这篇文章,内容包括微信分享在上面三个端的技术点和坑点、解决办法,微信开放标签的相关适配,以及ReactNative的特别处理部分。
重要通知:红宝书第5版2024年12月1日出炉了,涵盖了JS最新版本ES15的特性,感兴趣的可以去看看,https://u.jd.com/saQw1vP
红宝书第五版中文版
红宝书第五版英文原版pdf下载(访问密码: 9696)
一、前期准备:微信开放平台、微信公众平台注册并审核通过
1、微信开放平台入口
2、微信公众平台入口
3、官网域名,分享用网页的域名(可以是二级域名)部署完成,ICP备案完成。
Tip1:微信开放平台认证一次性的三百。公众平台首次认证三百,认证到期后每年需要再年审三百。平台网页:https://developers.weixin.qq.com/community/develop/doc/000c040991c220d8dcea6324e56000
Tip2:官网域名用于iOS的Universal Links,分享用网页的域名用于放到js接口安全域名
里面,凡是在js接口安全域名
里的网页在微信里打开都可以使用开放标签和对应的微信js接口。后面会说怎么放。
Tip3:注册和申请这两个平台的同时,移动应用也添加和关联进去,后面要用到APPID,另外移动应用需要开启微信分享功能,详见文档。
二、客户端SDK集成:
1、友盟分享集成 开发文档
2、微信官网自行集成 开发文档
本人用的是友盟分享集成,也可以微信官网自行集成,如果友盟分享已经集成了那至少微信文档里SDK的集成这一步已经完成了。
不要遗漏文档里任何一处,以免后面遇到不该遇到的坑。
注意iOS需要配置Universal Links:参考文档
有个需要服务端或运维小伙伴配合的步骤,就是创建个文件名为apple-app-site-association
的文件,没有后缀,里面的内容如下,
根据自己的参数来修改里面appID和paths的内容
{ |
然后让后端或者运维小伙伴,把这个文件放在官网的服务器根目录下。
比如服务器地址是: https://www.baidu.com/ ,把文件放在这根目录下后,访问 https://www.baidu.com/apple-app-site-association ,这文件就会被下载下来。
然后根目录新建一个.well-known文件夹,里面也放一份这个文件,这样会先去根目录找,如果没找到还会去.well-known文件夹找
三、微信分享H5页面开发(本人用的是Vue2)
H5开发需要适配两个端:手机浏览器端和微信浏览器端
1、手机浏览器的适配比较简单,跳转APP采用Schema逻辑(iOS和安卓均可)。
H5
// 打开app 目前采用的方法 用于适配非微信端打开的网页跳转app并传参 |
2、微信浏览器端的适配,需要使用微信的开放标签来处理H5和APP的跳转逻辑
微信开放标签:
1、绑定域名加入JS接口安全域名
登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
2、使用前需将「 JS 接口安全域名绑定的服务号」绑定在「移动应用的微信开放平台账号」下,并确保服务号与此开放平台账号同主体且均已认证。请前往 微信开放平台-管理中心-公众号详情-接口信息 设置域名与所需跳转的移动应用。
具体流程参考这篇说明文档:
https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_H5_Launch_APP.html
3、根据开发文档开发适配微信端网页开放标签,具体流程参考这篇文档:
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_Open_Tag.html
注意:
1、安全角度考虑,下面这段所需的参数从服务器接口获取,不要放前端
wx.config({ |
2、网页的域名和审核通过的js安全域名Host完全一致 + 第一点里面的config初始化成功 + 要在微信里面打开此网页 = 能显示微信开放标签里的内容且点击能跳转到APP,缺一不可
3、开放标签里放不了本地的图,本地的图可以上传到oss上生成链接的形式展示
<wx-open-launch-app |
4、开放标签里不能使用postion为fixed和absolute的样式,无效,如果需要可以在开放标签里设置style,加fixed或absolute
参考5里面的代码
5、一个取巧的办法是开放标签可以是透明的盖住普通浏览器样式的页面组件,实现微信端点击跳转APP且无需适配开放标签里面的样式
<wx-open-launch-app |
6 也可以根据网页是否在微信里打开的来进一步适配浏览器和微信的页面
如上的代码里有个iswxlet ua = window.navigator.userAgent.toLowerCase()
// 通过正则表达式匹配ua中是否含有MicroMessenger字符串
if (ua.match(/MicroMessenger/i) == 'micromessenger') {
this.iswx = true
} else {
this.iswx = false
}
四、客户端处理跳转逻辑
参考开发文档
1、安卓部分 - 浏览器通过schema跳转
安卓 MainActivity.java
文件里
|
安卓部分 - 微信页面通过开放标签跳转
在WXEntryActivity
文件里/**
* 从微信启动App
*
* @param req
*/
public void onReq(BaseReq req) {
super.onReq(req);
//获取开放标签传递的extinfo数据逻辑
try {
if (req.getType() == ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX && req instanceof ShowMessageFromWX.Req) {
ShowMessageFromWX.Req showReq = (ShowMessageFromWX.Req) req;
WXMediaMessage mediaMsg = showReq.message;
String extInfo = mediaMsg.messageExt;
// 原生这里已经可以处理跳转逻辑了
}
} catch (Exception e) {
e.printStackTrace();
}
}
2、iOS部分 - 浏览器通过schema跳转
参考这篇帖子
iOS AppDelete.mm
文件里
// 支持所有iOS系统 |
iOS部分 - 微信页面通过开放标签跳转
在通过Schema跳转的代码基础上,加上下面这段
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray * __nullable restorableObjects))restorationHandler |
3、ReactNative的特殊处理
ReactNative在获取到浏览器或者微信传来的ScehmaInfo后,发送消息到JS的操作在前面的代码里都写进去了,可以看对应的注释。
安卓由于ReactNative就一个MainActivity,拿到微信传过来的数据后还需要特殊处理。
在WXEntryActivity
文件里/**
* 从微信启动App
*
* @param req
*/
public void onReq(BaseReq req) {
super.onReq(req);
//获取开放标签传递的extinfo数据逻辑
try {
if (req.getType() == ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX && req instanceof ShowMessageFromWX.Req) {
ShowMessageFromWX.Req showReq = (ShowMessageFromWX.Req) req;
WXMediaMessage mediaMsg = showReq.message;
String extInfo = mediaMsg.messageExt;
// 原生这里已经可以处理跳转逻辑了,ReactNative需要特殊处理下,判断MainActivity是否存在,也就是说APP是否处于杀死状态
if (ActivityUtils.isActivityExistsInStack(MainActivity.class)) {
// 发送到RN端
MainApplication application = (MainApplication) this.getApplicationContext();
WritableMap map = Arguments.createMap();
map.putString("schemaInfo", extInfo);
ReactInstanceManager reactInstanceManager = application.getReactNativeHost().getReactInstanceManager();
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext != null) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("Demo_EmitterKey", map);
} else {
reactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() {
public void onReactContextInitialized(ReactContext context) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
/**
*要执行的操作
*/
context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("Demo_EmitterKey", map);
}
}, 4000);//4秒后执行Runnable中的run方法
reactInstanceManager.removeReactInstanceEventListener(this);
}
});
}
} else {
// 如果APP处于启动状态,则到MainActivity里处理逻辑
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("keySendToMainActivity", extInfo);
startActivity(intent);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
在MainActivity
文件里
protected void onCreate(Bundle savedInstanceState) {
MainApplication.getInstance().setMainActivity(this);
super.onCreate(null);
...
// 这里加上这些内容
if (getIntent().getStringExtra("keySendToMainActivity") != null && !"".equals(getIntent().getStringExtra("keySendToMainActivity"))) {
// 发送到RN端
MainApplication application = (MainApplication) this.getApplicationContext();
WritableMap map = Arguments.createMap();
map.putString("schemaInfo", getIntent().getStringExtra("keySendToMainActivity"));
ReactInstanceManager reactInstanceManager = application.getReactNativeHost().getReactInstanceManager();
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if(reactContext != null) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("Demo_EmitterKey", map);
} else {
reactInstanceManager.addReactInstanceEventListener(new ReactInstanceManager.ReactInstanceEventListener() {
public void onReactContextInitialized(ReactContext context) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
/**
*要执行的操作
*/
context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("Demo_EmitterKey", map);
}
}, 4000);//4秒后执行Runnable中的run方法
reactInstanceManager.removeReactInstanceEventListener(this);
}
});
}
}
}
鼓励一下
如果觉得我的文章对您有用,欢迎打赏(右边栏二维码),您的支持将鼓励我继续创作!”
咨询联系方式
版权声明: 转载时请注明作者Kovli以及本文地址: http://www.kovli.com/2024/12/18/wx-share/