在開(kāi)發(fā)小程序的過(guò)程中届搁,我遇到了這樣的一個(gè)需求帕识,通過(guò)短信中的鏈接打開(kāi)一個(gè)h5,這個(gè)h5可以實(shí)現(xiàn)點(diǎn)擊跳轉(zhuǎn)小程序胰柑,或者掃碼跳轉(zhuǎn)截亦,并且將鏈接上的參數(shù)填充到小程序界面上。下面來(lái)描述一下我的開(kāi)發(fā)步驟及實(shí)現(xiàn)方案柬讨。
這個(gè)需求大部分的功能是基于 h5 頁(yè)面實(shí)現(xiàn)的魁巩,所以首先進(jìn)行對(duì) h5 頁(yè)面的攻破。樣式部分不多說(shuō)姐浮,開(kāi)始攻破兩大功能點(diǎn)谷遂。
1. 通過(guò)點(diǎn)擊按鈕跳轉(zhuǎn)小程序
點(diǎn)擊按鈕跳轉(zhuǎn)即通過(guò)鏈接實(shí)現(xiàn)跳轉(zhuǎn),這里使用了小程序官方 api - urlscheme.generate
在這個(gè)api中提到獲取 URL Scheme 需要 access_token卖鲤。
access_token肾扰,是小程序全局唯一后臺(tái)接口調(diào)用憑據(jù)。需要通過(guò)官方 api - auth.getAccessToken 去調(diào)取蛋逾,文檔中提示 access_token 有效期是 2個(gè)小時(shí)集晚,所以我將獲取的 access_token 存儲(chǔ)在 redis 中,并設(shè)定過(guò)期時(shí)間区匣,避免反復(fù)調(diào)用造成 access_token 刷新偷拔,產(chǎn)生不必要的沖突。
下面是獲取 accessToken 的代碼實(shí)現(xiàn):
const getAccessToken = (appId, appSecret) => {
return new Promise((resolve, reject) => {
// 從 redis 中查找是否有 accessToken,如果 accessToken 過(guò)期莲绰,則獲取不到 accessToken
getRedisData(appId).then((accessToken) => {
if (!!accessToken) {
// 有 accessToken 則直接返回
resolve(accessToken);
} else {
// 沒(méi)有則通過(guò)接口重新獲取 accessToken
request({
url: `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appId}&secret=${appSecret}`,
method: 'GET',
timeout: 5000
}, (err, response, body) => {
body = JSON.parse(body);
if (err || !body) reject({errCode: -10, errInfo: err.toString()});
if (body.access_token) {
let accessToken = body.access_token;
// 獲取后將 accessToken 存儲(chǔ)在 redis 中欺旧,并設(shè)定過(guò)期時(shí)間,如果過(guò)期蛤签,則獲取不到 accessToken
setRedisDataEx(appId, accessToken, body.expires_in);
resolve(accessToken);
} else {
reject({errCode: body.errcode, errInfo: body.errmsg});
}
});
}
});
});
}
下面是獲取 URL Scheme 代碼實(shí)現(xiàn):
const getGenerateScheme = (req, res) => {
let { tenantCode, ...rest } = req.body;
// rest 為文檔中的剩余參數(shù)
let cfg = config[tenantCode]; // cfg中 存儲(chǔ)了小程序的 appId 及 appSecret
if (!cfg) return res.send(getErrInfo(errCode.ERR_PARAMETER_UNAVAILABLE, 'tenantCode'))
let { appId, appSecret } = cfg
getAccessToken(appId, appSecret).then((accessToken) => { // 獲取 accessToken
const params = {
...rest
}
request({
url: `https://api.weixin.qq.com/wxa/generatescheme?access_token=${accessToken}`,
method: 'POST',
timeout: 5000,
headers: {
'content-type': 'application/json',
},
body: JSON.stringify(params)
}, (err, response, body) => {
body = JSON.parse(body);
if (err || !body) return res.send({errCode: -10, errInfo: err.toString()});
if (body.openlink) {
// 獲取跳轉(zhuǎn)鏈接 openlink
let openlink = body.openlink;
return res.send({errCode: 0, result: openlink});
} else {
return res.send({errCode: body.errcode, errInfo: body.errmsg});
}
});
}).catch((err) => {
return res.send(err);
});
}
上述代碼中 rest
辞友,即為文檔中的參數(shù)。
調(diào)用 getGenerateScheme
接口后即可獲得 URL Scheme震肮,如:weixin://dl/business/?t=LcoXo1wSXIq
称龙。
iOS系統(tǒng)支持識(shí)別URL Scheme,可在短信等應(yīng)用場(chǎng)景中直接通過(guò)Scheme跳轉(zhuǎn)小程序戳晌。
Android系統(tǒng)不支持直接識(shí)別URL Scheme鲫尊,用戶無(wú)法通過(guò)Scheme正常打開(kāi)小程序,我們需要使用H5頁(yè)面中轉(zhuǎn)沦偎,再跳轉(zhuǎn)到Scheme實(shí)現(xiàn)打開(kāi)小程序疫向,跳轉(zhuǎn)代碼示例如下:
location.href = 'weixin://dl/business/?t=LcoXo1wSXIq
該跳轉(zhuǎn)方法可以在打開(kāi)H5時(shí)立即調(diào)用,也可以在用戶觸發(fā)事件后調(diào)用扛施。
2. 通過(guò)生成的二維碼圖片掃碼跳轉(zhuǎn)小程序
生成二維碼需要用到官方 api - wxacode.getUnlimited。
下面是獲取帶參小程序二維碼圖片代碼:
const getWxaCode = (req, res) => {
let { tenantCode, ...rest } = req.body;
// rest 為文檔中的剩余參數(shù)
let cfg = config[tenantCode];
if (!cfg) return res.send(getErrInfo(errCode.ERR_PARAMETER_UNAVAILABLE, 'tenantCode'))
let { appId, appSecret } = cfg; // cfg中 存儲(chǔ)了小程序的 appId 及 appSecret
getAccessToken(appId, appSecret).then((accessToken) => { // 獲取 accessToken
const params = {
...rest
}
request({
url: `https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=${accessToken}`,
method: 'POST',
timeout: 5000,
headers: {
'content-type': 'image/jpeg',
},
encoding: null,
body: JSON.stringify(params)
}, (err, response, body) => {
if (err || !body) return res.send({errCode: -10, errInfo: err.toString()});
if (body) {
const type = response.headers['content-type'];
const img = `data:${type};base64,${body.toString('base64')}`;
return res.send({errCode: 0, result: img});
}
});
}).catch((err) => {
return res.send(err);
});
}
這里返回的 body
是 圖片 Buffer 文件屹篓,Buffer是一個(gè)像Array的對(duì)象疙渣,但它主要用于操作字節(jié),也就是二進(jìn)制數(shù)據(jù)堆巧,它的元素為16進(jìn)制的兩位數(shù)妄荔,即0到255的數(shù)值。
request 發(fā)送請(qǐng)求的編碼格式 encoding谍肤,會(huì)默認(rèn)為 UTF-8啦租,而對(duì)于不能識(shí)別的byte串會(huì)解碼成?,通過(guò)將encoding設(shè)為null荒揣,也就不對(duì)原始數(shù)據(jù)編碼篷角,保持原始的二進(jìn)制圖片數(shù)據(jù),即可得到 Buffer 文件的正確格式系任。
獲取到 Buffer 文件后我又將其轉(zhuǎn)換成 base64 的格式恳蹲,以便前端直接使用。
至此這個(gè) h5 的功能基本完成點(diǎn)擊 鏈接 看看效果吧俩滥!如果如要通過(guò)短信發(fā)送打開(kāi)嘉蕾,那么將長(zhǎng)鏈接轉(zhuǎn)換成短鏈接通過(guò)短信發(fā)送出去即可。
3. 接收跳轉(zhuǎn)參數(shù)
通過(guò)接口獲取的鏈接及二維碼霜旧,在跳轉(zhuǎn)時(shí)會(huì)將其余參數(shù)轉(zhuǎn)換成頁(yè)面 ? 后面的部分错忱,形如 page='pages/index/index?foo=bar'
。我們可以在小程序的 App.onLaunch、App.onShow 和 Page.onLoad 的回調(diào)函數(shù)中獲取到以清。
本文首發(fā)于我的博客 mogii'blog 歡迎大家光臨~