云開發(fā) CloudID與動態(tài)消息

2020-07-22 15:32 更新

開通了云開發(fā)的小程序可以使用Cloud.CloudID接口返回一個 CloudID(開放數(shù)據(jù) ID)特殊對象,將該對象傳至云函數(shù)就可以獲取其對應(yīng)的開放數(shù)據(jù),比如獲取微信運(yùn)動的步數(shù)、手機(jī)號等開放數(shù)據(jù),而這個功能如果是使用非云開發(fā)的方式除了需要處理登錄的問題,還需要進(jìn)行加解密,十分繁瑣。

一、獲取微信步數(shù)

獲取微信運(yùn)動步數(shù)的小程序接口為wx.getWeRunData,可以獲取用戶過去三十天微信運(yùn)動步數(shù)。使用可開發(fā)者工具新建一個頁面頁面比如openData,然后在openData.wxml里輸入一個button按鈕:

<button bindtap="getWeRunData">獲取微信步數(shù)</button>

然后再在openData.js里輸入以下代碼,我們用事件處理函數(shù)getWeRunData來調(diào)用wx.getWeRunData接口,并打印結(jié)果。

getWeRunData(){
  wx.getWeRunData({
    success: (result) => {
      console.log(result)
    },
  })
}

編譯之后,點(diǎn)擊按鈕,我們可以在控制臺看到返回的res對象里有encryptedData包括敏感數(shù)據(jù)在內(nèi)的完整用戶信息的加密數(shù)據(jù)、iv加密算法的初始向量, cloudID敏感數(shù)據(jù)對應(yīng)的云 ID.

{errMsg: "getWeRunData:ok", 
encryptedData: "ABeBwlCHs....6PvAax", 
iv: "g8QPFXTLLD3N6Zn3YiuwEQ==", 
cloudID: "30_jVhZr_Up-8_TV...kgP8yJ8ykN0I"}

這個cloudID只有在開通了云開發(fā)的小程序才會返回,我們可以將cloudID傳入云函數(shù),通過云調(diào)用就可以直接獲取開放數(shù)據(jù)。

使用開發(fā)者工具新建云函數(shù)比如opendata,再index.js里輸入以下代碼,并部署上線,在云函數(shù)端接收到的 event 將會包含對應(yīng)開放數(shù)據(jù)的對象。

const cloud = require('wx-server-sdk')
cloud.init({
    env: cloud.DYNAMIC_CURRENT_ENV,
})
exports.main = async (event, context) => {
    return event
}

我們再來在前面的事件處理函數(shù)getWeRunData里上傳經(jīng)過cloud.CloudID接口獲得的cloudID對象,然后調(diào)用opendata云函數(shù),并在success里打印返回來的對象,就可以看到包含微信運(yùn)動步數(shù)的對象啦:

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ī)號

要獲取用戶的手機(jī)號,需要將 button 組件 open-type 的值設(shè)置為 getPhoneNumber,當(dāng)用戶點(diǎn)擊并同意之后,可以通過 bindgetphonenumber 事件回調(diào)獲取到微信服務(wù)器返回的加密數(shù)據(jù),如果開通了云開發(fā),就能在回調(diào)對象了獲取到cloudID。使用開發(fā)者工具在openData.wxml里輸入如下代碼:

<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>

然后再在openData.js里輸入以下代碼,我們打印事件處理函數(shù)getPhoneNumber返回的結(jié)果。

  getPhoneNumber (result) {
    console.log("result內(nèi)容",result.detail)
  },

同樣我們也會獲得一個類似于微信運(yùn)動步數(shù)的返回結(jié)果

{errMsg: "getPhoneNumber:ok", 
encryptedData: "Aw+W76TSvYAPS.....g==", 
iv: "9wSepi6qx...=", 
cloudID: "30_sSext5q.....qmLQ"}

我們?nèi)匀恢恍枰獙@取到cloudID經(jīng)過cloud.CloudID()接口處理返回的對象上傳并調(diào)用云函數(shù):

getPhoneNumber (result) {
  wx.cloud.callFunction({
    name: 'opendata',
    data: {
      getPhoneNumber: wx.cloud.CloudID(result.detail.cloudID), 
    },
    success:(res)=>{
      console.log("云函數(shù)返回的對象",res.result.getPhoneNumber)
    }
  })
},

在getPhoneNumber的data對象里的phoneNumber是用戶綁定的手機(jī)號(國外手機(jī)號會有區(qū)號)、purePhoneNumber是沒有區(qū)號的手機(jī)號、countryCode區(qū)號。

三、獲取微信群ID和群名稱

要獲取微信群ID和群名稱,需要經(jīng)過一系列相對比較復(fù)雜的處理,需要經(jīng)過以下步驟,具體的代碼和開發(fā)方式后面會具體介紹:

  • 首先需要小程序的分享里的withShareTicket: true,分享也必須分享到微信群里;

  • 點(diǎn)擊微信群里的小程序卡片,才能獲取到shareTicket,

  • 然后將shareTicket傳入到wx.getShareInfo里就會得到微信群敏感數(shù)據(jù)對應(yīng)的cloudID,

  • 然后我們需要將cloudID通過wx.cloud.CloudID(cloudID)傳入到云函數(shù),云函數(shù)就可以返回微信群ID,也就是openGId

  • 最后我們需要再通過<open-data type="groupName" open-gid="{{openGId}}"></open-data>來顯示群名

1、創(chuàng)建一個轉(zhuǎn)發(fā)分享

通過給 button 組件設(shè)置屬性open-type="share",可以在用戶點(diǎn)擊按鈕后觸發(fā)頁面的生命周期函數(shù)Page.onShareAppMessage事件。首先我們使用開發(fā)者工具新建一個頁面,比如share,然后再在share.wxml創(chuàng)建一個button組件,比如:

<button open-type="share">轉(zhuǎn)發(fā)</button>

要獲取群聊的名稱以及群的標(biāo)識openGId,需要帶shareTicket的轉(zhuǎn)發(fā)才可以,我們在share.js頁面生命周期函數(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ù)存儲到數(shù)據(jù)庫,相當(dāng)于埋點(diǎn)
  }
  return {
    title: '云開發(fā)技術(shù)訓(xùn)練營',
    path: 'pages/share/share?openid=oUL-m5FuRmuVmxvbYOGuXbuEDsn8',
    imageUrl:"cloud://xly-xrlur.786c-xly-xrlur-1300446086/share.png"http://支持云存儲的fileID
  }
},

關(guān)于顯示右上角菜單的轉(zhuǎn)發(fā)按鈕可以使用wx.showShareMenu接口,而onShareAppMessage除了可以監(jiān)聽用戶點(diǎn)擊頁面內(nèi)的button,也可以監(jiān)聽右上角菜單“轉(zhuǎn)發(fā)”按鈕的行為,無論是哪一種,都可以自定義菜單的title、path、imageUrl等,這里就不具體寫代碼啦。

2、獲取shareTickets

值得注意的是,只有轉(zhuǎn)發(fā)到微信群聊中,再通過微信群聊里的小程序卡片進(jìn)入到小程序才可以獲取到shareTickets返回值,單聊沒有shareTickets;shareTicket僅在當(dāng)前小程序生命周期內(nèi)有效。但是在開發(fā)時,怎么把小程序轉(zhuǎn)發(fā)到微信群里面去呢?開發(fā)者工具提供了帶shareTickets的調(diào)試方法。

在開發(fā)者工具的模擬器里點(diǎn)擊"轉(zhuǎn)發(fā)"button,就會出現(xiàn)一個測試模擬群列表,我們可以將小程序轉(zhuǎn)發(fā)到一個群聊里面去,比如測試模擬群4。調(diào)試時,我們要添加自定義編譯模式,在進(jìn)入場景里選擇1044: 帶 shareTicket 的小程序消息卡片,選擇進(jìn)入的群為你轉(zhuǎn)發(fā)的群,具體可以參考如下圖:

獲取shareTicket,我們可以使用wx.getLaunchOptionsSync()來獲取小程序啟動時的參數(shù),這個參數(shù)與App.onLaunch 的回調(diào)參數(shù)一致,而shareTicket就在這個參數(shù)對象里。我們可以在share.js的onLoad生命周期函數(shù)里來獲取它:

onLoad:function (options) {
  const res = wx.getLaunchOptionsSync()
  console.log('小程序啟動時的參數(shù)',res)
  const {shareTicket} = res
  console.log('shareTicket的值',shareTicket)
},

如果你直接使用普通編譯(不使用上面的調(diào)試方法),是獲取不到shareTicket的,shareTicket的值會為undefined,同時如果小程序直接加載(而不是通過點(diǎn)擊群聊里分享的小程序卡片進(jìn)入),shareTicket的值也是undefined

3、獲取cloudID并獲取群IDopenGId

當(dāng)我們獲取到shareTicket之后,就可以調(diào)用wx.getShareInfo接口來獲取到關(guān)于轉(zhuǎn)發(fā)的信息,尤其是cloudID。然后我們可以把獲取到的CloudID,傳入到云函數(shù),比如share云函數(shù)。

