从实际案例看 H5 与 WebView 交互
现在运营需要设计一个活动页面,这个页面需要支持如下功能:
<img src="https://img-blog.csdnimg.cn/direct/9cf7eeedd91d48088c3c1695941521cf.jpeg" width="375px"/>
<img src="https://img-blog.csdnimg.cn/direct/a78eef74969a46d0bc7f9348275329eb.jpeg" width="375px"/>
- 支持分享到微信的好友和朋友圈
- 支持长按保存图片
- 支持打开小程序(一键获取干货)
同时,这个活动页面不仅能在微信浏览器打开,还希望能在 APP
内部打开,并且同样支持上述功能。
现在按终端把需求进行拆解:
- 微信端
- APP 端
当前专注于在微信中实现各项功能,接下来我们将一一实现这些功能。
1. 微信内
1.1 实现分享到朋友圈、会话功能
需要借助 JS-SDK
来完成相关的功能,大概步骤如下:
- 先登录微信公众平台进入
公众号设置
的功能设置
里填写JS 接口安全域名
- 引入
JS
文件
大部分情况下,都是使用单页应用模式,可以通过直接在入口文件中引入或者通过动态加载的方式来使用。在这里,直接在入口文件中引入的方式更为方便。
<script src="http://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
- 通过
config
接口注入权限验证配置
// 服务端与微信后端交互,生成签名相关信息
const sha1 = require('crypto-js/sha1');
router.post('/getWxConfig', async function (req, res) {
try {
// 1. 获取 access_token
const { access_token } = await request.get('/cgi-bin/token', {
grant_type: 'client_credential',
appid,
secret,
});
// 2. 获取 ticket
const { ticket } = await request.get('/cgi-bin/ticket/getticket', {
access_token,
type: 'jsapi',
});
// 3. 获取签名
const { url } = req.body;
const noncestr = Math.random().toString(36).substring(2, 15);
const timestamp = parseInt(new Date().getTime() / 1000) + '';
const str = `jsapi_ticket=${ticket}&noncestr=${noncestr}×tamp=${timestamp}&url=${url}`;
const signature = sha1(str).toString();
// 4. 返回数据
res.json(
new Result({
data: {
appid,
timestamp,
nonceStr: noncestr,
signature,
},
})
);
} catch (error) {
res.json(
new Result({
code: 'BIZ_ERROR',
msg: error.errmsg || error.message,
})
);
}
});
// H5 页面,初始化 wx 配置
import { onMounted } from 'vue';
export default {
setup() {
const initWechatConfig = () => {
return getWxConfig({
url: location.href,
})
.then(({ data }) => {
const { appId, timestamp, noncestr, signature } = data;
wx.config({
debug: false, // 开发环境使用
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature, // 必填,签名
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'], // 必填,需要使用的JS接口列表
});
})
.catch((e) => {
console.error('getWxConfig error:::', e);
});
};
onMounted(() => {
initWechatConfig();
});
},
};
- 通过
ready
接口处理成功验证
当前面签名相关信息配置成功后,就会正常执行 ready
方法。
import { onMounted } from 'vue';
const shareConfig = {
title: '测一测你是哪种类型的程序员?',
desc: '代码世界不止0和1,还有独特的你!',
link: `${window.location.origin}/`,
imgUrl: `${window.location.origin}/thumbnail.png`,
};
export default {
setup() {
const initWechatConfig = () => {
return getWxConfig({
url: location.href,
})
.then(({ data }) => {
const { appId, timestamp, noncestr, signature } = data;
wx.config({
debug: false, // 开发环境使用
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature, // 必填,签名
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'], // 必填,需要使用的JS接口列表
});
wx.ready(() => {
const { title, desc, link, imgUrl } = shareConfig;
// 分享会话
wx.updateAppMessageShareData({
title, // 分享标题
desc, // 分享描述
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
// 朋友圈
wx.updateTimelineShareData({
title, // 分享标题
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
});
})
.catch((e) => {
console.error('getWxConfig error:::', e);
});
};
onMounted(() => {
initWechatConfig();
});
},
};
- 通过
error
接口处理失败验证
<script>
import { onMounted } from 'vue';
const shareConfig = {
title: '测一测你是哪种类型的程序员?',
desc: '代码世界不止0和1,还有独特的你!',
link: `${window.location.origin}/`,
imgUrl: `${window.location.origin}/thumbnail.png`,
};
export default {
setup() {
const initWechatConfig = () => {
return getWxConfig({
url: location.href,
})
.then(({ data }) => {
const { appId, timestamp, noncestr, signature } = data;
wx.config({
debug: false, // 开发环境使用
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature, // 必填,签名
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'], // 必填,需要使用的JS接口列表
});
wx.ready(() => {
const { title, desc, link, imgUrl } = shareConfig;
// 分享会话
wx.updateAppMessageShareData({
title, // 分享标题
desc, // 分享描述
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
// 朋友圈
wx.updateTimelineShareData({
title, // 分享标题
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
});
wx.error((res) => {
// todo
// 可以在这里保存状态,并在操作相关地方提醒用户,防止用户点击没任何反馈
console.log('res', res);
});
})
.catch((e) => {
console.error('getWxConfig error:::', e);
});
};
onMounted(() => {
initWechatConfig();
});
},
};
</script>
上面完成微信内如何实现分享到朋友圈、分享到会话的功能。包括公众号配置、服务端生成签名、客户端请求对应签名信息以及完成相应的初始化。
1.2 完成长按保存图片到相册
在微信内部,默认是支持长按图片进行保存到相册的。由于海报是通过 canvas
进行绘制的,我们可以使用 canvas
提供的方法 toDataURL
将图像转换为对应的 base64
格式的图片地址,然后通过 img
标签进行渲染。
<template>
<img v-if="base64URL" src="base64URL" />
</template>
<script>
import { onMounted, ref } from 'vue';
const shareConfig = {
title: '测一测你是哪种类型的程序员?',
desc: '代码世界不止0和1,还有独特的你!',
link: `${window.location.origin}/`,
imgUrl: `${window.location.origin}/thumbnail.png`,
};
export default {
setup() {
const base64URL = ref('');
// 初始化公众号配置
const initWechatConfig = () => {
return getWxConfig({
url: location.href,
})
.then(({ data }) => {
const { appId, timestamp, noncestr, signature } = data;
wx.config({
debug: false, // 开发环境使用
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature, // 必填,签名
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'], // 必填,需要使用的JS接口列表
});
wx.ready(() => {
const { title, desc, link, imgUrl } = shareConfig;
// 分享会话
wx.updateAppMessageShareData({
title, // 分享标题
desc, // 分享描述
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
// 朋友圈
wx.updateTimelineShareData({
title, // 分享标题
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
});
wx.error((res) => {
console.log('res', res);
});
})
.catch((e) => {
console.error('getWxConfig error:::', e);
});
};
const drawPoster = () => {
// 直接创建元素,在内存中直接完成绘制
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio;
canvas.width = 375;
canvas.height = 1334;
// 绘制图片
// 绘制文本
// ...
base64URL.value = canvas.toDataURL();
};
onMounted(() => {
initWechatConfig();
drawPoster();
});
return {
base64URL,
};
},
};
</script>
1.3 打开小程序
这就非常简单了,只需要获取到小程序对应 URL Scheme
即可。
<template>
<img v-if="base64URL" src="base64URL" />
<button @click="onGetCourse">一键获取干货</button>
</template>
<script>
import { onMounted, ref } from 'vue';
const shareConfig = {
title: '测一测你是哪种类型的程序员?',
desc: '代码世界不止0和1,还有独特的你!',
link: `${window.location.origin}/`,
imgUrl: `${window.location.origin}/thumbnail.png`,
};
export default {
setup() {
const base64URL = ref('');
// 初始化公众号配置
const initWechatConfig = () => {
return getWxConfig({
url: location.href,
})
.then(({ data }) => {
const { appId, timestamp, noncestr, signature } = data;
wx.config({
debug: false, // 开发环境使用
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature, // 必填,签名
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'], // 必填,需要使用的JS接口列表
});
wx.ready(() => {
const { title, desc, link, imgUrl } = shareConfig;
// 分享会话
wx.updateAppMessageShareData({
title, // 分享标题
desc, // 分享描述
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
// 朋友圈
wx.updateTimelineShareData({
title, // 分享标题
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
});
wx.error((res) => {
console.log('res', res);
});
})
.catch((e) => {
console.error('getWxConfig error:::', e);
});
};
const drawPoster = () => {
// 直接创建元素,在内存中直接完成绘制
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio;
canvas.width = 375;
canvas.height = 1334;
// 绘制图片
// 绘制文本
// ...
base64URL.value = canvas.toDataURL();
};
const openMiniProgram = () => {
const miniURLScheme = 'weixin://dl/business/?t=dgQQRtdOgOs';
location.href = miniURLScheme;
};
const onGetCourse = () => {
openMiniProgram();
};
onMounted(() => {
initWechatConfig();
drawPoster();
});
return {
base64URL,
onGetCourse,
};
},
};
</script>
目前已经实现了在微信浏览器内部的功能,包括微信分享、长按保存图片到相册、打开小程序等。接下来我们将优化这些功能,使其能够在 APP
内部实现
2. APP 内
在微信内打开 H5 时,分享朋友圈、好友等功能通常是在微信宿主环境下结合 jweixin sdk
实现的。然而,当网页在 APP
中打开时,宿主环境变成了 APP
,此时 jweixin sdk
将失效。
要实现这些功能,我们需要从 APP
这个宿主环境上来想办法。完成这些功能其实并不难。
将功能分解为:
- APP 与 微信交换
- APP 与 H5 交互
首先,APP 可以通过引入原生的 share
模块与微信 APP
进行交互。
现在只需要解决 H5
与 APP
的交互就可以实现这些功能。也就是说,我们需要让 H5
能够调用 APP
中的分享功能,这样就可以实现在 APP
中打开网页时也能享受到微信的分享功能。
通常,当 webview
和 H5
页面需要进行交互时,会使用桥接方式,也就是所谓的"jsbridge"。简单来说,原生应用会在 webview
的上下文中注入一些 API
,使得 H5
页面可以通过访问这些 API
与原生应用进行交互。同时,H5
页面也可以通过特定的渠道来接收原生应用发送的消息,实现双向通信。
在 uniapp 中也不例外, uniapp 封装 webview
的 API
成特定的 sdk 供 H5 调用,这样做的好处是方便维护和更新迭代。即使内部 API 发生变更,对外使用的 API 也可以保持不变。这样可以减少对 H5 开发者的影响,同时也提高了代码的稳定性和可维护性。
上面把整个交互流程捋顺了,接下来可以进入实际编码环节了。
2.1 APP 引入原生模块
- 微信 appid 申请步骤: https://ask.dcloud.net.cn/article/208
- iOS 平台微信 SDK 配置通用链接: https://ask.dcloud.net.cn/article/36445
说明下,我们的 APP
是通过 uniapp
开发的。上图是 HBuilderX
配置的截图。
APP 分享功能配置完成后,接着实现 H5 与 APP 交互。
2.2 实现分享到朋友圈、会话功能
2.2.1 H5 页面中引入 uni.webview.js
<script
type="text/javascript"
src="https://gitee.com/dcloud/uni-app/raw/dev/dist/uni.webview.1.5.4.js"
></script>
2.2.2 定义 webview
加载 H5
页面
<template>
<web-view :src="src"></web-view>
</template>
<script>
let wv;
export default {
data() {
return {
src: '',
};
},
onLoad(options) {
this.src = options.src;
// #ifdef APP-PLUS
// 此对象相当于 html5plus 里的 plus.webview.currentWebview()。在uni-app里vue页面直接使用plus.webview.currentWebview()无效,非v3编译模式使用this.$mp.page.
const currentWebview = this.$scope.$getAppWebview();
setTimeout(function () {
wv = currentWebview.children()[0];
wv.setStyle({
scalable: false,
});
}, 200); //如果是页面初始化调用时,需要延时一下
// #endif
},
};
</script>
2.2.3 定义 webview
的 message
事件监听器,处理 H5
发送的事件
- APP 监听消息
<template>
<web-view :src="src" @message="message"></web-view>
</template>
<script>
let wv;
export default {
data() {
return {
src: '',
};
},
onLoad(options) {
this.src = options.src;
// #ifdef APP-PLUS
// 此对象相当于 html5plus 里的 plus.webview.currentWebview()。在uni-app里vue页面直接使用plus.webview.currentWebview()无效,非v3编译模式使用this.$mp.page.
const currentWebview = this.$scope.$getAppWebview();
setTimeout(function () {
wv = currentWebview.children()[0];
wv.setStyle({
scalable: false,
});
}, 200); //如果是页面初始化调用时,需要延时一下
// #endif
},
methods: {
message(event) {
/**
* 1. webview 需要接受多种消息类型,不同的消息类型业务逻辑不同。 考虑后面扩展把消息格式约定如下:
* {
* eventType: 'share|saveImageToPhotosAlbum'
* data: {}
* }
*/
const data = event.detail.data;
if (Array.isArray(data) && data.length > 0) {
const { eventType, data } = data[0];
switch (config.eventType) {
case 'share':
uni.share(data);
break;
default:
break;
}
}
},
},
};
</script>
- H5 发送事件
<template>
<img v-if="base64URL" src="base64URL" />
<button @click="onGetCourse">一键获取干货</button>
<button @click="onAppMessageShare">分享至微信好友</button>
<button @click="onTimelineShare">分享至朋友圈</button>
</template>
<script>
import { onMounted, ref } from 'vue';
const shareConfig = {
title: '测一测你是哪种类型的程序员?',
desc: '代码世界不止0和1,还有独特的你!',
link: `${window.location.origin}/`,
imgUrl: `${window.location.origin}/thumbnail.png`,
};
const wxSceneSession = 'WXSceneSession'; // 微信会话
const wxSceneTimeline = 'WXSceneTimeline'; // 微信朋友圈
export default {
setup() {
const base64URL = ref('');
const isWechatBrowser = () => {
const ua = window.navigator.userAgent.toString();
return ua.includes('MicroMessenger');
};
// 在 uniapp webview 中
const inWebviewInner = '__WebVieW_Id__' in window;
// 初始化公众号配置
const initWechatConfig = () => {
return getWxConfig({
url: location.href,
})
.then(({ data }) => {
const { appId, timestamp, noncestr, signature } = data;
wx.config({
debug: false, // 开发环境使用
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature, // 必填,签名
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'], // 必填,需要使用的JS接口列表
});
wx.ready(() => {
const { title, desc, link, imgUrl } = shareConfig;
// 分享会话
wx.updateAppMessageShareData({
title, // 分享标题
desc, // 分享描述
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
// 朋友圈
wx.updateTimelineShareData({
title, // 分享标题
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
});
wx.error((res) => {
console.log('res', res);
});
})
.catch((e) => {
console.error('getWxConfig error:::', e);
});
};
const drawPoster = () => {
// 直接创建元素,在内存中直接完成绘制
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio;
canvas.width = 375;
canvas.height = 1334;
// 绘制图片
// 绘制文本
// ...
base64URL.value = canvas.toDataURL();
};
const openMiniProgram = () => {
const miniURLScheme = 'weixin://dl/business/?t=dgQQRtdOgOs';
location.href = miniURLScheme;
};
const onGetCourse = () => {
openMiniProgram();
};
const sendMessage = (scene) => {
if (window.webUni) {
window.webUni.postMessage({
data: {
eventType: 'share',
provider: 'weixin',
scene,
type: 0,
href: shareConfig.link,
title: shareConfig.title,
summary: shareConfig.desc,
imageUrl: shareConfig.imgUrl,
},
});
} else {
uni.showToast({
title: '分享功能初始化失败',
});
}
};
const onAppMessageShare = () => {
sendMessage(wxSceneSession);
};
const onTimelineShare = () => {
sendMessage(wxSceneTimeline);
};
const addEventListener = () => {
document.addEventListener('UniAppJSBridgeReady', () => {
console.log(window.webUni);
});
};
onMounted(() => {
// 这里按需执行,只在微信浏览器才执行对应的初始化操作。理想情况下,对应 wxsdk 也是可以在微信环境才去加载,这里方便就直接在入口文件中引入了。
if (isWechatBrowser()) {
initWechatConfig();
} else if (inWebviewInner) {
addEventListener();
}
drawPoster();
});
return {
base64URL,
onGetCourse,
onAppMessageShare,
onTimelineShare,
};
},
};
</script>
在 H5 页面上,我们已经成功实现了与 APP 的交互,并成功调用了 APP 提供的分享到朋友圈和会话的功能。
2.3 完成长按保存图片到相册
在微信浏览器内部,我们可以通过微信提供的长按图片功能来保存图片。然而,在 APP 中,我们需要自己来实现长按保存功能。现在我们来分析一下如何实现。
首先,在 H5
中,我们可以获取到图片对应的 base64 URL
。同样,在APP
中,我们可以使用 saveImageToPhotosAlbum
函数来保存图片到相册。只要将图片数据发送给 APP,就可以成功将图片存储到相册中。
2.3.1 分析下 saveImageToPhotosAlbum 参数
uni.saveImageToPhotosAlbum({
filePath:
'图片文件路径,可以是临时文件路径也可以是永久文件路径,不支持网络图片路径',
success: () => {},
fail: () => {},
complete: () => {},
});
filePath
并不支持直接传入 base64
格式以及网络图片,只能把图片先保存到本地文件系统目录下。 怎么把 base64
图片保存到本地文件系统目录下? [Bitmap](https://www.dcloud.io/docs/api/zh_cn/nativeobj.html#plus.nativeObj.Bitmap)
。 在 HTML5+
中,提供通过 window.plus.nativeObj.Bitmap
方式创建 bitmap
对象,通过 bitmap
实例中 loadBase64Data
加载 Base64
编码格式图片到 Bitmap
对象中,再调用save
方法保存图片(保存到本地文件系统中,如果图片为空或者指定的路径文件已经存在则返回失败)。
2.3.2 图片添加长按事件
<!-- H5页面 -->
<template>
<img v-if="base64URL" src="base64URL" @longtap="onLongtap" />
<button @click="onGetCourse">一键获取干货</button>
<button @click="onAppMessageShare">分享至微信好友</button>
<button @click="onTimelineShare">分享至朋友圈</button>
</template>
<script>
import { onMounted, ref } from 'vue';
const shareConfig = {
title: '测一测你是哪种类型的程序员?',
desc: '代码世界不止0和1,还有独特的你!',
link: `${window.location.origin}/`,
imgUrl: `${window.location.origin}/thumbnail.png`,
};
const wxSceneSession = 'WXSceneSession'; // 微信会话
const wxSceneTimeline = 'WXSceneTimeline'; // 微信朋友圈
export default {
setup() {
const base64URL = ref('');
const isWechatBrowser = () => {
const ua = window.navigator.userAgent.toString();
return ua.includes('MicroMessenger');
};
// 在 uniapp webview 中
const inWebviewInner = '__WebVieW_Id__' in window;
// 初始化公众号配置
const initWechatConfig = () => {
return getWxConfig({
url: location.href,
})
.then(({ data }) => {
const { appId, timestamp, noncestr, signature } = data;
wx.config({
debug: false, // 开发环境使用
appId, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr, // 必填,生成签名的随机串
signature, // 必填,签名
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'], // 必填,需要使用的JS接口列表
});
wx.ready(() => {
const { title, desc, link, imgUrl } = shareConfig;
// 分享会话
wx.updateAppMessageShareData({
title, // 分享标题
desc, // 分享描述
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
// 朋友圈
wx.updateTimelineShareData({
title, // 分享标题
link, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
imgUrl, // 分享图标
success() {
// todo...
},
});
});
wx.error((res) => {
console.log('res', res);
});
})
.catch((e) => {
console.error('getWxConfig error:::', e);
});
};
const drawPoster = () => {
// 直接创建元素,在内存中直接完成绘制
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio;
canvas.width = 375;
canvas.height = 1334;
// 绘制图片
// 绘制文本
// ...
base64URL.value = canvas.toDataURL();
};
const openMiniProgram = () => {
const miniURLScheme = 'weixin://dl/business/?t=dgQQRtdOgOs';
location.href = miniURLScheme;
};
const onGetCourse = () => {
openMiniProgram();
};
const sendMessage = (scene) => {
if (window.webUni) {
window.webUni.postMessage({
data: {
eventType: 'share',
provider: 'weixin',
scene,
type: 0,
href: shareConfig.link,
title: shareConfig.title,
summary: shareConfig.desc,
imageUrl: shareConfig.imgUrl,
},
});
} else {
uni.showToast({
title: '分享功能初始化失败',
});
}
};
const onAppMessageShare = () => {
sendMessage(wxSceneSession);
};
const onTimelineShare = () => {
sendMessage(wxSceneTimeline);
};
const addEventListener = () => {
document.addEventListener('UniAppJSBridgeReady', () => {
console.log(window.webUni);
});
};
const onLongtap = () => {
if (window.plus) {
const bitmap = new window.plus.nativeObj.Bitmap('poster');
bitmap.loadBase64Data(base64URL.value, () => {
const url = `_doc/${Date.now()}.png`;
bitmap.save(
url,
{
overwrite: true,
},
(i) => {
window.webUni.postMessage({
data: {
eventType: 'saveImageToPhotosAlbum',
data: i.target,
},
});
},
() => {
uni.showToast({
title: '保存图片失败',
});
}
);
});
}
};
onMounted(() => {
// 这里按需执行,只在微信浏览器才执行对应的初始化操作。理想情况下,对应 wxsdk 也是可以在微信环境才去加载,这里方便就直接在入口文件中引入了。
if (isWechatBrowser()) {
initWechatConfig();
} else if (inWebviewInner) {
addEventListener();
}
drawPoster();
});
return {
base64URL,
onGetCourse,
onAppMessageShare,
onTimelineShare,
};
},
};
</script>
2.3.3 webview 处理自定义的 saveImageToPhotosAlbum 事件
<template>
<web-view :src="src" @message="message"></web-view>
</template>
<script>
let wv;
export default {
data() {
return {
src: '',
};
},
onLoad(options) {
this.src = options.src;
// #ifdef APP-PLUS
// 此对象相当于 html5plus 里的 plus.webview.currentWebview()。在uni-app里vue页面直接使用plus.webview.currentWebview()无效,非v3编译模式使用this.$mp.page.
const currentWebview = this.$scope.$getAppWebview();
setTimeout(function () {
wv = currentWebview.children()[0];
wv.setStyle({
scalable: false,
});
}, 200); //如果是页面初始化调用时,需要延时一下
// #endif
},
methods: {
message(event) {
/**
* 1. webview 需要接受多种消息类型,不同的消息类型业务逻辑不同。 考虑后面扩展把消息格式约定如下:
* {
* eventType: 'share|saveImageToPhotosAlbum|lanuchMinPro'
* data: {}
* }
*/
const data = event.detail.data;
if (Array.isArray(data) && data.length > 0) {
const { eventType, data } = data[0];
switch (config.eventType) {
case 'share':
uni.share(data);
break;
case 'saveImageToPhotosAlbum':
uni.saveImageToPhotosAlbum({
filePath: config.data,
success: () => {
uni.showToast({
title: '图片保存成功',
});
},
fail: () => {
uni.showToast({
title: '图片保存失败',
});
},
});
break;
default:
break;
}
}
},
},
};
</script>
2.4 打开小程序
在 APP
中打开小程序,可以通过如下的方式:
// 方式一:
const openMiniProgram = () => {
const miniURLScheme = 'weixin://dl/business/?t=dgQQRtdOgOs';
location.href = miniURLScheme;
};
// 方式二:
const openMiniProgram2 = () => {
// #ifdef APP
plus.share.getServices(function (res) {
let sweixin = null;
//
for (let i = 0; i < res.length; i++) {
let t = res[i];
if (t.id === 'weixin') {
sweixin = t;
}
}
if (sweixin) {
sweixin.launchMiniProgram({
id: 'gh_245f93d8f342',
path: '/pages/mine/index',
type: 0,
});
} else {
uni.showToast({
title: '当前环境不支持微信操作!',
});
}
});
// #endif
};
到目前为止,我们已经成功在微信
和 APP
的不同宿主环境中分别实现了所有功能。
3. 常见问题
3.1 如何在本地调试微信分享功能
- 下载花生壳
- 配置外网映射(将本地 H5 项目 IP 和端口映射到外网)
- 在公众号将外网映射域名添加到公众号中的
JS 接口安全域名
下 这样就可以很方便调试公众号相关的分享功能了
3.2 配置服务器白名单
在服务端调用微信接口时,如果没有配置服务器白名单,就会出现如下错误:
- "invalid ip 175.9.143.154 ipv6 ::ffff:175.9.143.154, not in whitelist rid: 6571d1d4-7f45e7df-2d05fc1b"
原因是微信 access_token
刷新需要添加服务器白名单
注意:配置完成后,并不会实时生效。
如果您有任何疑问,请随时在评论区留言。
总结
本文介绍了如何利用 jweixin sdk
在微信内部完成会话和朋友圈分享。同时,还讲解了 webview
与 H5
交互的原理,并介绍了如何借助 APP
的能力实现微信分享功能。最后,还详细讲解了如何利用 bitmap
将 H5
中的 base64
图片格式存储到本地系统目录中,并最终将图片保存到相册中。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。