Electron pushNotifications API:macOS 上 APNS 推送通知的注册、接收与源码实现
Electron pushNotifications APImacOS 上 APNS 推送通知的注册、接收与源码实现【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electronElectron 的pushNotifications模块让 macOS 上的 Electron 主进程应用能够直接对接 Apple 推送通知服务APNS向系统注册接收推送、获取设备令牌并在应用运行期间实时接收远端推送。本文完整覆盖该 API 的方法与事件用法并沿require(electron)到 Objective-C 委托回调的完整调用链剖析其底层实现帮助开发者写出可落地的 APNS 集成代码并理解令牌、错误处理与生命周期细节。模块概览Main 进程下的 APNS 桥接层pushNotifications是 Electron 主进程Main Process模块用于注册并接收来自远端推送服务目前实现为 Apple Push Notification service的通知。它本质上是一个极薄的桥接层JS 侧入口lib/browser/api/push-notifications.ts 仅有一行核心逻辑——取出原生绑定后直接导出const { pushNotifications } process._linkedBinding(electron_browser_push_notifications); export default pushNotifications;该模块通过 lib/browser/api/module-list.ts 中的{ name: pushNotifications, loader: () require(./push-notifications) }注册为require(electron)的导出属性。C 侧实现shell/browser/api/electron_api_push_notifications.cc 定义了electron::api::PushNotifications类继承gin::Wrappable与EventEmitterMixin并在Initialize中把单例挂到 JS 的exports.pushNotifications上。从源码结构看模块的平台能力有明确边界只有编译目标是 macOS 时GetObjectTemplateBuilder才会注册 APNS 相关方法——#if BUILDFLAG(IS_MAC) builder .SetMethod(registerForAPNSNotifications, PushNotifications::RegisterForAPNSNotifications) .SetMethod(unregisterForAPNSNotifications, PushNotifications::UnregisterForAPNSNotifications); #endif也就是说registerForAPNSNotifications/unregisterForAPNSNotifications这两个方法体位于 shell/browser/api/electron_api_push_notifications_mac.mm非 macOS 平台上调用会因方法未注册而失败。API 文档docs/api/push-notifications.md中每个方法和事件都标注了_macOS_与此源码条件编译完全一致。典型用法注册、上报令牌、接收通知官方文档给出的完整示例是const { pushNotifications, Notification } require(electron) pushNotifications.registerForAPNSNotifications().then((token) { // forward token to your remote notification server }) pushNotifications.on(received-apns-notification, (event, userInfo) { // generate a new Notification object with the relevant userInfo fields })这段代码表达了 APNS 集成的标准两步走先把设备令牌device token转发给自己的远端推送服务器随后监听received-apns-notification事件用推送载荷构造Notification对象呈现给用户。在此基础上结合源码中的错误路径注册失败时 Promise 会被 reject一个更贴近生产的写法是const { pushNotifications, Notification } require(electron) // 1. 注册 APNS成功拿到令牌失败得到可读错误信息 pushNotifications.registerForAPNSNotifications() .then((token) { // token 是小写十六进制字符串见源码剖析一节上报给推送服务器 console.log(APNS device token:, token) // TODO: 通过 HTTPS 上报给远端通知服务器 }) .catch((error) { // 例如网络不可达、无推送权限等导致的注册失败 console.error(APNS registration failed:, error.message) }) // 2. 应用运行期间收到远端推送apns 环境时触发 pushNotifications.on(received-apns-notification, (event, userInfo) { // userInfo 是 RecordString, any通常包含 apns 载荷alert、sound、badge 等 const notification new Notification({ title: New message, body: userInfo.alert || }) notification.show() })注意received-apns-notification的触发条件是“应用处于运行状态时收到远端通知”原文档Emitted when the app receives a remote notification while running。若应用未运行而是由推送唤起则不经过此事件路径。Methods 详解pushNotifications.registerForAPNSNotifications()macOS返回值Promisestring语义将应用注册到 APNS 以接收 Badge、Sound、Alert 类型的远程通知。注册成功时 Promise 以 APNS 设备令牌device tokenresolve失败时以错误消息 reject。从 shell/browser/api/electron_api_push_notifications_mac.mm 的实现可以看到它实际做的事v8::Localv8::Promise PushNotifications::RegisterForAPNSNotifications( v8::Isolate* isolate) { gin_helper::Promisestd::string promise(isolate); v8::Localv8::Promise handle promise.GetHandle(); [[AtomApplication sharedApplication] registerForRemoteNotifications]; apns_promise_set_.emplace_back(std::move(promise)); return handle; }要点有三异步且不可同步得知结果。调用只是转手调用 AppKit 的registerForRemoteNotifications结果由系统稍后经代理回调告知见下节“令牌如何回到 JS”因此 API 形态必然是 Promise。并发调用被安全地合并。头文件 shell/browser/api/electron_api_push_notifications.h 中维护了一个apns_promise_set_std::vectorgin_helper::Promisestd::string注释写明它保存“所有应当在 macOS 完成注册或注册失败后被 fulfill 的 promises”。当系统回调到来时ResolveAPNSPromiseSetWithToken/RejectAPNSPromiseSetWithError会移动并结算整个集合中的每一个 Promise——也就是说在结果到来之前重复调用注册接口多个待决 Promise 都会用同一个令牌 resolve。令牌的具体形态。设备令牌并不是原样透传的NSData。在 shell/browser/mac/electron_application_delegate.mm 中- (void)application:(NSApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { // Resolve outstanding APNS promises created during registration attempts if (auto* push_notifications electron::api::PushNotifications::Get()) { std::string encoded base::HexEncode(electron::util::as_byte_span(deviceToken)); push_notifications-ResolveAPNSPromiseSetWithToken( base::ToLowerASCII(encoded)); } }即返回给 JS 的 token 是设备令牌字节序列的十六进制编码、再转为小写 ASCII 后的字符串base::HexEncodebase::ToLowerASCII。现代 APNS 令牌为 32 字节因此你拿到的将是 64 个十六进制字符的小写字符串服务端存储与比对时应按“小写十六进制”这一形态处理。pushNotifications.unregisterForAPNSNotifications()macOS语义使应用脱离 APNS 的远程通知接收原文档明确说明“通过本方法退订的应用随时可以重新注册”Apps unregistered through this method can always reregister。实现只有一行shell/browser/api/electron_api_push_notifications_mac.mmvoid PushNotifications::UnregisterForAPNSNotifications() { [[AtomApplication sharedApplication] unregisterForRemoteNotifications]; }它直接对应 AppKit 的unregisterForRemoteNotifications。注意该方法不返回 Promise也没有完成回调——退订同样是异步系统行为源码中没有为它挂接任何状态结算逻辑从源码结构看调用方不应假设调用返回即完成。Events 详解received-apns-notificationmacOS参数eventEventuserInfoRecordString, any触发时机应用运行期间收到一条远端推送时。完整链路是AppKit 代理回调 → 模块单例 →EventEmitterMixin::Emit。第一步发生在 shell/browser/mac/electron_application_delegate.mm- (void)application:(NSApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo { if (auto* push_notifications electron::api::PushNotifications::Get()) { push_notifications-OnDidReceiveAPNSNotification( electron::NSDictionaryToValue(userInfo)); } }系统把推送载荷NSDictionary经electron::NSDictionaryToValue转换成base::DictValue后交给模块第二步在 shell/browser/api/electron_api_push_notifications_mac.mmvoid PushNotifications::OnDidReceiveAPNSNotification( const base::DictValue user_info) { Emit(received-apns-notification, user_info); }Emit来自EventEmitterMixin最终在 JS 侧表现为pushNotifications.on(received-apns-notification, (event, userInfo) …)。userInfo的内容就是推送方写入的 APNS 载荷如aps之外的自定义字段、alert、sound等具体以你的推送服务端下发的 JSON 为准这也是文档示例中提示“用相关 userInfo 字段生成新的 Notification 对象”的由来——模块本身不做载荷解析解析与展示完全交给应用代码通常配合 docs/api/notification.md 的NotificationAPI。另外注册失败的路径也值得与事件对照理解didFailToRegisterForRemoteNotificationsWithError:会把 NSError 拼成可读字符串再 reject 所有待决 Promiseshell/browser/mac/electron_application_delegate.mmstd::string error_message(base::SysNSStringToUTF8( [NSString stringWithFormat:%ld % %, error.code, error.domain, error.userInfo]));因此 catch 到的错误消息形如“错误码 错误域 userInfo 字典”的组合排障时可直接从中读出系统层面的失败原因。生命周期与工程注意事项结合上述源码有几点值得在工程实现中注意单例与 Isolate 清理。PushNotifications::Get()使用base::NoDestructorcppgc::PersistentPushNotifications维持跨 JS 上下文的生命周期shell/browser/api/electron_api_push_notifications.cc同时它实现了OnBeforeMicrotasksRunnerDispose在 V8 微任务运行器销毁时执行apns_promise_set_.clear()shell/browser/api/electron_api_push_notifications.cc。可以推断若注册发起后 JS 环境在系统回调到来之前被销毁未结算的 Promise 会被静默丢弃应用不应在 teardown 阶段仍依赖该 Promise 的 then/catch 执行。平台可用性。模块对象本身全平台存在非 Mac 下require(electron).pushNotifications仍可取到 EventEmitter 实例但两个 APNS 方法与received-apns-notification事件仅在 macOS 有意义跨平台代码中应做process.platform darwin之类的判断后再调用。与Notification的分工。pushNotifications只负责“收”展示仍由Notification完成——收到推送后从userInfo取字段构造new Notification({...})再.show()这是文档示例给出的推荐做法。退订可逆。unregisterForAPNSNotifications之后随时可再次registerForAPNSNotifications重新获得可能不同的令牌因此“注销/重登”类流程无需担心一次性资源。参考路径索引内容路径API 文档docs/api/push-notifications.mdJS 模块导出lib/browser/api/push-notifications.ts模块注册表lib/browser/api/module-list.tsC 绑定跨平台骨架shell/browser/api/electron_api_push_notifications.cc类声明与 Promise 集合shell/browser/api/electron_api_push_notifications.hAPNS 方法实现macOSshell/browser/api/electron_api_push_notifications_mac.mm系统代理回调令牌/失败/收推shell/browser/mac/electron_application_delegate.mm本机通知展示docs/api/notification.md【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →