# 在 iOS 设备上测试

在开发测试过程中,我注意到 iOS 和模拟器、安卓设备等略有不同。如下:

  1. iOS 的 JavaScript 没有 Promise.finally()。可以自己在 app.js 中手动添加如下代码:
App({
  OnLaunch() {
    // ios 端没有 Promise.finally(),需要自己定义
    Promise.prototype.finally = function (callback) {
      let P = this.constructor;
      return this.then(
        value => P.resolve(callback()).then(() => value),
        reason => P.resolve(callback()).then(() => {
          throw reason
      })
      );
    };
  }
})
  1. iOS 中 wx.showActionSheet (opens new window)itemColor 参数仅支持 #000000 十六进制形式,不支持 red 等颜色(安卓/模拟器均支持)。

# 设置转发功能

在需要转发的每个页面的 js 下添加 onShareAppMessage 函数即可。函数模板如下:

onShareAppMessage: function (res) {
  if (res.from === 'button') {
    // 来自页面内转发按钮
    console.log(res.target)
  }
  return {
    title: '云开发技术训练营',
    path: "pages/home/home,
    imageUrl:"https://hackwork.oss-cn-shanghai.aliyuncs.com/lesson/weapp/4/weapp.jpg",
    success: function (res) {
      // 转发成功
    },
    fail: function (res) {
      // 转发失败
    }
  }
},

如果想要自动设置所有页面的转发,可以参考 https://www.cnblogs.com/xyyt/p/12614181.html。

# 小程序配置的细节

如删掉 tabBar、下拉小程序不出现空白、改变背景颜色、禁止页面下拉、自定义顶部导航栏。可见 https://cloudbase.net/community/guides/handbook/tcb09.html。

# 带参小程序码

# 获取带参小程序码

官方文档 (opens new window)

带参数的微信小程序可以在服务器以 HTTPS 调用 API 或在小程序的云函数中获取。这里给出后者的示例代码。

由于 wxacode.get 总共只能生成十万个小程序码,因此我们使用 wxacode.getUnlimited。代价是,参数 scene 字符串长度不能大于 32。(openid 的长度为 28,数据库记录的 _id 长度为 32)

//云函数 index.js
/*
获取某活动的签到二维码
文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html
调用方法:

wx.cloud.callFunction({
  name: "get_check_in_wxacode",
  data: {
    id: activity_id,
  },
  success(){},
  fail(){}
}
*/
const cloud = require('wx-server-sdk');
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
});

exports.main = async (event, context) => {
  console.log(event);
  console.log(context);

  try {
    const result = await cloud.openapi.wxacode.getUnlimited({
      scene: event.id,
      path: 'pages/activities/activities'
    });
    return result;
  } catch (err) {
    return err;
  }
}

注意,这个 API 获取的二维码在小程序发布之前都不能被正确识别,无论是微信扫码进入小程序亦或是小程序内 wx.scanCode()。在正式发布后,开发版/体验版/正式版都可以正确识别。

微信扫码进入小程序,可用以下方法在上述 path 页的 onLoad 函数中获取 scene 值:

  onLoad(query) {
    // scene 需要使用 decodeURIComponent 才能获取到生成二维码时传入的 scene
    const scene = decodeURIComponent(query.scene)
  }

调用 wx.scanCode() 的识别方法如下:

function resolve_url (url) {
  let array = url.split('?');
  let obj = {
    __path: array[0]
  };
  if (array[1] != undefined) {
    let option_arr = array[1].split('&');
    option_arr.forEach(element => {
      let option = element.split('=');
      if (option.length == 2) {
        obj[option[0]] = option[1];
      }
    });
  }
  return obj;
}
wx.scanCode({
  success: res => {
    let path = res.path; // path='pages/activities/activities?scene=xxxxxxxx'
    let obj = resolve_url(path);
    const scene = console.log(obj.scene);
  }
})

# 小程序码处理

小程序中需要将获取的 result 中的 buffer 转为 base64 编码,即可作为 wxml 的 <image> 控件的 src 参数,呈现在屏幕上。

wx.cloud.callFunction({
  name: "get_check_in_wxacode",
  data: {
    id: app.globalData.current_activity._id
  },
  success(res) {
    let wxacode_url = "data:image/png;base64," + wx.arrayBufferToBase64(res.result.buffer);
    that.setData({
      wxacode_url: wxacode_url // 可作为 wxml <image> 控件的 src 参数
    })
  },
  fail(err) {
    console.log(err)
    wx.showToast({
      title: '获取签到二维码失败 请联系管理员',
      icon: 'none'
    })
  }
})

效果图

更新:大图预览和下载功能可以直接调用 wx.previewImage() 一行代码完成,不用下面这么麻烦。

配合 WeUI 小程序的 gallery 控件 (opens new window)即可实现大图预览功能。

图片下载功能,同样是利用 base64 编码的文件。申请权限以后,先用 base64 编码的字符串 wx.getFileSystemManager().writeFile() 生成临时文件,再将临时文件 wx.saveImageToPhotosAlbum() 保存到相册。微信 API 会保存到默认的相册位置(安卓版微信 7.0.16 会保存到 /sdcard/Pictures/Weixin),且不会向小程序返回路径或文件名。

  downloadWxacode() {
    let that = this;
    wx.authorize({ // 申请权限
      scope: "scope.writePhotosAlbum",
      success: res => {
        wx.getFileSystemManager().writeFile({ // 存到临时文件
          filePath: wx.env.USER_DATA_PATH + '/temp.png',
          data: that.data.wxacode_url.slice(22), // 把 data:image/png;base64, 去除
          encoding: 'base64',
          success: res => {
            wx.saveImageToPhotosAlbum({ // 存到相册
              filePath: wx.env.USER_DATA_PATH + '/temp.png',
              success: function (res) {
                console.log(res);
                wx.showToast({
                  title: '保存成功',
                  icon: 'none',
                  duration: 5000
                })
              },
              fail: function (err) {
                console.log(err)
                wx.showToast({
                  title: '保存失败',
                  icon: 'none'
                })
              }
            })
          },
          fail: err => {
            console.log(err)
            wx.showToast({
              title: '保存失败',
              icon: 'none'
            })
          }
        })
      },
      fail: err => {
        console.log(err)
        wx.showToast({
          title: '没有写入相册的权限',
          icon: 'none'
        })
      }
    });
  }

# 绕开审核限制

更新于 2020.9.14,之后可能失效

我实现了一个社团活动管理的小程序,任何人可以创建活动,但审核的时候,“创建活动”这个功能导致小程序没有通过审核,大概意思就是个人小程序不能作为信息公开的平台。

去开个公司专门用于审核肯定是不现实的。于是,就只能和审核员斗争了

经过观察,我发现审核员只是测试功能,不会动代码/数据库。

因此,我加入一段代码,每次启动时读取数据库配置,如果存在 can_upload: true,才显示添加活动相关组件,否则就不显示。成功通过审核。

当然,以后也可能有复查导致小程序下架,不过我目前还没有被下架/警告过。