記錄微信小程序的坑

----------------更新--------------

2018年10月10日官網3個接口廢棄的通知:

一、分享監聽接口
分享消息給好友時,開發者將沒法從callback獲知用戶是否分享完成,也沒法在分享後當即得到羣ID。請參考調整指引html

二、getUserInfo接口
用戶須要點擊組件後,才能夠觸發登陸受權彈窗、受權本身的暱稱頭像等數據。請參考調整指引前端

三、openSetting接口
用戶須要點擊行爲後,才能夠跳轉打開設置頁,管理受權信息。請參考調整指引node

1.不一樣版本號是否可使用某方法/屬性

官方文檔上提到了幾種檢測方法,可是測試後發現有些沒有用
1)wx.canIUse()對一些api沒有用
2)if (wx.apiXX) { wx.apiXX(); }也不徹底有用
因此,最後經過直接比較當前版本號和目標版本號來實現兼容。json

/**
 * 比較兩個版本號的大小,用於兼容小程序不一樣版本的api時比較版本號(v1 > v2則返回1)
 * @param {*} v1
 * @param {*} v2
 */
export function compareVersion(v1, v2) {
  v1 = v1.split('.')
  v2 = v2.split('.')
  var len = Math.max(v1.length, v2.length)

  while (v1.length < len) {
    v1.push('0')
  }
  while (v2.length < len) {
    v2.push('0')
  }

  for (var i = 0; i < len; i++) {
    var num1 = parseInt(v1[i])
    var num2 = parseInt(v2[i])

    if (num1 > num2) {
      return 1
    } else if (num1 < num2) {
      return -1
    }
  }

  return 0
}

const  SDKVersion  =  wx.getSystemInfoSync().SDKVersion; // 獲取版本
if(T.compareVersion(SDKVersion, '2.0.7')>=0) { ... }

2.小程序間的跳轉

小程序跳轉只能實現 同一公衆號下關聯 的小程序跳轉
一個公衆號可關聯10個同主體的小程序,3個不一樣主體的小程序。
一個小程序可關聯3個公衆號。
p.s. 因此想跳轉像蘇寧小程序,只能把咱們小程序關聯到他們小程序的公衆號下)canvas

(1)使用navigator組件(僅用於微信2.0.7以上版本)小程序

<navigator target="miniProgram"  app-id="{{changeNewAppid}}"  path="{{changeNewUrl}}"  version="release"  @tap="goMiniprogram">
跳轉mp
</navigator>

(2)使用navigateToMiniProgram來兼容微信2.0.7如下(但即將廢棄) >=1.3.0微信小程序

goMiniprogram() {
    const  SDKVersion  =  wx.getSystemInfoSync().SDKVersion; // 獲取版本
    if(T.compareVersion(SDKVersion, '2.0.7')>=0) {
        wx.navigateToMiniProgram({
            appId:  this.changeNewAppid,
            path:  this.changeNewUrl,
            envVersion:  'release',
            success(res) {
                console.log('打開mp成功')
            }
        })
    }
}

調試注意:
開發者工具上不會顯示跳轉,但咱們能夠從回調函數裏log打印信息,只有真機調試才能夠跳轉api

3.小程序所屬的公衆號入口及其推送文章等入口進入小程序的url配置

