微信小遊戲開發小記

evont發表於2019-03-04

前言

最近由於業務原因開始接觸微信小遊戲的開發,踩了一些坑。下面開始寫一下關於遇到的一些問題以及解決方法的總結,


一、開放資料域繪製圖片問題

在DOM 環境中使用Canvans 繪製圖片我們一般是使用如下的方式:

var img = document.getElementById(`img`);
ctx.drawImage(img, 10, 10);
複製程式碼

drawImage 的第一個引數可以用HTMLImageElement,HTMLCanvasElement或者HTMLVideoElement作為引數,但是在開放資料域下不存在DOM 操作,我們需要使用如下的方式去繪製圖片;

let pic = wx.createImage(); 
pic.src = url;
// 如果是網路圖片,則需載入完成後繪製
// pic.onload = () => {
  ctx.drawImage(pic, 10, 10);
// }
複製程式碼

二、開放資料域效能問題

由於開放域不能向主域傳送資料,傳統上的思路是主域需要重新整理ShareCanvas並繪製到主屏上,但這樣就會導致效能上的開銷過大,僅僅用來繪製排行榜的話是十分不明智的做法,Egret 有一個髒渲染的概念,如果頁面沒有“髒”,即是沒有變化的元素,則不會重新渲染Canvans ,從而減少了重繪次數,優化了渲染效能,具體的實現思路如下:

let requestAnimationFrameID; // 記錄requestAnimationFrame的ID
let isDirty = true; // 標誌是否為髒
/**
 * 每次渲染時,判斷是否“髒”了,若是,則重新渲染
 */
function render() {
  if (isDirty) {
    context.setTransform(1, 0, 0, 1, 0, 0); // 座標系復位
    context.clearRect(0, 0, sharedCanvas.width, sharedCanvas.height); // 清除 Canvans 畫布
    drawElements();  //繪製排行榜,或者其他元素
    isDirty = false;
  }
  requestAnimationFrame(render);
}
複製程式碼

三、UI 同步問題

微信小遊戲有一個十分坑的地方:4M的限制。當我們需要繪製排行榜但又需要讓ui 與主域一致的時候就會出現很尷尬的狀況:如果將ui程式碼在開放域和主域都放一份,這會讓體積大大增加,如果使用的是遊戲框架,同步繪製程式碼的難度也會增加。

那麼,我們可以怎麼解決這個問題呢?

我的實現思路是,開放域的存在目前也只是獲取好友或群共玩好友的關係資料,對於大多數遊戲,只在繪製排行榜傷上有用。因此,排行榜可以僅繪製關係資料,即,只繪製頭像、排行這一類資料,繪製時對尺寸進行比例縮放,而背景則在主域進行繪製,然後再把排行榜墊在背景上。這種方法僅適用於只繪製不那麼複雜的排行榜的需求,對於需要繪製更復雜的介面的功能來說還是雞肋的,尚未見到或想出一個更好的方法。


四、客服訊息回回復圖片功能

不少的小遊戲都有客服功能的需求(emmm,比如回覆公眾號圖片引導關注),但是微信的客服系統是不支援回覆圖片的,這個時候就需要自己接入客服功能。微信的傳送圖片資訊的body 格式如下:

  "touser":"OPENID",
    "msgtype":"image",
    "image":
    {
      "media_id":"MEDIA_ID"
    }
}
複製程式碼

具體實現步驟如下:

  1. 新增臨時素材
    當我們想向使用者傳送一張圖片時,並不能隨心所欲地使用任意圖片地址,如上json所示,微信只提供一個mediaid,這個mediaid是我們呼叫新增臨時素材介面提交到微信伺服器上之後,返回的一個圖片標識,介面如下:
https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
複製程式碼

引數說明:
access_token: 呼叫介面憑證
type:媒體型別,固定填寫為 image
media:form-data中媒體檔案標識,有filename、filelength、content-type等資訊

然後我們需要實現一個可以上傳圖片的頁面,node端接收併傳送到微信伺服器上,如果成功獲取到mediaid之後我們就可以存放在資料庫或快取上對應appid 的地方以便後續傳送圖片使用

let token = wechat.getMiniAccessToken(); // 自己實現獲取當前小程式/小遊戲的access token的函式,appid 要對應,否則mediaid是不會回覆到使用者的
const options = {
  url: `https://api.weixin.qq.com/cgi-bin/media/upload?access_token=${token.access_token}&type=image`,
  formData: body.fields,
};

request.post(options, (err, res, data) => {
  // 將回傳的物件中的mediaid 對應appid存放
})
複製程式碼
  1. 接收使用者發來的訊息

這一步我們需要先配置好伺服器,參考微信伺服器接入指引這篇文章,需要注意的是,只有在驗證url是否合法的情況下,才會帶有echostr 引數,以此我們可以判斷當前請求是否為伺服器驗證,如果帶有echostr 引數,我們只需要在確認簽名無誤之後,把echostr 原樣返回就可以了。如果沒有echostr引數,則是微信轉發過來的使用者發來的訊息,此時我們就要進入下一步去傳送圖片了。

  const {
    signature, timestamp, nonce, echostr,
  } = this.query;
  const { body } = this.request;
  if (echostr) { // 用於配置客服伺服器使用
    const result = wechat.checkSign(timestamp, nonce, signature); // 校驗簽名是否正確
    this.body = result ? echostr : `err signature`; 
  } else {
    wechat.sengMsg(body); // 進入下一步傳送圖片
    this.body = `success`;
  }
複製程式碼
  1. 向使用者傳送圖片

上一步中我們接收到微信轉發過來的使用者訊息,具體格式可以參考微信客服訊息 這篇文章,我們可以獲取到傳送過來使用者,只需要請求微信的介面,就可以把訊息推送給該使用者了。

  const mediaId = `需要傳送的圖片的mediaid`;
  let token = wechat.getMiniAccessToken(); // 當前小程式/小遊戲的access token
  const options = {
    url: `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${token.access_token}`,
    body: {
      touser: data.FromUserName, // 需要傳送的使用者
      msgtype: `image`,
      image: {
        media_id: mediaId,
      },
    },
    json: true,
  };
  request.post(options, (err, res, data) => {
    // 傳送之後的處理函式
  });
複製程式碼

結語

筆者對於微信小遊戲也只能算是剛入門,以上內容也只是幾天開發完之後的一些經驗,不算成熟,如有錯誤,希望指正,互相成長,謝謝。

以上內容歸本人EvontGoh 所有,如需轉載,請註明出處;

相關文章