從實際案例看 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 圖片格式存儲到本地系統目錄中,並最終將圖片保存到相冊中。