格式:pages/list?source=wxmpcz01 (不要appid,也不要pages前加/緩存

4.保存圖片功能(用途之一是分享朋友圈)

思路:
1.小程序不能分享到朋友圈,只能經過保存圖片的形式分享。
2.若是保存靜態圖片,能夠直接調接口就行,可是需求是動態的圖片(獲取用戶的頭像),因此須要用canvas畫圖,而後保存成2倍/3倍圖微信

優化的問題:
1、文字有用特殊字體,可是字體文件都比較大。因此須要用fontmin抽取出所需字的字體文件,最後上線頁面從原來的3.7MB變成29KB字體woff/eot/ttf文件。

  1. 以前產品想要文案不寫死,三種成功頁各自有隨機的文案,這個在想怎麼優化更好。由於寫死的文案能夠直接抽出來。隨機文案要麼就是一次性把文案抽出來但字體文件大小會增長;要麼就是node寫個進程模擬cmd去跑fontmin實時壓縮字體的命令,但這種會更慢一些,並且小程序不必定支持這種寫法。(通常的PC端網頁是支持的)
  2. 小程序中canvas不支持使用自定義字體。因此保存功能須要使用圖片替代文字。
  3. 保存圖片由於用的canvas,而後canvas每一層沒法設置優先級,只能一層層疊上去,因此一些圖片/資源異步加載的順序比較重要,若是加載順序不作控制則可能將其餘內容物覆蓋。目前用的是await/aync + Promise.all()來實現

2、爲了使保存的帶有二維碼的圖片更加清晰,保存圖片須要使用upng轉換成base64格式的。

5.canvas畫圖

1.canvas的clip()裁剪方法,只對第一次裁剪的圖有效,後面裁剪都無效。
解決方案:製做一張和頭像圖片同樣大的中間有個n個圓形鏤空(中間透明)的圖片繪製在頭像上,在視覺上給頭像作出圓形的效果。
2.不能給文字設置字體,因此需求須要特殊字體時用的圖片。
3.保存canvas爲圖片時,ctx.draw()須要加個定時器,晚些執行canvasToTempFilePath().不然保存下來的是空白圖片。

ctx.draw(true, setTimeout(function() { // 延遲一下
    wx.canvasToTempFilePath({
        x: 0,
        y: 0,
        width: 2079,
        height: 2181,
        destWidth: 2079,
        destHeight: 2181,
        canvasId: 'myCanvas',
        success: function(res) {
            self.data.savedImgUrl = res.tempFilePath;
            self.saveImageToPhoto();
        }
    });
}, 400));
// 保存圖片到相冊
saveImageToPhoto() {
    const that = this;
    if (this.data.savedImgUrl !== '') {
        wx.saveImageToPhotosAlbum({
            filePath: this.data.savedImgUrl,
            success: function() {
                that.imgSaveLoading = false;
                that.$apply();
                wx.showModal({
                    title: '保存圖片成功',
                    content: 'xxxx',
                    showCancel: false
                });
            },
            fail: function(res) {
                console.log(res);
                that.imgSaveLoading = false;
                that.$apply();
                if (res.errMsg === 'saveImageToPhotosAlbum:fail cancel') {
                    wx.showModal({
                        title: '保存圖片失敗',
                        content: '您已取消保存圖片到相冊!',
                        showCancel: false
                    });
                } else {
                    wx.showModal({
                        title: '提示',
                        content: '保存圖片失敗,您能夠點擊肯定設置獲取相冊權限後再嘗試保存!',
                        complete: function(res) {
                            if (res.confirm) {
                                wx.openSetting({});      // 打開小程序設置頁面,能夠設置權限
                            } else {
                                wx.showModal({
                                    title: '保存圖片失敗',
                                    content: '您已取消保存圖片到相冊!',
                                    showCancel: false
                                });
                            }
                        }
                    });
                }
            }
        });
    }
}

參考文章:
小程序05 canvas繪圖並保存到相冊
canvas坑

6.分享轉發功能

若是使用右上角的默認分享功能,能夠調用onShareAppMessage(), 若是自定義按鈕分享則是使用<button open-type="share"> 結合 onShareAppMessage里加一些判斷。(注意:成功/失敗callback於2018/10/10廢棄)

<button id="share-family" open-type="share">分享給家人</button>

onShareAppMessage(res) {
    let  shareType  =  'friend';
    let  title  =  '送你一個公益禮包,快去打開看看是什麼!';
    let  path  =  'XXXX'; // 右上角分享時

    if (res.from  ===  'button') {// 來自頁面內轉發按鈕,根據不一樣的#id分享不一樣的連接等操做
        shareType  =  res.target.id.split('-')[1];
        if (shareType  ===  'family') { // 分享結果頁
            path  =  ‘XXXXXX2’;
            title  = '我有個公益禮包須要和家人一塊兒打開,你快點進來!'  ;
        }
        ....
    }
    return { // 分享的title,path裏均可有變量
        title:  title,
        path:  path,
        imageUrl:  'xxx',
        success(res) {
            console.log(res);
            作一些成功後的操做...
        },
        fail(res) {
            console.log(res);
        }
    };
}

7.上報formid給後臺實現服務消息觸達

1.在微信公衆平臺-小程序的模板中心先申請一個消息模板
2.服務消息觸達只有支付的和提交表單才能觸發服務觸達通知。而支付這個方法不符合場景,因此使用提交表單:把任意一個文本改形成一個空表單的按鈕,而後點擊上報formid給後臺。(1次提交表單可下發1條,屢次提交下發條數獨立,相互不影響。)
3.後臺使用formid後調用相應觸達的接口。

/**
前提條件:
1.已獲取access_tocken。
(參考接口:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appId}&secret=${appSecret})
2.已獲取openId。
(參考接口:https://api.weixin.qq.com/sns/jscode2session?appid=${G.appId}&secret=${ appSecret}&js_code=${code}&grant_type=authorization_code)
**/

// 關鍵代碼:
<form bindsubmit="formSubmit" report-submit>
    <button form-type="submit">
        一個普通文本,把他改形成一個按鈕,點擊提交空表單來上報formid
    </button>
</form>

formSubmit(e) {
    const { formId } = e.detail; // 得到formid
    ...
},

注意:
1.只能手機調試,我用開發工具打印出來的formId: "the formId is a mock one"並非數字串。
2.每一個formid只能給當前用戶推送的時候用 不能給其餘人用。

除官方api外的參考文章:
微信小程序實例:建立下發模板消息實例
手把手教你開發微信小程序之模版消息
開發 | 教你突破小程序模板消息的推送限制

8.獲取用戶信息接口wx.getUserInfo的廢棄問題

wx.getUserInfo接口是獲取用戶信息(暱稱,頭像等)的接口,在官方文檔上寫是即將廢棄。如今開發版和體驗版已經廢棄(調用接口默認直接fail),可是現網版本仍是可使用(會出現系統彈彈窗),官網更新說於2018/10/10廢棄
目前,有兩種兼容方式:
1.若是隻是單純展現用戶頭像或暱稱,可使用 <open-data > 組件。可是這個有侷限性,只能顯示,卻獲取不到信息,好比:後臺接口須要前端傳遞用戶暱稱或頭像信息時。

<open-data type="userAvatarUrl"></open-data>

2.使用<button open-type="getUserInfo">,引導用戶主動進行受權操做(適配v1.3.0以上版本)

<button open-type="getUserInfo" bindgetuserinfo="onGotUserInfo"\>
onGotUserInfo(e){
  const { errMsg, userInfo } = e.detail;
  if(errMsg.indexOf('ok') != -1) { //贊成受權
    info = e.detail.userInfo;
  }
  const { avatarUrl, nickName } = info; // 獲取到了頭像,暱稱等
  ...
},

官方api說明廢棄問題:
https://developers.weixin.qq....

9.生成二維碼

參考如下api的三種api能夠獲取二維碼,可是有侷限性。好比說:可接受path參數較長,生成個數受限;有的可接受頁面參數較短,生成個數不受限;
https://developers.weixin.qq....

1)獲取access_token的接口 GET
https://api.weixin.qq.com/cgi...

