開(kāi)通了云開(kāi)發(fā)的小程序可以使用Cloud.CloudID接口返回一個(gè) CloudID(開(kāi)放數(shù)據(jù) ID)特殊對(duì)象,將該對(duì)象傳至云函數(shù)就可以獲取其對(duì)應(yīng)的開(kāi)放數(shù)據(jù),比如獲取微信運(yùn)動(dòng)的步數(shù)、手機(jī)號(hào)等開(kāi)放數(shù)據(jù),而這個(gè)功能如果是使用非云開(kāi)發(fā)的方式除了需要處理登錄的問(wèn)題,還需要進(jìn)行加解密,十分繁瑣。
獲取微信運(yùn)動(dòng)步數(shù)的小程序接口為wx.getWeRunData,可以獲取用戶過(guò)去三十天微信運(yùn)動(dòng)步數(shù)。使用可開(kāi)發(fā)者工具新建一個(gè)頁(yè)面頁(yè)面比如openData,然后在openData.wxml里輸入一個(gè)button按鈕:
<button bindtap="getWeRunData">獲取微信步數(shù)</button>
然后再在openData.js里輸入以下代碼,我們用事件處理函數(shù)getWeRunData來(lái)調(diào)用wx.getWeRunData接口,并打印結(jié)果。
getWeRunData(){
wx.getWeRunData({
success: (result) => {
console.log(result)
},
})
}
編譯之后,點(diǎn)擊按鈕,我們可以在控制臺(tái)看到返回的res對(duì)象里有encryptedData包括敏感數(shù)據(jù)在內(nèi)的完整用戶信息的加密數(shù)據(jù)、iv加密算法的初始向量, cloudID敏感數(shù)據(jù)對(duì)應(yīng)的云 ID.
{errMsg: "getWeRunData:ok",
encryptedData: "ABeBwlCHs....6PvAax",
iv: "g8QPFXTLLD3N6Zn3YiuwEQ==",
cloudID: "30_jVhZr_Up-8_TV...kgP8yJ8ykN0I"}
這個(gè)cloudID只有在開(kāi)通了云開(kāi)發(fā)的小程序才會(huì)返回,我們可以將cloudID傳入云函數(shù),通過(guò)云調(diào)用就可以直接獲取開(kāi)放數(shù)據(jù)。
使用開(kāi)發(fā)者工具新建云函數(shù)比如opendata,再index.js里輸入以下代碼,并部署上線,在云函數(shù)端接收到的 event 將會(huì)包含對(duì)應(yīng)開(kāi)放數(shù)據(jù)的對(duì)象。
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV,
})
exports.main = async (event, context) => {
return event
}
我們?cè)賮?lái)在前面的事件處理函數(shù)getWeRunData里上傳經(jīng)過(guò)cloud.CloudID接口獲得的cloudID對(duì)象,然后調(diào)用opendata云函數(shù),并在success里打印返回來(lái)的對(duì)象,就可以看到包含微信運(yùn)動(dòng)步數(shù)的對(duì)象啦:
getWeRunData(){
wx.getWeRunData({
success: (result) => {
console.log(result.cloudID)
wx.cloud.callFunction({
name: 'opendata',
data: {
weRunData: wx.cloud.CloudID(result.cloudID),
},
success:(res)=>{
console.log(res.result.weRunData.cloudID)
console.log(res.result.weRunData.data.stepInfoList)
}
})
}
})
}
要獲取用戶的手機(jī)號(hào),需要將 button 組件 open-type 的值設(shè)置為 getPhoneNumber,當(dāng)用戶點(diǎn)擊并同意之后,可以通過(guò) bindgetphonenumber 事件回調(diào)獲取到微信服務(wù)器返回的加密數(shù)據(jù),如果開(kāi)通了云開(kāi)發(fā),就能在回調(diào)對(duì)象了獲取到cloudID。使用開(kāi)發(fā)者工具在openData.wxml里輸入如下代碼:
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
然后再在openData.js里輸入以下代碼,我們打印事件處理函數(shù)getPhoneNumber返回的結(jié)果。
getPhoneNumber (result) {
console.log("result內(nèi)容",result.detail)
},
同樣我們也會(huì)獲得一個(gè)類似于微信運(yùn)動(dòng)步數(shù)的返回結(jié)果
{errMsg: "getPhoneNumber:ok",
encryptedData: "Aw+W76TSvYAPS.....g==",
iv: "9wSepi6qx...=",
cloudID: "30_sSext5q.....qmLQ"}
我們?nèi)匀恢恍枰獙@取到cloudID經(jīng)過(guò)cloud.CloudID()接口處理返回的對(duì)象上傳并調(diào)用云函數(shù):
getPhoneNumber (result) {
wx.cloud.callFunction({
name: 'opendata',
data: {
getPhoneNumber: wx.cloud.CloudID(result.detail.cloudID),
},
success:(res)=>{
console.log("云函數(shù)返回的對(duì)象",res.result.getPhoneNumber)
}
})
},
在getPhoneNumber的data對(duì)象里的phoneNumber是用戶綁定的手機(jī)號(hào)(國(guó)外手機(jī)號(hào)會(huì)有區(qū)號(hào))、purePhoneNumber是沒(méi)有區(qū)號(hào)的手機(jī)號(hào)、countryCode區(qū)號(hào)。
要獲取微信群ID和群名稱,需要經(jīng)過(guò)一系列相對(duì)比較復(fù)雜的處理,需要經(jīng)過(guò)以下步驟,具體的代碼和開(kāi)發(fā)方式后面會(huì)具體介紹:
withShareTicket: true
,分享也必須分享到微信群里;shareTicket
,wx.getShareInfo
里就會(huì)得到微信群敏感數(shù)據(jù)對(duì)應(yīng)的cloudID,wx.cloud.CloudID(cloudID)
傳入到云函數(shù),云函數(shù)就可以返回微信群ID,也就是openGId
<open-data type="groupName" open-gid="{{openGId}}"></open-data>
來(lái)顯示群名
通過(guò)給 button 組件設(shè)置屬性open-type="share"
,可以在用戶點(diǎn)擊按鈕后觸發(fā)頁(yè)面的生命周期函數(shù)Page.onShareAppMessage
事件。首先我們使用開(kāi)發(fā)者工具新建一個(gè)頁(yè)面,比如share,然后再在share.wxml創(chuàng)建一個(gè)button組件,比如:
<button open-type="share">轉(zhuǎn)發(fā)</button>
要獲取群聊的名稱以及群的標(biāo)識(shí)openGId,需要帶shareTicket的轉(zhuǎn)發(fā)才可以,我們?cè)趕hare.js頁(yè)面生命周期函數(shù)onShareAppMessage
里輸入如下代碼,設(shè)置withShareTicket
為true:
onShareAppMessage: function (res) {
wx.updateShareMenu({
withShareTicket: true,
success(res) {
console.log(res)
},
fail(err) {
console.log(err)
}
})
if (res.from === 'button') {
console.log(res.target) //可以在這里將用戶點(diǎn)擊button的次數(shù)存儲(chǔ)到數(shù)據(jù)庫(kù),相當(dāng)于埋點(diǎn)
}
return {
title: '云開(kāi)發(fā)技術(shù)訓(xùn)練營(yíng)',
path: 'pages/share/share?openid=oUL-m5FuRmuVmxvbYOGuXbuEDsn8',
imageUrl:"cloud://xly-xrlur.786c-xly-xrlur-1300446086/share.png"http://支持云存儲(chǔ)的fileID
}
},
關(guān)于顯示右上角菜單的轉(zhuǎn)發(fā)按鈕可以使用
wx.showShareMenu
接口,而onShareAppMessage
除了可以監(jiān)聽(tīng)用戶點(diǎn)擊頁(yè)面內(nèi)的button,也可以監(jiān)聽(tīng)右上角菜單“轉(zhuǎn)發(fā)”按鈕的行為,無(wú)論是哪一種,都可以自定義菜單的title、path、imageUrl等,這里就不具體寫(xiě)代碼啦。
值得注意的是,只有轉(zhuǎn)發(fā)到微信群聊中,再通過(guò)微信群聊里的小程序卡片進(jìn)入到小程序才可以獲取到shareTickets返回值,單聊沒(méi)有shareTickets;shareTicket僅在當(dāng)前小程序生命周期內(nèi)有效。但是在開(kāi)發(fā)時(shí),怎么把小程序轉(zhuǎn)發(fā)到微信群里面去呢?開(kāi)發(fā)者工具提供了帶shareTickets的調(diào)試方法。
在開(kāi)發(fā)者工具的模擬器里點(diǎn)擊"轉(zhuǎn)發(fā)"button,就會(huì)出現(xiàn)一個(gè)測(cè)試模擬群列表,我們可以將小程序轉(zhuǎn)發(fā)到一個(gè)群聊里面去,比如測(cè)試模擬群4
。調(diào)試時(shí),我們要添加自定義編譯模式,在進(jìn)入場(chǎng)景里選擇1044: 帶 shareTicket 的小程序消息卡片
,選擇進(jìn)入的群為你轉(zhuǎn)發(fā)的群,具體可以參考如下圖:
獲取shareTicket,我們可以使用wx.getLaunchOptionsSync()
來(lái)獲取小程序啟動(dòng)時(shí)的參數(shù),這個(gè)參數(shù)與App.onLaunch 的回調(diào)參數(shù)一致,而shareTicket就在這個(gè)參數(shù)對(duì)象里。我們可以在share.js的onLoad生命周期函數(shù)里來(lái)獲取它:
onLoad:function (options) {
const res = wx.getLaunchOptionsSync()
console.log('小程序啟動(dòng)時(shí)的參數(shù)',res)
const {shareTicket} = res
console.log('shareTicket的值',shareTicket)
},
如果你直接使用普通編譯(不使用上面的調(diào)試方法),是獲取不到shareTicket的,shareTicket的值會(huì)為
undefined
,同時(shí)如果小程序直接加載(而不是通過(guò)點(diǎn)擊群聊里分享的小程序卡片進(jìn)入),shareTicket的值也是undefined
。
當(dāng)我們獲取到shareTicket之后,就可以調(diào)用wx.getShareInfo
接口來(lái)獲取到關(guān)于轉(zhuǎn)發(fā)的信息,尤其是cloudID。然后我們可以把獲取到的CloudID,傳入到云函數(shù),比如share云函數(shù)。
使用開(kāi)發(fā)者工具新建一個(gè)share云函數(shù),在index.js里輸入以下代碼(這個(gè)其實(shí)就是返回event對(duì)象,如此簡(jiǎn)單的云函數(shù)我們可以和其他云函數(shù)合并到一起使用,比如獲取openid等):
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV,
})
const TcbRouter = require('tcb-router');
exports.main = async (event, context) => {
return event
}
然后再在小程序端share.js的生命周期函數(shù)里繼續(xù)寫(xiě)如下代碼,先判斷shareTicket是否為空(也就是判斷是否是通過(guò)微信群聊小程序卡片進(jìn)入的),然后調(diào)用wx.getShareInfo來(lái)獲取CloudID,再將CloudID傳入到wx.cloud.CloudID()
接口,并將該對(duì)象傳至云函數(shù)share就可以返回這個(gè)CloudID對(duì)應(yīng)的開(kāi)放數(shù)據(jù)了(這里的開(kāi)放數(shù)據(jù)主要是openGId)。
onLoad:function (options) {
const that = this
const res = await wx.getLaunchOptionsSync()
const {shareTicket} = res
if(shareTicket!=null){ //當(dāng)shareTicket不為空時(shí),調(diào)用wx.getShareInfo來(lái)獲取CloudID
wx.getShareInfo({
shareTicket:shareTicket,
success:function (res) {
const cloudID = res.cloudID
wx.cloud.callFunction({
name: 'share',
data: {
groupData: wx.cloud.CloudID(cloudID)
},
success: function (res) {
that.setData({
openGId:res.result.groupData.data.openGId
})
}
})
}
})
}
},
openGId為當(dāng)前群的唯一標(biāo)識(shí),也就是每個(gè)微信群都有唯一且不變的這樣一個(gè)ID,可以用于區(qū)分不同的微信群。我們可以把微信群內(nèi)點(diǎn)擊了小程序分享卡片的群成員的用戶信息與這個(gè)openGId相關(guān)聯(lián),這樣就可以弄群排行榜等一些基于微信群的開(kāi)發(fā)。
不過(guò)我們只能獲取微信群的群ID,是不能獲取微信群的名稱的,但是可以通過(guò)開(kāi)放能力來(lái)顯示微信群的名稱,我們只需要把獲取到的openGId字符串傳入到open-gid
就可以了。
<open-data type="groupName" open-gid="{{openGId}}"></open-data>
可能你在調(diào)試的時(shí)候會(huì)出現(xiàn),即使你把openGId寫(xiě)入到上面的組件,依然不會(huì)顯示群名,或者使用真機(jī)調(diào)試也無(wú)法顯示,這是因?yàn)闇y(cè)試群或者新建的群,可能會(huì)無(wú)效。
動(dòng)態(tài)消息發(fā)出去之后,開(kāi)發(fā)者可以通過(guò)后臺(tái)接口修改部分消息內(nèi)容,動(dòng)態(tài)消息也有對(duì)應(yīng)的提醒按鈕,用戶點(diǎn)擊提醒按鈕可以訂閱提醒,開(kāi)發(fā)者可以通過(guò)后臺(tái)修改消息狀態(tài)并推送一次提醒消息給訂閱了提醒的用戶。效果如下所示,這種特別適合我們做搶購(gòu)、拼團(tuán)等運(yùn)營(yíng)活動(dòng):
要讓轉(zhuǎn)發(fā)的小程序卡片里有動(dòng)態(tài)消息,首先需要使用云調(diào)用updatableMessage.createActivityId
接口來(lái)創(chuàng)建activityId
,然后將activityId和templateInfo傳入到wx.updateShareMenu
,而要更新動(dòng)態(tài)消息則需要使用到updatableMessage.setUpdatableMsg
的接口。我們可以把創(chuàng)建動(dòng)態(tài)消息和更新動(dòng)態(tài)消息的云函數(shù)使用tcb-router整合到一個(gè)云函數(shù)里面。
使用開(kāi)發(fā)者工具新建一個(gè)云函數(shù),云函數(shù)的名稱為activity,然后在package.json增加tcb-router最新版latest的依賴并用npm install安裝:
"dependencies": {
"wx-server-sdk":"latest",
"tcb-router": "latest"
}
以及在config.json里添加云調(diào)用的權(quán)限,用于生成ActivityId以及修改被分享的動(dòng)態(tài)消息:
{
"permissions": {
"openapi": [
"updatableMessage.createActivityId",
"updatableMessage.setUpdatableMsg"
]
}
}
然后再在index.js里輸入以下代碼,使用createActivityId
生成ActivityId并返回:
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV,
})
const TcbRouter = require('tcb-router');
exports.main = async (event, context) => {
const app = new TcbRouter({event})
app.use(async (ctx, next) => {
ctx.data = {}
await next();
});
app.router('getActivityId',async (ctx, next)=>{
const result = await cloud.openapi.updatableMessage.createActivityId()
ctx.data.activityID = result
ctx.body = {"activityID":ctx.data.activityID}
})
//后面我們會(huì)介紹如何更新動(dòng)態(tài)消息,updatableMsg的router可以添加在這里
return app.serve();
}
和前面一樣,我們可以通過(guò)調(diào)用wx.updateShareMenu
接口,傳入isUpdatableMessage: true
,以及 templateInfo
、activityId
等參數(shù):
async onShareAppMessage(res) {
const activityId = (await wx.cloud.callFunction({
name: 'activity',
data: {
$url: "getActivityId",
}
})).result.activityID.activityId
wx.updateShareMenu({
withShareTicket: true,
isUpdatableMessage: true,
activityId: activityId,
templateInfo: {
parameterList: [{
name: 'member_count',
value: '4' //這里的數(shù)據(jù)可以來(lái)自數(shù)據(jù)庫(kù)
}, {
name: 'room_limit',
value: '30' //這里的數(shù)據(jù)可以來(lái)自數(shù)據(jù)庫(kù)
}]
}
})
return {
title: 'HackWeek技術(shù)訓(xùn)練營(yíng)',
path: 'pages/share/share?openid=oUL-m5FuRmuVmxvbYOGuXbuEDsn8',
imageUrl:"cloud://xly-xrlur.786c-xly-xrlur-1300446086/1572315793633-633.png"
}
},
動(dòng)態(tài)消息發(fā)出去之后,我們可以通過(guò)這個(gè)activityId來(lái)追蹤這個(gè)動(dòng)態(tài)消息,當(dāng)用戶進(jìn)入分享的小程序,報(bào)名參與了這個(gè)活動(dòng)時(shí),比如活動(dòng)為拼團(tuán),30人這個(gè)團(tuán)購(gòu)項(xiàng)目就成功啦,現(xiàn)在已經(jīng)有4個(gè)人參與了(可以從數(shù)據(jù)庫(kù)獲得),當(dāng)有新的用戶付費(fèi)參與這個(gè)拼團(tuán)時(shí),我們可以在這個(gè)用戶付費(fèi)的回調(diào)函數(shù)里調(diào)用updatableMessage.setUpdatableMsg
這個(gè)接口來(lái)修改動(dòng)態(tài)消息。比如:
wx.cloud.callFunction({
name: 'activity',
data: {
$url: "updatableMsg",
activityId: activityId, //activityId建議由前端傳入,獲取的方法如上
}
})
我們繼續(xù)在activity云函數(shù)里添加一個(gè)updatableMsg的router即可
const {activityID} = event
app.router('updatableMsg',async (ctx, next)=>{
//我們可以用從數(shù)據(jù)庫(kù)拉取現(xiàn)在拼團(tuán)的人數(shù),以及滿團(tuán)的人數(shù),從而確定targetState的狀態(tài)
const result = await cloud.openapi.updatableMessage.setUpdatableMsg({
activityID:activityID,
targetState:0,
templateInfo: {
parameterList: [{
name: 'member_count',
value: '5' //從數(shù)據(jù)庫(kù)拉取
}, {
name: 'room_limit',
value: '30' //從數(shù)據(jù)庫(kù)拉取
}]
}
})
})
更多建議: