Skip to content
能力中心
产品中心
应用市场
WebOffice
开发者后台

离线推送

App 客户端不在线时(App 进程被杀死),如果接收到新消息,离线消息会触发WPS协作中台服务端的推送服务。WPS协作中台服务端会通过推送通道下发一条提醒到客户端 SDK。该提醒一般以通知形式展示在通知面板,提示用户有离线消息。

证书配置

请前往苹果开发者帐号中心生成相应的推送证书,获得证书后需将证书上传至企业管理后台

工程配置

在项目 TARGETS 下添加 Push项, Signing & Capabilities -> + -> Push Notifications,并且 Bundle Identifier 与生成的证书相匹配,如下图:

img

img

注册通知

需要在应用启动后,注册通知才能收到远程推送。

代码示例

  1. didFinishLaunchingWithOptions 后注册推送
swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    let center = UNUserNotificationCenter.current()
    center.delegate = self
    center.getNotificationSettings { (settings) in
        if settings.notificationCenterSetting == .enabled {
            print("打开了通知")
        } else {
            print("关闭了通知")
            center.requestAuthorization(options: [.badge, .alert, .sound]) { (granted, error) in
                print("申请了通知")
            }
        }
    }

    return true
}
  1. 在获得 deviceToken 后传入 SDK,SDK 内部将在连接成功后上报给推送服务
swift
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    KIM.shared.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    print("didFailToRegisterForRemoteNotificationsWithError: \(error)")
}

接收离线推送

代码示例

swift
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.sound, .alert])
}

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    let content = response.notification.request.content
    print("push title:\(content.title)")
    print("push subtitle:\(content.subtitle)")
    print("push body:\(content.body)")
    print("push userInfo:\(content.userInfo)")
    completionHandler()
}

应用角标处理

SDK 不处理应用角标的设置与更新,需要根据自身需要补充完善功能. 会话未读数可以通过 SDK 相关接口获得。代码示例:

swift
// 获取消息未读数 (不包含免打扰消息)
KIM.shared.getUnreadMessageCount()

角标数量加 1 处理

因为推送角标除了涉及到协作中台的服务的推送下发外还会考虑用户自身服务的下发。收到新推送时角标上的数量一般的处理方式为在原有的数量上加 1。

参考示例

请替换下面步骤中 groupIdbadgeKey, 并保证他们的正确性, 否则会影响功能使用.

  1. 在项目 TARGETS 下添加推送处理插件,File -> New -> Targets...,选择 Notification Content Extension 和 Notification Service Extension, 输入对应的 Bundle Identifier, 请确保与生成的证书相匹配. 如下图:
  1. 使用 APP GroupId 和 UserDefaults, 在应用和推送插件间进行数据共享.
swift
let groupId: String = "your app groud id"
let badgeKey = "your badge key"

let userDefaults = UserDefaults(suiteName: groupId)
let badge = userDefaults?.value(forKey: badgeKey) as? Int
  1. 可以在应用启动后, 或者其他有效的地方, 添加系统监听及更新应用角标数据的处理,并同步到 UserDefaults, 与推送插件共享数据.
swift
import UIKit
import WOASDK

class AppDelegate: UIResponder, UIApplicationDelegate {

    /// badge UserDefaults key
    private static let badgeKey = "your badge key"

    /// AppGroupId
    private static let groupId: String = "your app groud id"

    /// 角标缓存设置,用于 notificaiton extension 数据共享
    private static var badge: Int {
        get {
            let userDefaults = UserDefaults(suiteName: groupId)
            let badge = (userDefaults?.value(forKey: badgeKey) as? Int) ?? 0
            return badge
        }
        set {
            let userDefaults = UserDefaults(suiteName: groupId)
            userDefaults?.setValue(newValue, forKey: badgeKey)
        }
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        /// ...
        configApplicationBadgeNumber()
    }

    /// 角标更新配置
    func configApplicationBadgeNumber() {
        NotificationCenter.default.addObserver(self, selector: #selector(willResignActiveNotification(notification:)), name: UIApplication.willResignActiveNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(willTerminateNotification(notification:)), name: UIApplication.willTerminateNotification, object: nil)
    }

    @objc func willResignActiveNotification(notification: Notification) {
        updateBadgeNumber()
    }

    @objc func willTerminateNotification(notification: Notification) {
        updateBadgeNumber()
    }

    /// 更新角标
    func updateBadgeNumber() {
        let badge = KIM.shared.getUnreadMessageCount()
        Self.badge = badge
        UIApplication.shared.applicationIconBadgeNumber = badge
    }
}
  1. 在 NotificationService 文件添加对应的处理代码,完成角标的自增处理.
swift
import UserNotifications

class NotificationService: UNNotificationServiceExtension {

    private let badgeKey = "your badge key"
    private let groupID = "your app groud id"

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        if let bestAttemptContent = bestAttemptContent {

            if let userDefaults = UserDefaults(suiteName: groupID),
               var cachedBadge = userDefaults.value(forKey: badgeKey) as? Int {

                // 判断是否为撤回消息
                if isRecallMsg(bestAttemptContent.userInfo) {
                    cachedBadge -= 1
                    cachedBadge = max(0, cachedBadge)
                } else {
                    cachedBadge += 1
                }
                userDefaults.setValue(cachedBadge, forKey: badgeKey)
                userDefaults.synchronize()
                bestAttemptContent.badge = NSNumber(value: cachedBadge)
            }
            contentHandler(bestAttemptContent)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }

    private func isRecallMsg(_ notiUserInfo:  [AnyHashable : Any]) -> Bool {
        guard
            let userinfoDict = notiUserInfo["message"] as? [String: Any],
            let msgInfoDic = userinfoDict["params"] as? [String: Any],
            let decrease = msgInfoDic["corner_mark_decrease"] as? Bool
        else {
            return false
        }
        return decrease
    }
}