2)獲取二維碼圖片的文件流接口 POST
https://api.weixin.qq.com/wxa...
{ "path": "pages/list" }

10.<rich-text>組件

由於說明彈窗的文字是運營在工具上配置的一些字段,而後如今有一些關鍵字高亮的功能,那樣運營可能要配置html字符串片斷或者其餘字符串片斷,但小程序不能夠像H5直接插入html片斷,高亮實現起來比較麻煩
網上解決方法:有的使用wxParse工具庫,有的是本身寫正則而後去本身拼湊標籤
目前解決方法:使用小程序的<rich-text>組件,把內容字段定義成json形式(而不是html格式,免去了手動正則匹配html標籤的步驟),而後來動態生成相應標籤並動態添加高亮class,但有個不足的地方就是每一個text片斷若是高亮class是hightlight,而不符合的會有一個空的class。

ps.不採用wxParse的緣由:
須要引入7個文件而後總大小134KB,感受比較佔體積。

11.拒絕地理位置受權後從新拉起受權窗口

當用戶選擇一些個性化偏好設置以後,系統會把選擇保存在受權緩存裏,後續碰到相同受權不會再系統彈窗詢問,而是默認以第一次用戶的選擇爲準(獲取地理位置也屬於這種狀況)。如今需求是但願能點擊「獲取當前地址」以後再次彈窗詢問用戶受權。

