push.js 5.9 KB
Newer Older
DCloud_JSON's avatar
DCloud_JSON 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
async function sendPushMsg(param, appId) {
  // 本方法仅用于暴露给数据库触发器调用(或者在本云对象的其它方法内部调用)
  if (this.getMethodName() === 'sendPushMsg' && this.getClientInfo().source !== 'function') {
    throw {
      errSubject: 'uni-im-co-sendPushMsg',
      errCode: 0,
      errMsg: '本方法仅用于暴露给数据库触发器调用'
    }
  }

  let pushParam = {
    // 验证token是否有效,无效则不向此设备推送消息
    check_token: true,
    settings: {
      //-1表示不设离线,因为离线后重新打开数据统一从数据库中拉取。否则会重复
      ttl: -1,
      // strategy:{
        // 1: 表示该消息在设备在线时推送个推通道,设备离线时推送厂商通道;
        // 3: 表示该消息只通过个推通道下发,不考虑设备是否在线;

      //   "default":2
      // }
    },
    // 离线推送厂商信息配置,需要到云厂商后台申请
    channel: {
      // 华为离线推送
      "HW": "NORMAL",
      // 小米离线推送
      "XM": "114240",
      "OP": "114240",
      "VV": 1
    },
    options: {
      "HW": {
        "/message/android/notification/default_sound": true,
        "/message/android/notification/importance": "NORMAL",
        "/message/android/notification/channel_id": "114240",
        "/message/android/notification/sound": "pushsound",
        "/message/android/category": "IM"
      },
      "VV": {
        "/category": "NORMAL", //二级分类。
      },
      "OP": {
        "/channel_id": "114240"
      },
      "HO": {
        "/android/notification/importance": "NORMAL"
      }
    }
  }
  /**
   * 如果不指定接收消息的客户端appid,则指定为消息推送者的客户端appid。
   * 用于两个客户端appid不同的场景,比如电商项目,商家和普通用户端appid不同
   */
  // 调用扩展插件的初始化接口
  const { invokeExts } = require('uni-im-ext')
  invokeExts('ext-before-send-push',this.clientInfo)
  
  if (!appId) {
    appId = this.clientInfo.appId
    console.log('this.clientInfo',this.clientInfo);
    if (!appId) {
      throw new Error('appId is not definded')
      console.error('####################appId is not definded, use default appId:', appId)
    }
  }
  // 如果是uni-im特殊消息,默认不走厂商通道,只走个推通道
  if (param.payload.type == "uni-im") {
    const msgData = param.payload.data
    let noPushOffline = false
    if (msgData.type === 'system' || msgData.type === 'revoke_msg') {
      noPushOffline = true
    } else {
      // 如果是扩展的消息类型,由扩展模块决定是否需要离线推送
      const { msgTypes } = require('uni-im-ext')
      let msgType = await msgTypes.get(msgData.type)
      if (msgType && msgType.noPushOffline) {
        noPushOffline = msgType.noPushOffline(msgData)
      }
    }
    if (noPushOffline) {
      console.error('uni-im特殊消息,默认不走厂商通道,只走个推通道')
      pushParam.settings.strategy = {
        "default": 3
      }
    }
  }
  
  // 深合并pushParam, param
  (function deepMerge(target, source) {
    if (typeof target !== 'object' || typeof source !== 'object') {
      return;
    }
    for (const key in source) {
      if (typeof target[key] === 'object' && typeof source[key] === 'object') {
        deepMerge(target[key], source[key]);
      } else {
        target[key] = source[key];
      }
    }
    return target;
  })(pushParam, param);
  // console.log('pushParam', pushParam)
  // console.log('pushParam.channel', pushParam.channel)
  
  // 如果是im通知消息(比如:加好友申请,用户请求加群,用户退群等),则记录到数据表uni-im-notification中
  if (param.payload.type == "uni-im-notification") {
    let {
      title,
      content,
      payload,
      sound,
      open_url,
      path,
      user_id
    } = pushParam
    let notificationContent = {
      title,
      content,
      payload,
      sound,
      open_url,
      path
    }
    notificationContent.is_read = false
    notificationContent.create_time = Date.now()
    let notificationData;
    // 如果接收消息的用户量不止一个,则需要插入数据表的记录为多条(数组)
    if (Array.isArray(user_id)) {
      notificationData = user_id.map(uid => {
        return {
          user_id: uid,
          ...notificationContent
        }
      })
    } else {
      notificationData = Object.assign(notificationContent, {
        user_id
      })
    }
    // 执行写入到数据库
    let db = uniCloud.database()
    let uinRes = await db.collection('uni-im-notification').add(notificationData)
    // console.log('uinRes',uinRes)
    param.payload.notificationId = uinRes.id
  }

  // WS 推送:clear-conversation-unreadCount 消息推送给自己
  if (pushParam.payload.type === 'uni-im' && pushParam.payload.data.type === 'clear-conversation-unreadCount') {
    let msgData = pushParam.payload.data
    const { invokeExts } = require('uni-im-ext')
    await invokeExts('push-msg-notify', {
      to_uids: [msgData.to_uid],
      msg: {
        type: 'clear-conversation',
        conversation_id: msgData.conversation_id,
      }
    })
  }

  let res = await uniCloud.getPushManager({
    appId,
    debug: false,
  }).sendMessage(pushParam)
  if (res.errCode) {
    console.error(res.errCode);
    console.error(res.errMsg);
    if (res.errCode == "uni-push-user-invalid" || res.errMsg == "target user is invalid") {
      // 可能因为用户长时间没有登录,或客户端获取到的push_clientid错误;导致的cid无效而发送失败,但是此时已将离线数据写入数据库,登录后可获取。客户端不需要进入 catch
      res = {
        data: {
          "uni-push-err-res": res
        },
        errCode: 0
      }
    } else {
      console.error(res.errCode);
      throw new Error(res.errMsg)
    }
  }
  return res
}

module.exports = {
  sendPushMsg,
}