Swift Server Push Notification 配置

Share
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

在 AI 时代,做 iOS 逆向分析有哪些高效手段

在 AI 时代,做 iOS 逆向分析有哪些高效手段

AI 发展如此迅猛,传统的代码手艺活已经被 AI 取代了很大一部分。除了生成代码外,AI 在其他的研发流程也能提升很多效率,例如这次要说的 AI 逆向分析。 在手工时代,我们逆向分析一个 iOS app,通常是使用 Hopper 或者 IDA 等软件查看解密的 Mach-O,然后利用软件提供的能力加上人工去分析逻辑流程。这个过程还要求我们懂一些基础的汇编语法。有时候还要去猜测哪些类哪些方法是负责某个逻辑,靠试验去验证。 现在来到了大模型时代,AI 不仅能自己通过一些简单的工具去分析 ipa 和 Mach-O ,也能使用更准更稳的 MCP、Skill 工具来做深度的分析。 Hopper MCP Hopper 在新版本支持了 MCP Server。 把 framework、Mach-O 或者解密后的 IPA 直接丢给它,

By Gray
Cinder:基于 Swift Macro 与 Mach-O Section 的解耦注册机制

Cinder:基于 Swift Macro 与 Mach-O Section 的解耦注册机制

Cinder(Github) 是一个无需逐模块启动注册、支持字符串、类型和函数调用的 Swift 编译期注册框架。 Cinder 是什么 在 iOS app 里借助 Mach-O 注册能力做一些二进制的插桩操作并不罕见。以往这些操作大都使用 objc runtime ,借助 __attribute__((used)) 和 __attribute__((section("name"))) 实现。在 Swift 上实现有一些难度,因为 Swift runtime 能力弱,以及早期的版本没有类似 objc 的 __attribute__ 能力。 * 在 Swift 5.10 版本,Apple 提供了 @_used 和

By Gray