Logo

微信小程序码开发注意事项

avatar hugo 18 Sep 2020

后端

Gem: bs_wechat_mini_program

Source Code: set_unlimited_wxacode

用法:

class Model < ApplicationRecord
  SLUG_LENGTH = 24

  # https://github.com/norman/friendly_id
  extend FriendlyId
  friendly_id :slug

  # https://github.com/FooBarWidget/default_value_for
  default_value_for :slug do
  loop do
    new_slug = SecureRandom.urlsafe_base64(SLUG_LENGTH)
    break new_slug unless Model.exists?(slug: new_slug)
    end
  end

  has_one_attached :wxacode

  set_unlimited_wxacode :wxacode, page: "pages/package-bookable/detail" # default scene: id=xx
  set_unlimited_wxacode :wxacode, page: "pages/package-bookable/detail", scene: :slug, is_hyaline: true, width: 1280, auto_color: true
  set_unlimited_wxacode :wxacode, page: "pages/package-bookable/detail", scene: -> { "id=#{slug}" }
  set_unlimited_wxacode :wxacode, page: "pages/package-bookable/detail", scene: -> { "id=#{id}&kind=#{kind}" }, line_color: { r: "133", g: "166", b: "111" }
end

Model.friendly.find params[:id] # id is a slug string
  • scene 最大32个可见字符,只支持数字、大小写英文以及部分特殊字 !#$&'()*+,/:;=?@-._~
irb> 'restaurant'.size # => 10
irb> 'id='.size # => 3
irb> '&kind='.size # => 6
irb> 32 - (10 + 3 + 6) # => 13,9万亿
irb> SecureRandom.urlsafe_base64(24) # => "CyR78WW0r8Mz3vD-n2YvnpCqdASk3tGo"
irb> "CyR78WW0r8Mz3vD-n2YvnpCqdASk3tGo".size # => 32, The length of the result string is about 4/3 of 24
  • page 必须是已经发布的小程序存在的页面(否则报错),例如 pages/index/index ,根路径前不要填加 / ,不能携带参数(参数请放在scene字段里)
  • 调用分钟频率受限(5000次/分钟),如需大量小程序码,建议预生成

Why slug?

静态页面的小程序码 [https://domain.com/pages/about_us](https://domain.com/pages/about_us) or https://domain.com/pages/tos

Ref

wxacode.getUnlimited: 获取小程序码,适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制。

小程序端

假如生成小程序码时的 scene 参数是 id=xx&kind=yy

Page({
  onLoad (query) {
    // Good:
    console.log(query) // => { scene: "id%3D2%xxkind%3Dyy" }

    // Bad:
    console.log(uni.getLaunchOptionsSync()); // 只在冷启动时有效,小程序未被销毁时拿到的数据保持不变
    // {
    // 	path: "pages/package-bookable/detail",
    // 	query: {
    // 		scene: "id%3D2%26kind%3Dwinery"
    // 	},
    // 	referrerInfo: {},
    // 	scene: 1047,
    // 	shareTicket: undefined
    // }

    let id, kind, scene;
    if (options.scene) {
      scene = resolveQrcodeScene(options.scene);
      ({ id, kind } = scene);
    } else {
      // wx.navigateTo({ url: 'pages/package-bookable/detail?id=xx&kind=yy' })
      ({ id, kind } = options);
    }

    // use id and kind to fetch data
  },

    resolveQrcodeScene(scene) {
      // scene 需要使用 decodeURIComponent 才能获取到生成二维码时传入的 scene
      scene = decodeURIComponent(scene);
      const arr = scene.split('&');
      const obj = {};
      arr.forEach(item => {
      const [k, v] = item.split('=');
        obj[k] = v;
      });
      return obj;
    }
})

Ref

小程序内扫码

小程序内扫码非本小程序的小程序码返回:

{
  charSet: "UTF-8"
  errMsg: "scanCode:ok"
  rawData: "bGMxc3lxblU4Yl9IMEltMlBtSlJUN3NlbmU9N2Y0ZDdjMWM="
  result: "*"
  scanType: "WX_CODE"
}

小程序内扫码本小程序的小程序码返回:

{
  charSet: "UTF-8"
  errMsg: "scanCode:ok"
  path: "pages/package-wine/detail?scene=id%3D1"
  rawData: "bDAyNFJ6JkxrM1FuQXY9I3YqdzsyKTI="
  scanType: "WX_CODE"
}

小程序内扫码普通二维码,二维码数据会在 result 里返回:

{
  charSet: "UTF-8"
  errMsg: "scanCode:ok"
  rawData: "aHR0cHM6Ly9jbGkuaW0vbW9iIw=="
  result: "https://cli.im/mob#"
  scanType: "QR_CODE"
}

处理代码示例:

const data = await uni.scanCode({ onlyFromCamera: true });

if (data.path) {
  this.$nav.nav('/' + data.path);
} else {
  this.$nav.navigateBack(); // or navigate to homepage
}

wx.scanCode(Object object): 调起客户端扫码界面进行扫码

首次提交审核注意事项

手动上传一份小程序码,关联到有分享海报的数据上。

> record = Model.find # or Model.each do { ... }
> record.wxacode = ActiveStorage::Blob.last

手动更新小程序码:

$ cap production rails:console
ruby> record = Model.find
ruby> record.set_wxacode_with_unlimited_wxacode # replace `wxacode` with column param in `set_unlimited_wxacode :column`