Swift Server Push Notification 配置

Swift Server Push Notification 配置
Photo by Jakub Żerdzicki / Unsplash

获取证书

在 Apple Developer 开发者账号 Certificates, Identifiers & Profiles 里选择 Keys。新增一个 key, configure 里选择 Sandbox & Production。下载该 p8 证书,并且保存好(只能下载一次)。

终端 cd 到证书所在路径,输入下面指令。

openssl pkcs8 -nocrypt -in AuthKey_XXXXXXXXX.p8 -out ~/Downloads/key.pem

cat key.pem

得到 PRIVATE KEY 字符串,复制好。

服务端配置

服务端有多种技术栈方案,包括 Java、NodeJS、Swift、Python 等。这里采用 Swift Server 方案。

Swift Server 整体使用 Vapor 框架,具体实现可以参考官方文档。对于 Apple Push Notification 的实现使用 APNSwift 模块。

APNSwift 初始化需要配置推送证书等信息。

static let deviceToken = ""
static let appBundleID = ""
static let privateKey = """
"""
static let keyIdentifier = ""
static let teamIdentifier = ""
    
let client = APNSClient(
    configuration: .init(
        authenticationMethod: .jwt(
            privateKey: try .init(pemRepresentation: privateKey),
            keyIdentifier: keyIdentifier,
            teamIdentifier: teamIdentifier
        ),
        environment: .development
    ),
    eventLoopGroupProvider: .createNew,
    responseDecoder: JSONDecoder(),
    requestEncoder: JSONEncoder()
)

// Shutdown the client when done
try await client.shutdown()
  • privateKey 就是上面 cat key.pem 得到的 PRIVATE KEY 字符串,包含 -----BEGIN PRIVATE KEY----------END PRIVATE KEY-----
  • teamIdentifier 是 Apple Developer 的团队 id。
  • keyIdentifier 是上面在 Apple Developer 生成推送 p8 证书时,Key 对应的 KEY ID
  • deviceToken 是移动端 iOS app 生成的 push device token
Key ID

客户端配置

iOS 项目需要设置 Push Notification 的 Capability。

Push Notifications Capability

然后在 app 启动后获取通知权限,这样才能拿到 push device token。

import UIKit

final class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 请求推送通知权限
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
            if granted {
                // 注册 APNs
                DispatchQueue.main.async {
                    application.registerForRemoteNotifications()
                }
            } else {
                print("User denied push notifications")
            }
        }
        return true
    }

    // 处理推送通知注册成功后的设备 token
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        print("Device Token: \(deviceToken)")
        let deviceTokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
        print("Device Token String: \(deviceTokenString)")
        // 将 deviceToken 发送到你的服务器
    }

    // 处理推送通知注册失败
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Failed to register for remote notifications: \(error)")
    }
}

拿到 deviceToken 后,将其发送给服务器存储。服务器发送推送时,需要指定 deviceToken 才能知道是对哪一台手机发送推送。

尝试发送简单推送

Server 调用下面方法,传入初始化的 APNSClient 实例。不出意外的话,手机就能收到推送了。

func sendSimpleAlert(with client: some APNSClientProtocol) async throws {
    try await client.sendAlertNotification(
        .init(
            alert: .init(
                title: .raw("Simple Alert"),
                subtitle: .raw("Subtitle"),
                body: .raw("Body"),
                launchImage: nil
            ),
            expiration: .immediately,
            priority: .immediately,
            topic: self.appBundleID,
            payload: EmptyPayload()
        ),
        deviceToken: self.deviceToken
    )
}

Read more

联通 FTTR 宽带从路由器设置自动重启和穿墙功率

联通 FTTR 宽带从路由器设置自动重启和穿墙功率

几个月前把家里宽带换成了联通的千兆 FTTR 宽带,包含一主一从两个点位。配套光猫设备是华为的星光 F50 尊享版。 主点位放置在客厅茶几上,方便连接电视。从点位放在卧室门口,那里恰好有一个不耽误过路的小拐角可以放路由器。平常我们基本不在客厅活动,其他区域最近的 Wi-Fi 信号源是从路由器,因此我们大多数的设备连接的都是从路由器。从路由器的工作负荷很大。 从路由器个头小主路由器很多,散热不咋地。工作时间久了发热就容易发生数据包堵塞,丢包延迟高。需要把它电源拔掉重启。从宽带开通到现在,数据包堵塞影响网络的情况每个月会发生一次。有一次还影响了居家办公的视频会议。宽带维修师傅也给不出有效的法子,建议就是定期插拔从路由器电源。 从路由器和书房之间隔了两堵墙。信号到我书桌那个位置时,千兆网速已经衰减到只有 400-500Mbps 了,折损将近一半。叠加路由器发热的 debuff,书桌位置的网速最差的时候几乎和百兆宽带差不多。 我尝试过在光猫后台管理将路由器功率设置到「穿墙」模式,但没有任何作用。今天在后台研究了一番发现,原来我之前设置的功率是仅对主路由器生效,从路由器还是标准功率。要修

By Gray
《漫步华尔街(第12版)》读书笔记

《漫步华尔街(第12版)》读书笔记

股票分析 基本面分析 * 基本面分析的四个基本决定因素 * 预期增长率 * 复合增长(复利)对投资决策有很重要的意义。 * 一只股票的股利增长和盈利增长率越高,理性投资者应愿意为其支付越高的价格。 * 推论:一只股票的超常增长率持续时间越长,理性投资者应愿意为其支付越高的价格。 * 预期股利支付率 * 对于预期增长率相同的两只股票来说,持有股利支付率越高的股票,较之股利支付率低的股票,会使你的财务状况更好。 * 在其他条件相同的情况下,一家公司发放的现金股利占其盈利的比例越高,理性投资者应愿意为其股票支付越高的价格。 * 特例,很多处于强劲增长阶段的公司,往往不支付任何股利。这时候不满足「在其他条件相同的情况下」。 * 风险程度 * 在其他条件相同的情况下,一家公司的股票风险越低,理性投资者(以及厌恶风险的投资者)应愿意为其股票支付越高的价格。 * 市场利率水平 * 在其他条件相同的情况下,市场利率越低,理性投资者应愿意为股票支付越高的价格。 * 举例,银行存款利率

By Gray