使用開發(fā)者工具新建一個share云函數(shù),在index.js里輸入以下代碼(這個其實(shí)就是返回event對象,如此簡單的云函數(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ù)寫如下代碼,先判斷shareTicket是否為空(也就是判斷是否是通過微信群聊小程序卡片進(jìn)入的),然后調(diào)用wx.getShareInfo來獲取CloudID,再將CloudID傳入到wx.cloud.CloudID()接口,并將該對象傳至云函數(shù)share就可以返回這個CloudID對應(yīng)的開放數(shù)據(jù)了(這里的開放數(shù)據(jù)主要是openGId)。

onLoad:function (options) {
  const that = this
  const res = await wx.getLaunchOptionsSync()
  const {shareTicket} = res
  if(shareTicket!=null){ //當(dāng)shareTicket不為空時,調(diào)用wx.getShareInfo來獲取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
            })
          }
        })
      }
    })
  }
},

4、顯示群的名稱

openGId為當(dāng)前群的唯一標(biāo)識,也就是每個微信群都有唯一且不變的這樣一個ID,可以用于區(qū)分不同的微信群。我們可以把微信群內(nèi)點(diǎn)擊了小程序分享卡片的群成員的用戶信息與這個openGId相關(guān)聯(lián),這樣就可以弄群排行榜等一些基于微信群的開發(fā)。

不過我們只能獲取微信群的群ID,是不能獲取微信群的名稱的,但是可以通過開放能力來顯示微信群的名稱,我們只需要把獲取到的openGId字符串傳入到open-gid就可以了。

<open-data type="groupName" open-gid="{{openGId}}"></open-data>

可能你在調(diào)試的時候會出現(xiàn),即使你把openGId寫入到上面的組件,依然不會顯示群名,或者使用真機(jī)調(diào)試也無法顯示,這是因為測試群或者新建的群,可能會無效。

四、動態(tài)消息

動態(tài)消息發(fā)出去之后,開發(fā)者可以通過后臺接口修改部分消息內(nèi)容,動態(tài)消息也有對應(yīng)的提醒按鈕,用戶點(diǎn)擊提醒按鈕可以訂閱提醒,開發(fā)者可以通過后臺修改消息狀態(tài)并推送一次提醒消息給訂閱了提醒的用戶。效果如下所示,這種特別適合我們做搶購、拼團(tuán)等運(yùn)營活動:

要讓轉(zhuǎn)發(fā)的小程序卡片里有動態(tài)消息,首先需要使用云調(diào)用updatableMessage.createActivityId接口來創(chuàng)建activityId,然后將activityId和templateInfo傳入到wx.updateShareMenu,而要更新動態(tài)消息則需要使用到updatableMessage.setUpdatableMsg的接口。我們可以把創(chuàng)建動態(tài)消息和更新動態(tài)消息的云函數(shù)使用tcb-router整合到一個云函數(shù)里面。

1、創(chuàng)建 activityId

使用開發(fā)者工具新建一個云函數(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以及修改被分享的動態(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}
  })
  //后面我們會介紹如何更新動態(tài)消息,updatableMsg的router可以添加在這里
  return app.serve();
}

2、在轉(zhuǎn)發(fā)之前聲明消息類型為動態(tài)消息

和前面一樣,我們可以通過調(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ù)可以來自數(shù)據(jù)庫
      }, {
        name: 'room_limit',
        value: '30' //這里的數(shù)據(jù)可以來自數(shù)據(jù)庫
      }]
    }
  })
  return {
    title: 'HackWeek技術(shù)訓(xùn)練營',
    path: 'pages/share/share?openid=oUL-m5FuRmuVmxvbYOGuXbuEDsn8',
    imageUrl:"cloud://xly-xrlur.786c-xly-xrlur-1300446086/1572315793633-633.png"
  }
},

3、修改動態(tài)消息內(nèi)容

動態(tài)消息發(fā)出去之后,我們可以通過這個activityId來追蹤這個動態(tài)消息,當(dāng)用戶進(jìn)入分享的小程序,報名參與了這個活動時,比如活動為拼團(tuán),30人這個團(tuán)購項目就成功啦,現(xiàn)在已經(jīng)有4個人參與了(可以從數(shù)據(jù)庫獲得),當(dāng)有新的用戶付費(fèi)參與這個拼團(tuán)時,我們可以在這個用戶付費(fèi)的回調(diào)函數(shù)里調(diào)用updatableMessage.setUpdatableMsg這個接口來修改動態(tài)消息。比如:

wx.cloud.callFunction({
  name: 'activity',
  data: {
    $url: "updatableMsg",
    activityId: activityId, //activityId建議由前端傳入,獲取的方法如上
  }
})

我們繼續(xù)在activity云函數(shù)里添加一個updatableMsg的router即可

const {activityID} = event
app.router('updatableMsg',async (ctx, next)=>{
  //我們可以用從數(shù)據(jù)庫拉取現(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ù)庫拉取
      }, {
        name: 'room_limit',
        value: '30' //從數(shù)據(jù)庫拉取
      }]
    }
  })
})

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號