zoukankan      html  css  js  c++  java
  • 开发小程序注意的一些问题

    2018年10月10日官网3个接口废弃的通知:

    1、分享监听接口
    分享消息给好友时,开发者将无法从callback获知用户是否分享完成,也无法在分享后立即获得群ID。请参考调整指引

    2、getUserInfo接口
    用户需要点击组件后,才可以触发登录授权弹窗、授权自己的昵称头像等数据。请参考调整指引

    3、openSetting接口
    用户需要点击行为后,才可以跳转打开设置页,管理授权信息。请参考调整指引

    1.不同版本号是否可以使用某方法/属性

    官方文档上提到了几种检测方法,但是测试后发现有些没有用:
    1)wx.canIUse()对一些api没有用
    2)if (wx.apiXX) { wx.apiXX(); }也不完全有用
    所以,最后通过直接比较当前版本号和目标版本号来实现兼容。

    1.  
      /**
    2.  
      * 比较两个版本号的大小,用于兼容小程序不同版本的api时比较版本号(v1 > v2则返回1)
    3.  
      * @param {*} v1
    4.  
      * @param {*} v2
    5.  
      */
    6.  
      export function compareVersion(v1, v2) {
    7.  
      v1 = v1.split('.')
    8.  
      v2 = v2.split('.')
    9.  
      var len = Math.max(v1.length, v2.length)
    10.  
       
    11.  
      while (v1.length < len) {
    12.  
      v1.push('0')
    13.  
      }
    14.  
      while (v2.length < len) {
    15.  
      v2.push('0')
    16.  
      }
    17.  
       
    18.  
      for (var i = 0; i < len; i++) {
    19.  
      var num1 = parseInt(v1[i])
    20.  
      var num2 = parseInt(v2[i])
    21.  
       
    22.  
      if (num1 > num2) {
    23.  
      return 1
    24.  
      } else if (num1 < num2) {
    25.  
      return -1
    26.  
      }
    27.  
      }
    28.  
       
    29.  
      return 0
    30.  
      }
    31.  
       
    32.  
      const SDKVersion = wx.getSystemInfoSync().SDKVersion; // 获取版本
    33.  
      if(T.compareVersion(SDKVersion, '2.0.7')>=0) { ... }

    2.小程序间的跳转

    小程序跳转只能实现 同一公众号下关联 的小程序跳转
    一个公众号可关联10个同主体的小程序,3个不同主体的小程序。
    一个小程序可关联3个公众号。
    (p.s. 所以想跳转像苏宁小程序,只能把我们小程序关联到他们小程序的公众号下)

    (1)使用navigator组件(仅用于微信2.0.7以上版本)

    1.  
      <navigator target="miniProgram" app-id="{{changeNewAppid}}" path="{{changeNewUrl}}" version="release" @tap="goMiniprogram">
    2.  
      跳转mp
    3.  
      </navigator>

    (2)使用navigateToMiniProgram来兼容微信2.0.7以下(但即将废弃) >=1.3.0

    1.  
      goMiniprogram() {
    2.  
      const SDKVersion = wx.getSystemInfoSync().SDKVersion; // 获取版本
    3.  
      if(T.compareVersion(SDKVersion, '2.0.7')>=0) {
    4.  
      wx.navigateToMiniProgram({
    5.  
      appId: this.changeNewAppid,
    6.  
      path: this.changeNewUrl,
    7.  
      envVersion: 'release',
    8.  
      success(res) {
    9.  
      console.log('打开mp成功')
    10.  
      }
    11.  
      })
    12.  
      }
    13.  
      }

    调试注意:
    开发者工具上不会显示跳转,但我们可以从回调函数里log打印信息,只有真机调试才可以跳转。

    3.小程序所属的公众号入口及其推送文章等入口进入小程序的url配置

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

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

    思路:
    1.小程序不能分享到朋友圈,只能通过保存图片的形式分享。
    2.如果保存静态图片,可以直接调接口就行,但是需求是动态的图片(获取用户的头像),所以需要用canvas画图,然后保存成2倍/3倍图。

    优化的问题:
    一、文字有用特殊字体,但是字体文件都比较大。所以需要用fontmin抽取出所需字的字体文件,最后上线页面从原来的3.7MB变成29KB字体woff/eot/ttf文件。

    1. 之前产品想要文案不写死,三种成功页各自有随机的文案,这个在想怎么优化更好。因为写死的文案可以直接抽出来。随机文案要么就是一次性把文案抽出来但字体文件大小会增加;要么就是node写个进程模拟cmd去跑fontmin实时压缩字体的命令,但这种会更慢一些,而且小程序不一定支持这种写法。(一般的PC端网页是支持的)
    2. 小程序中canvas不支持使用自定义字体。所以保存功能需要使用图片替代文字。
    3. 保存图片因为用的canvas,然后canvas每一层无法设置优先级,只能一层层叠上去,所以一些图片/资源异步加载的顺序比较重要,如果加载顺序不做控制则可能将其他内容物覆盖。目前用的是await/aync + Promise.all()来实现

    二、为了使保存的带有二维码的图片更加清晰,保存图片需要使用upng转换成base64格式的。

    5.canvas画图

    1.canvas的clip()裁剪方法,只对第一次裁剪的图有效,后面裁剪都无效。
    解决方案:制作一张和头像图片一样大的中间有个n个圆形镂空(中间透明)的图片绘制在头像上,在视觉上给头像做出圆形的效果。
    2.不能给文字设置字体,所以需求需要特殊字体时用的图片。
    3.保存canvas为图片时,ctx.draw()需要加个定时器,晚些执行canvasToTempFilePath().否则保存下来的是空白图片。

    1.  
      ctx.draw(true, setTimeout(function() { // 延迟一下
    2.  
      wx.canvasToTempFilePath({
    3.  
      x: 0,
    4.  
      y: 0,
    5.  
      2079,
    6.  
      height: 2181,
    7.  
      destWidth: 2079,
    8.  
      destHeight: 2181,
    9.  
      canvasId: 'myCanvas',
    10.  
      success: function(res) {
    11.  
      self.data.savedImgUrl = res.tempFilePath;
    12.  
      self.saveImageToPhoto();
    13.  
      }
    14.  
      });
    15.  
      }, 400));
    16.  
      // 保存图片到相册
    17.  
      saveImageToPhoto() {
    18.  
      const that = this;
    19.  
      if (this.data.savedImgUrl !== '') {
    20.  
      wx.saveImageToPhotosAlbum({
    21.  
      filePath: this.data.savedImgUrl,
    22.  
      success: function() {
    23.  
      that.imgSaveLoading = false;
    24.  
      that.$apply();
    25.  
      wx.showModal({
    26.  
      title: '保存图片成功',
    27.  
      content: 'xxxx',
    28.  
      showCancel: false
    29.  
      });
    30.  
      },
    31.  
      fail: function(res) {
    32.  
      console.log(res);
    33.  
      that.imgSaveLoading = false;
    34.  
      that.$apply();
    35.  
      if (res.errMsg === 'saveImageToPhotosAlbum:fail cancel') {
    36.  
      wx.showModal({
    37.  
      title: '保存图片失败',
    38.  
      content: '您已取消保存图片到相册!',
    39.  
      showCancel: false
    40.  
      });
    41.  
      } else {
    42.  
      wx.showModal({
    43.  
      title: '提示',
    44.  
      content: '保存图片失败,您可以点击确定设置获取相册权限后再尝试保存!',
    45.  
      complete: function(res) {
    46.  
      if (res.confirm) {
    47.  
      wx.openSetting({}); // 打开小程序设置页面,可以设置权限
    48.  
      } else {
    49.  
      wx.showModal({
    50.  
      title: '保存图片失败',
    51.  
      content: '您已取消保存图片到相册!',
    52.  
      showCancel: false
    53.  
      });
    54.  
      }
    55.  
      }
    56.  
      });
    57.  
      }
    58.  
      }
    59.  
      });
    60.  
      }
    61.  
      }

    参考文章:
    小程序05 canvas绘图并保存到相册
    canvas坑

    6.分享转发功能

    如果使用右上角的默认分享功能,可以调用onShareAppMessage(), 如果自定义按钮分享则是使用<button open-type="share"> 结合 onShareAppMessage里加一些判断。(注意:成功/失败callback于2018/10/10废弃)

    1.  
      <button id="share-family" open-type="share">分享给家人</button>
    2.  
       
    3.  
      onShareAppMessage(res) {
    4.  
      let shareType = 'friend';
    5.  
      let title = '送你一个公益礼包,快去打开看看是什么!';
    6.  
      let path = 'XXXX'; // 右上角分享时
    7.  
       
    8.  
      if (res.from === 'button') {// 来自页面内转发按钮,根据不同的#id分享不同的链接等操作
    9.  
      shareType = res.target.id.split('-')[1];
    10.  
      if (shareType === 'family') { // 分享结果页
    11.  
      path = ‘XXXXXX2’;
    12.  
      title = '我有个公益礼包需要和家人一起打开,你快点进来!' ;
    13.  
      }
    14.  
      ....
    15.  
      }
    16.  
      return { // 分享的title,path里都可有变量
    17.  
      title: title,
    18.  
      path: path,
    19.  
      imageUrl: 'xxx',
    20.  
      success(res) {
    21.  
      console.log(res);
    22.  
      做一些成功后的操作...
    23.  
      },
    24.  
      fail(res) {
    25.  
      console.log(res);
    26.  
      }
    27.  
      };
    28.  
      }

    7.上报formid给后台实现服务消息触达

    1.在微信公众平台-小程序的模板中心先申请一个消息模板
    2.服务消息触达只有支付的和提交表单才能触发服务触达通知。而支付这个方法不符合场景,所以使用提交表单:把任意一个文本改造成一个空表单的按钮,然后点击上报formid给后台。(1次提交表单可下发1条,多次提交下发条数独立,相互不影响。)
    3.后台使用formid后调用相应触达的接口。

    1.  
      /**
    2.  
      前提条件:
    3.  
      1.已获取access_tocken。
    4.  
      (参考接口:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appId}&secret=${appSecret})
    5.  
      2.已获取openId。
    6.  
      (参考接口:https://api.weixin.qq.com/sns/jscode2session?appid=${G.appId}&secret=${ appSecret}&js_code=${code}&grant_type=authorization_code)
    7.  
      **/
    8.  
       
    9.  
      // 关键代码:
    10.  
      <form bindsubmit="formSubmit" report-submit>
    11.  
      <button form-type="submit">
    12.  
      一个普通文本,把他改造成一个按钮,点击提交空表单来上报formid
    13.  
      </button>
    14.  
      </form>
    15.  
       
    16.  
      formSubmit(e) {
    17.  
      const { formId } = e.detail; // 获得formid
    18.  
      ...
    19.  
      },

    注意:
    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以上版本)

    1.  
      <button open-type="getUserInfo" bindgetuserinfo="onGotUserInfo">
    2.  
      onGotUserInfo(e){
    3.  
      const { errMsg, userInfo } = e.detail;
    4.  
      if(errMsg.indexOf('ok') != -1) { //同意授权
    5.  
      info = e.detail.userInfo;
    6.  
      }
    7.  
      const { avatarUrl, nickName } = info; // 获取到了头像,昵称等
    8.  
      ...
    9.  
      },

    官方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.  
      // 写法1
    2.  
      <button open-type="openSetting" bindopensetting="openSetting">自动获取地址</button>
    3.  
      openSetting(e) {
    4.  
      //判断是否获得了用户地理位置授权(v2.0.7以上版本)
    5.  
      const that = this;
    6.  
      if(e.detail.authSetting['scope.userLocation']) {
    7.  
      //同意用户的地理位置授权 立刻打开“设置”
    8.  
      const getUserLocationWrapper = function(){
    9.  
      API.getUserLocation().then((location)=>{
    10.  
      ...
    11.  
      }).catch((error) => {
    12.  
      console.log('发起api 失败',error)
    13.  
      });
    14.  
      }
    15.  
      // 设置一个延时 因为用户打开授权按钮不能立即生效 所以会出现请求接口auth deny的问题
    16.  
      setTimeout(getUserLocationWrapper, 500);
    17.  
      }
    18.  
      }
    19.  
       
    20.  
      // 写法2
    21.  
      <view class="edit-item-authorize" @tap="dealLocationAuthorize">
    22.  
      <text>自动获取地址</text>
    23.  
      </view>
    24.  
       
    25.  
      dealLocationAuthorize() {
    26.  
      //判断是否获得了用户地理位置授权(v2.0.7以下版本)
    27.  
      wx.getSetting({
    28.  
      success: (res) => {
    29.  
      if (!res.authSetting['scope.userLocation']){
    30.  
      this.openConfirm()
    31.  
      }
    32.  
      }
    33.  
      })
    34.  
      }
    35.  
       
    36.  
      // 未授权地址时,需要打开自定义的弹窗,询问用户是否去设置中打开权限
    37.  
      openConfirm () {
    38.  
      const that = this;
    39.  
      //此处可以打开一个modal询问,然后在success的回调里调用openSetting都行的
    40.  
      //wx.showModal({
    41.  
      //content: 'XXXX要获取您的地理位置,是否允许?',
    42.  
      //confirmText: "允许",
    43.  
      //cancelText: "不允许",
    44.  
      //success: function (res) {
    45.  
      //if (res.confirm) { //点击“确认”时打开设置页面
    46.  
       
    47.  
      wx.openSetting({ // openSetting打开“设置”(v2.0.7以下版本)
    48.  
      success: (res) => {
    49.  
      const getUserLocationWrapper = function(){
    50.  
      API.getUserLocation().then((location)=>{
    51.  
      ...
    52.  
      console.log('调用后台接口拿到位置信息', location)
    53.  
      }).catch((error) => {
    54.  
      console.log('发起调用后台接口失败',error)
    55.  
      });
    56.  
      }
    57.  
      // 设置一个延时 因为用户打开授权按钮不能立即生效 所以会出现请求接口auth deny的问题
    58.  
      setTimeout(getUserLocationWrapper, 500);
    59.  
      }
    60.  
      })
    61.  
       
    62.  
      //} else {
    63.  
      // console.log('用户点击取消')
    64.  
      //}
    65.  
      //that.$apply();
    66.  
      //}
    67.  
      //});
    68.  
      }

    12.有时候开发者模式自测通过,但是发的体验版一些数据拿不到,然后当体验版开了调试模式时,又可以跑通所有逻辑。

    解决过程:后来发现是请求方式的问题,dev环境都是http请求,idc则需要https的请求,所以之前只有开了调试模式才能拿到数据。然后,还发现因为调试者工具上开发时默认勾选“不校验合法域名、https证书...”的选项所以开发时未报错,如果取消勾选则会报http那个域名不在白名单内报错(我们小程序白名单用的是https的url)。

  • 相关阅读:
    final finally finalize区别
    final 有什么用
    Java基础(一) 八大基本数据类型
    22
    21
    20
    18
    17
    16
    15
  • 原文地址:https://www.cnblogs.com/zxh1919/p/14329106.html
Copyright © 2011-2022 走看看