api bug:
若是用戶拒絕第一次系統受權彈窗,後面wx.authorize()拉取受權窗口的接口將無效。(在wx.authorize的success回調裏調用後臺獲取地址接口會直接fail, 報{errMsg: "getLocation:fail auth deny"}的錯)

解決方案:
經過一個點擊操做來調起openSetting。先去查用戶是否受權地理位置(wx.getSetting + authSetting['scope.userLocation']), 若是未受權則打開一個自定義的彈窗詢問用戶是否去「設置」中打開權限(wx.showModal + wx.openSetting),而後跳轉去到「設置」。若是「設置」中用戶打開地理權限按鈕,就在成功的callback裏去調獲取地址的API,後續操做就和第一次進入頁面一致了。(這裏的「設置」是指小程序的受權設置頁,非手機設置或者自定義的設置頁)

版本兼容:
**2.3.0版本開始,用戶只有發生點擊行爲後,才能夠跳轉打開設置頁,因此不能直接調用,如onLoad裏就調用。(2018/10/10生效)
1)<button open-type="openSetting" bindopensetting="openSettingFn"> 按鈕兼容 (v2.0.7以上生效)
2)<button @tap="openSettingFn">自動獲取地址</button>綁定的點擊事件openSettingFn仍是能夠調用api**

// 寫法1
<button open-type="openSetting"  bindopensetting="openSetting">自動獲取地址</button>
openSetting(e) {
  //判斷是否得到了用戶地理位置受權(v2.0.7以上版本)
  const that = this;
  if(e.detail.authSetting['scope.userLocation']) { 
    //贊成用戶的地理位置受權 馬上打開「設置」
    const getUserLocationWrapper = function(){
      API.getUserLocation().then((location)=>{
        ...
      }).catch((error) => {
        console.log('發起api 失敗',error)
      });
    }
    // 設置一個延時 由於用戶打開受權按鈕不能當即生效 因此會出現請求接口auth deny的問題
    setTimeout(getUserLocationWrapper, 500);
  }
}

// 寫法2
<view class="edit-item-authorize" @tap="dealLocationAuthorize">
  <text>自動獲取地址</text>
</view>

dealLocationAuthorize() {
  //判斷是否得到了用戶地理位置受權(v2.0.7如下版本)
  wx.getSetting({
    success: (res) => {
      if (!res.authSetting['scope.userLocation']){
        this.openConfirm()
      }
    }
  })
}

// 未受權地址時,須要打開自定義的彈窗,詢問用戶是否去設置中打開權限
openConfirm () {
  const that = this;
  //此處能夠打開一個modal詢問,而後在success的回調裏調用openSetting都行的
  //wx.showModal({
    //content: 'XXXX要獲取您的地理位置,是否容許?',
    //confirmText: "容許",
    //cancelText: "不容許",
    //success: function (res) {
      //if (res.confirm) { //點擊「確認」時打開設置頁面
      
        wx.openSetting({ // openSetting打開「設置」(v2.0.7如下版本)
          success: (res) => {
            const getUserLocationWrapper = function(){
              API.getUserLocation().then((location)=>{
                ...
                console.log('調用後臺接口拿到位置信息', location)
              }).catch((error) => {
                console.log('發起調用後臺接口失敗',error)
              });
            }
            // 設置一個延時 由於用戶打開受權按鈕不能當即生效 因此會出現請求接口auth deny的問題
            setTimeout(getUserLocationWrapper, 500);
          }
        })
        
      //} else {
       // console.log('用戶點擊取消')
      //}
      //that.$apply();
    //}
  //});
}

12.有時候開發者模式自測經過,可是發的體驗版一些數據拿不到,而後當體驗版開了調試模式時,又能夠跑通全部邏輯。

解決過程:後來發現是請求方式的問題,dev環境都是http請求,idc則須要https的請求,因此以前只有開了調試模式才能拿到數據。而後,還發現由於調試者工具上開發時默認勾選「不校驗合法域名、https證書...」的選項因此開發時未報錯,若是取消勾選則會報http那個域名不在白名單內報錯(咱們小程序白名單用的是https的url)。

還發現了一些奇怪的現象:像小程序開發板/體驗版開了調試模式,再去打開線上小程序,本沒有調試工具的線上小程序也有了調試工具。以及這三個版本小程序的緩存感受有必定聯繫,可能共用。具體待實驗後跟進。

相關文章
相關標籤/搜索