# 设备呼叫手机微信

在用户对设备进行授权后,设备可以向已授权用户发起音视频通话,用户在微信内打开小程序进行接听。

硬件开发者需建立小程序用户 openId、小程序 appId、硬件设备之间的关联。用户在手机端授权后设备才可拨打。

如果要获取通话过程的各类事件,可以使用插件的 onVoipEvent 接口。

# 1. 设备端发起通话(安卓直连)

发起通话前,一般需要用户选择拨打给的用户和通话的类型(音频/视频)。

根据业务场景不同,发起通话前的流程(如选择联系人和房间类型)可以在小程序的另一个页面中或者安卓应用中进行。

# 1.1 小程序页面进入通话页面

适用于用户发起通话前的页面(如联系人选择等)是小程序页面时。

发起通话时,设备端需要在之前的页面中调用插件的 initByCaller 接口,然后跳转到插件的发起通话页面。

const wmpfVoip = requirePlugin('wmpf-voip').default

try {
  // 2.4.0 以下版本 roomId 为 groupId
  const { roomId, isSuccess } = await wmpfVoip.initByCaller({
    caller: {
      id: 'sn', // 设备 SN
      // 不支持传 name,显示的是授权时「deviceName」+「modelId 对应设备型号」
    },
    listener: {
      // 参见 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html 获取
      id: 'openId' // 接听方 用户 openId
      name: 'xxxxxx', // 接听方名字,仅显示用
    },
    roomType: 'video', // 房间类型。voice: 音频房间;video: 视频房间
    businessType: 1, // 1 为设备呼叫手机微信
    voipToken: 'xxxxxxxxxx', // 使用设备认证 SDK 注册的设备传入 deviceToken,使用 WMPF RegisterMiniProgramDevice 接口注册的设备无需传入(插件 2.3.0 支持)
    miniprogramState: 'formal', // 指定接听方使用的小程序版本
  })

  if (isSuccess) {
    // 如果小程序启动直接进入插件页面,则不要调用 wx.redirectTo
    wx.redirectTo({
      url: wmpfVoip.CALL_PAGE_PATH,
      // 插件 2.3.9 开始支持 CALL_PAGE_PATH, 低版本请传入 'plugin-private://wxf830863afde621eb/pages/call-page-plugin/call-page-plugin',
    })
  } else {
    wx.showToast({
      title: '呼叫失败',
      icon: 'error',
    })
  }
} catch (e) {
  // 参数错误的情况会通过异常抛出
  wx.showToast({
    title: '呼叫失败',
    icon: 'error',
  })
}

# 1.2 安卓应用直接进入通话页面

适用于用户发起通话前的页面(如联系人选择等)是安卓应用页面时。

发起通话时,需要安卓应用调用 WMPF launchMiniProgram 接口拉起小程序,path 直接使用插件的拨打页面 plugin-private://wxf830863afde621eb/pages/call-page-plugin/call-page-plugin。路径后可以带自定义参数,如 &a=1

这种情况下,开发者可以直接在小程序 App.onShow 时调用 initByCaller,插件会直接进入拨打状态,不需要也不可以再跳转到插件页面

强烈建议开发者在启动参数中增加防重放参数,例如callSeq=1703741306977。参数名可以自定义,取值可以是时间戳或其他唯一 ID。主要起到以下功能

  • 如果用户点击重新进入小程序,避免重复发起通话。
  • 小程序切后台又切前台的情况(如进入小程序设置页、进入其他原生页面、用户手动操作等),App.onShowcallPageOnShow 会多次触发,避免重复发起通话。
  • 标识当前启动是会发起通话,方便一些逻辑判断。

建议开发者使用「小程序预热」能力加快小程序的启动速度。

const wmpfVoip = requirePlugin('wmpf-voip').default

// 假设预热启动参数为 ?isPreLaunch=1
// 假设发起呼叫时启动参数为 ?callSeq=1703741306977&..其他呼叫用的参数

function checkCallSeq(seq) {
  if (!seq) return false
  // 重新进入小程序会重启小程序,因此 seq 需要持久化存储,不能仅存变量
  const lastCallSeq = wx.getStorageSync('WMPF_CALL_SEQ')
  if (seq !== lastCallSeq) {
    // 示例仅做简单的比较,开发者可以根据业务需要增加其他判断条件,如 parstInt(seq) > parseInt(lastCallSeq)
    wx.setStorageSync('WMPF_CALL_SEQ', seq)
    return true
  } else {
    // 重复发起的通话
    return false
  }
}

function call(options) {
  try {
    wmpfVoip
      .initByCaller({
        /* 参数可从 options 中获取,此处省略 */
      })
      .catch(e => {
        wx.showToast({
          title: '呼叫失败',
          icon: 'error',
        })
      })
  } catch (e) {
    // 参数错误的情况会通过异常抛出
    wx.showToast({
      title: '呼叫失败',
      icon: 'error',
    })
  }
}

/**
 * 调用 WMPF LaunchMiniProgram 时,
 *  - 如果小程序不在前台(未启动或在后台),会触发 App.onShow
 *  - 如果小程序在前台,App.onShow 不会触发,但会触发插件的 callPageOnShow
 */

App({
  onShow() {
    const { query } = wmpfVoip.getPluginEnterOptions()
    if (query.isPreLaunch) {
      // 小程序预热场景,无需处理
      return
    }

    if (!query.callSeq) {
      // 当前启动不是发起通话,无需处理
      return
    }

    if(!checkCallSeq(query.callSeq)) {
      // 重复发起通话,直接忽略
      return
    }

    call(query)
  },
})

wmpfVoip.onVoipEvent(event => {
  if (event.eventName === 'callPageOnShow') {
    // 仅处理小程序在前台时,调用 WMPF LaunchMiniProgram 触发小程序 reLaunch 的情况
    const query = wmpfVoip.getPluginOnloadOptions()
    if (checkCallSeq(query.callSeq)) { 
      // 此处可以过滤掉已被 App.onShow 处理的情况
      call(query)
    }
  }
})

注意

  • 给用户推送的接听提醒会在调用 initByCaller 后由微信后台直接下发,不需要开发者额外调用服务端下发消息的接口。
  • roomType 等参数可以通过拉起小程序的 path 中的 query 传递给小程序。
  • 设备上,APP 拉起小程序或接听通话较慢时,请参考性能与体验优化指南

# 2. 设备端发起通话(Linux 直连)

请参考 《小程序音视频通话 SDK (Linux)》 5.4.1 发起通话部分

# 3. 手机微信端接听通话

用户在手机端可以收到「响铃+振动」的强提醒通知,点击接听按钮后,会启动小程序并直接进入「VOIP 通话」插件页面接听通话。

完成通话后,微信客户端内会显示本次通话的信息与「关闭」按钮,用户点击「关闭」按钮后再跳转开发者调用setVoipEndPagePath设置的页面。开发者未设置时则直接关闭小程序。

开发者可以自定义接听页面按钮,以及通话结束跳转页。详情请参考插件文档

# 4. 设备端处理通话结束(安卓直连)

设备端通话结束后,开发者需自行处理页面跳转或关闭小程序。一般有以下几种方式: