react-native-nitro-ali-push 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +240 -2
  3. package/android/CMakeLists.txt +31 -0
  4. package/android/build.gradle +139 -0
  5. package/android/src/main/AndroidManifest.xml +30 -0
  6. package/android/src/main/java/com/margelo/nitro/alipush/AliPushMessageReceiver.kt +156 -0
  7. package/android/src/main/java/com/margelo/nitro/alipush/HybridAliPushPlugin.kt +303 -0
  8. package/android/src/main/java/com/margelo/nitro/alipush/ThirdPartMessageActivity.kt +26 -0
  9. package/ios/HybridAliPushPlugin.swift +519 -0
  10. package/lib/index.d.ts +195 -0
  11. package/lib/index.js +269 -0
  12. package/lib/specs/AliPushPlugin.nitro.d.ts +88 -0
  13. package/lib/specs/AliPushPlugin.nitro.js +2 -0
  14. package/lib/types.d.ts +111 -0
  15. package/lib/types.js +11 -0
  16. package/nitrogen/generated/.gitattributes +1 -0
  17. package/nitrogen/generated/android/NitroAliPush+autolinking.cmake +84 -0
  18. package/nitrogen/generated/android/NitroAliPush+autolinking.gradle +27 -0
  19. package/nitrogen/generated/android/NitroAliPushOnLoad.cpp +58 -0
  20. package/nitrogen/generated/android/NitroAliPushOnLoad.hpp +34 -0
  21. package/nitrogen/generated/android/c++/JAliPushAppState.hpp +61 -0
  22. package/nitrogen/generated/android/c++/JAliPushMessage.hpp +98 -0
  23. package/nitrogen/generated/android/c++/JAliPushMessageType.hpp +58 -0
  24. package/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
  25. package/nitrogen/generated/android/c++/JFunc_void_AliPushMessage.hpp +87 -0
  26. package/nitrogen/generated/android/c++/JHybridAliPushPluginSpec.cpp +338 -0
  27. package/nitrogen/generated/android/c++/JHybridAliPushPluginSpec.hpp +78 -0
  28. package/nitrogen/generated/android/c++/JVariant_Double_String.cpp +26 -0
  29. package/nitrogen/generated/android/c++/JVariant_Double_String.hpp +68 -0
  30. package/nitrogen/generated/android/c++/JVariant_NullType_AliPushMessage.cpp +26 -0
  31. package/nitrogen/generated/android/c++/JVariant_NullType_AliPushMessage.hpp +80 -0
  32. package/nitrogen/generated/android/c++/JVariant_NullType_String.cpp +26 -0
  33. package/nitrogen/generated/android/c++/JVariant_NullType_String.hpp +70 -0
  34. package/nitrogen/generated/android/kotlin/com/margelo/nitro/alipush/AliPushAppState.kt +24 -0
  35. package/nitrogen/generated/android/kotlin/com/margelo/nitro/alipush/AliPushMessage.kt +91 -0
  36. package/nitrogen/generated/android/kotlin/com/margelo/nitro/alipush/AliPushMessageType.kt +23 -0
  37. package/nitrogen/generated/android/kotlin/com/margelo/nitro/alipush/Func_void.kt +78 -0
  38. package/nitrogen/generated/android/kotlin/com/margelo/nitro/alipush/Func_void_AliPushMessage.kt +78 -0
  39. package/nitrogen/generated/android/kotlin/com/margelo/nitro/alipush/HybridAliPushPluginSpec.kt +123 -0
  40. package/nitrogen/generated/android/kotlin/com/margelo/nitro/alipush/NitroAliPushOnLoad.kt +35 -0
  41. package/nitrogen/generated/android/kotlin/com/margelo/nitro/alipush/Variant_Double_String.kt +62 -0
  42. package/nitrogen/generated/android/kotlin/com/margelo/nitro/alipush/Variant_NullType_AliPushMessage.kt +62 -0
  43. package/nitrogen/generated/android/kotlin/com/margelo/nitro/alipush/Variant_NullType_String.kt +62 -0
  44. package/nitrogen/generated/ios/NitroAliPush+autolinking.rb +62 -0
  45. package/nitrogen/generated/ios/NitroAliPush-Swift-Cxx-Bridge.cpp +89 -0
  46. package/nitrogen/generated/ios/NitroAliPush-Swift-Cxx-Bridge.hpp +531 -0
  47. package/nitrogen/generated/ios/NitroAliPush-Swift-Cxx-Umbrella.hpp +60 -0
  48. package/nitrogen/generated/ios/NitroAliPushAutolinking.mm +33 -0
  49. package/nitrogen/generated/ios/NitroAliPushAutolinking.swift +26 -0
  50. package/nitrogen/generated/ios/c++/HybridAliPushPluginSpecSwift.cpp +11 -0
  51. package/nitrogen/generated/ios/c++/HybridAliPushPluginSpecSwift.hpp +217 -0
  52. package/nitrogen/generated/ios/swift/AliPushAppState.swift +44 -0
  53. package/nitrogen/generated/ios/swift/AliPushMessage.swift +191 -0
  54. package/nitrogen/generated/ios/swift/AliPushMessageType.swift +40 -0
  55. package/nitrogen/generated/ios/swift/Func_void.swift +46 -0
  56. package/nitrogen/generated/ios/swift/Func_void_AliPushMessage.swift +46 -0
  57. package/nitrogen/generated/ios/swift/Func_void_bool.swift +46 -0
  58. package/nitrogen/generated/ios/swift/Func_void_double.swift +46 -0
  59. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
  60. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
  61. package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__AliPushMessage_.swift +58 -0
  62. package/nitrogen/generated/ios/swift/HybridAliPushPluginSpec.swift +70 -0
  63. package/nitrogen/generated/ios/swift/HybridAliPushPluginSpec_cxx.swift +476 -0
  64. package/nitrogen/generated/ios/swift/Variant_Double_String.swift +30 -0
  65. package/nitrogen/generated/ios/swift/Variant_NullType_AliPushMessage.swift +30 -0
  66. package/nitrogen/generated/ios/swift/Variant_NullType_String.swift +30 -0
  67. package/nitrogen/generated/shared/c++/AliPushAppState.hpp +80 -0
  68. package/nitrogen/generated/shared/c++/AliPushMessage.hpp +123 -0
  69. package/nitrogen/generated/shared/c++/AliPushMessageType.hpp +76 -0
  70. package/nitrogen/generated/shared/c++/HybridAliPushPluginSpec.cpp +36 -0
  71. package/nitrogen/generated/shared/c++/HybridAliPushPluginSpec.hpp +85 -0
  72. package/package.json +61 -4
  73. package/react-native-nitro-ali-push.podspec +41 -0
  74. package/src/index.ts +284 -0
  75. package/src/specs/AliPushPlugin.nitro.ts +104 -0
  76. package/src/types.ts +117 -0
@@ -0,0 +1,519 @@
1
+ import Foundation
2
+ import UIKit
3
+ import UserNotifications
4
+ import CloudPushSDK
5
+ import NitroModules
6
+
7
+ /// 通知栏消息类型。
8
+ private let ALIYUN_PUSH_TYPE_NOTIFICATION = "notification"
9
+ /// 透传 / 非通知栏消息类型。
10
+ private let ALIYUN_PUSH_TYPE_MESSAGE = "message"
11
+
12
+ /// Debug 下输出日志(对应原 Objective-C 的 `DLog` 宏)。
13
+ private func DLog(_ message: String, file: String = #file, line: UInt = #line) {
14
+ #if DEBUG
15
+ print("<\((file as NSString).lastPathComponent):\(line)> \(message)")
16
+ #endif
17
+ }
18
+
19
+ /**
20
+ * react-native-nitro-ali-push 的 iOS 原生实现(Swift,Nitro HybridObject)。
21
+ *
22
+ * 通过 `nitrogen` 生成的 `HybridAliPushPluginSpec` 协议暴露给 JS;初始化、APNs 注册、
23
+ * `CloudPushSDK` 回调以及事件分发都在本类完成。
24
+ *
25
+ * iOS 端的推送初始化必须在原生层完成(AppDelegate 调用 `shared.setParams`),而不是
26
+ * 从 JS 调用 `initPush`(该方法在 iOS 上为无操作)。
27
+ */
28
+ /// 必须 `public`:本库作为 pod 是独立模块,App 的 Swift/ObjC 需要引用它。
29
+ /// 仅 `internal` 时不会写进 `<react_native_nitro_ali_push-Swift.h>`,App 端编译报
30
+ /// "Use of undeclared identifier 'HybridAliPushPlugin'"。`@objc` 运行时名保持不变。
31
+ @objc(HybridAliPushPlugin)
32
+ public final class HybridAliPushPlugin: HybridAliPushPluginSpec, UNUserNotificationCenterDelegate {
33
+ /// 由 AppDelegate 创建的权威实例(持有 UNUserNotificationCenter 代理与 CloudPushSDK 回调)。
34
+ private static var sharedInstance: HybridAliPushPlugin?
35
+ /// JS 注册的监听器(静态池,AppDelegate 实例与 JS 实例共享)。
36
+ private static var listeners: [UUID: (AliPushMessage) -> Void] = [:]
37
+ /// App 冷启动(被通知唤起)时、JS 尚未完成订阅的窗口期内到达的首条消息缓存。
38
+ private static var initialNotification: AliPushMessage?
39
+
40
+ // MARK: - 单例(供 AppDelegate 使用)
41
+
42
+ @objc public static func shared() -> HybridAliPushPlugin {
43
+ if let instance = sharedInstance { return instance }
44
+ let instance = HybridAliPushPlugin()
45
+ sharedInstance = instance
46
+ return instance
47
+ }
48
+
49
+ // MARK: - 生命周期 / Nitro 必填
50
+
51
+ override init() {
52
+ super.init()
53
+ }
54
+
55
+ // MARK: - 由原生 AppDelegate 调用完成 iOS 端推送初始化(不应从 JS 调用)
56
+
57
+ @objc public func setParams(_ appKey: String,
58
+ appSecret: String,
59
+ lauchOptions: [AnyHashable: Any]?,
60
+ createNotificationCategoryHandler: @escaping () -> Void) {
61
+ registerAPNs(createNotificationCategoryHandler)
62
+ initCloudPush(appKey: appKey, appSecret: appSecret)
63
+ listenerOnChannelOpened()
64
+ registerMessageReceive()
65
+ CloudPushSDK.sendNotificationAck(lauchOptions)
66
+ }
67
+
68
+ // MARK: - APNs 注册
69
+
70
+ private func registerAPNs(_ createNotificationCategoryHandler: (() -> Void)?) {
71
+ let center = UNUserNotificationCenter.current()
72
+ createNotificationCategoryHandler?()
73
+ center.delegate = self
74
+
75
+ center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
76
+ if granted {
77
+ DLog("User authorized notification.")
78
+ DispatchQueue.main.async {
79
+ UIApplication.shared.registerForRemoteNotifications()
80
+ }
81
+ } else {
82
+ DLog("User denied notification: \(String(describing: error))")
83
+ }
84
+ }
85
+ }
86
+
87
+ // MARK: - SDK 初始化
88
+
89
+ private func initCloudPush(appKey: String, appSecret: String) {
90
+ CloudPushSDK.start(withAppkey: appKey, appSecret: appSecret) { res in
91
+ if res?.success ?? false {
92
+ DLog("Push SDK init success, deviceId: \(String(describing: CloudPushSDK.getDeviceId())).")
93
+ } else {
94
+ DLog("Push SDK init failed, error: \(String(describing: res?.error)).")
95
+ }
96
+ }
97
+ }
98
+
99
+ // MARK: - AppDelegate 转发方法
100
+
101
+ @objc public func application(_ application: UIApplication,
102
+ didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
103
+ CloudPushSDK.registerDevice(deviceToken) { res in
104
+ if res?.success ?? false {
105
+ DLog("Register deviceToken success.")
106
+ } else {
107
+ DLog("Register deviceToken failed, error: \(String(describing: res?.error)).")
108
+ }
109
+ }
110
+ }
111
+
112
+ @objc public func application(_ application: UIApplication,
113
+ didFailToRegisterForRemoteNotificationsWithError error: Error) {
114
+ DLog("Get deviceToken failed, error: \(error.localizedDescription)")
115
+ }
116
+
117
+ @objc public func application(_ application: UIApplication,
118
+ didReceiveRemoteNotification userInfo: [AnyHashable: Any],
119
+ fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
120
+ CloudPushSDK.sendNotificationAck(userInfo)
121
+ completionHandler(.newData)
122
+ }
123
+
124
+ // MARK: - UNUserNotificationCenterDelegate
125
+
126
+ /// App 处于前台时收到通知。
127
+ func userNotificationCenter(_ center: UNUserNotificationCenter,
128
+ willPresent notification: UNNotification,
129
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
130
+ DLog("Receive a notification in foreground.")
131
+ let content = notification.request.content
132
+ let userInfo = content.userInfo
133
+
134
+ var dict: [AnyHashable: Any] = [:]
135
+ dict["date"] = notification.date
136
+ dict["title"] = content.title
137
+ dict["subtitle"] = content.subtitle
138
+ if let body = content.body as String? { dict["body"] = body }
139
+ if let badge = content.badge as? NSNumber { dict["badge"] = badge }
140
+ UIApplication.shared.applicationIconBadgeNumber = content.badge?.intValue ?? 0
141
+ dict["extras"] = userInfo
142
+ dict["type"] = ALIYUN_PUSH_TYPE_NOTIFICATION
143
+
144
+ sendEventToJs(buildMessage(dict))
145
+ CloudPushSDK.sendNotificationAck(userInfo)
146
+
147
+ completionHandler(content.body.isEmpty ? [] : [.sound, .alert, .badge])
148
+ }
149
+
150
+ /// 用户点击 / 删除 / 自定义 action 回调。
151
+ func userNotificationCenter(_ center: UNUserNotificationCenter,
152
+ didReceive response: UNNotificationResponse,
153
+ withCompletionHandler completionHandler: @escaping () -> Void) {
154
+ DLog("Open/delete a notification.")
155
+ let content = response.notification.request.content
156
+ let userInfo = content.userInfo
157
+
158
+ var dict: [AnyHashable: Any] = [:]
159
+ dict["date"] = response.notification.date
160
+ dict["title"] = content.title
161
+ dict["subtitle"] = content.subtitle
162
+ if let body = content.body as String? { dict["body"] = body }
163
+ if let badge = content.badge as? NSNumber { dict["badge"] = badge }
164
+ UIApplication.shared.applicationIconBadgeNumber = content.badge?.intValue ?? 0
165
+ dict["extras"] = userInfo
166
+ dict["type"] = ALIYUN_PUSH_TYPE_NOTIFICATION
167
+
168
+ if response.actionIdentifier == UNNotificationDefaultActionIdentifier {
169
+ dict["actionIdentifier"] = "opened"
170
+ } else if response.actionIdentifier == UNNotificationDismissActionIdentifier {
171
+ dict["actionIdentifier"] = "removed"
172
+ } else {
173
+ dict["actionIdentifier"] = response.actionIdentifier
174
+ }
175
+
176
+ sendEventToJs(buildMessage(dict))
177
+ CloudPushSDK.sendNotificationAck(userInfo)
178
+ completionHandler()
179
+ }
180
+
181
+ // MARK: - 通道 / 消息监听
182
+
183
+ private func listenerOnChannelOpened() {
184
+ NotificationCenter.default.addObserver(
185
+ self,
186
+ selector: #selector(onChannelOpened(_:)),
187
+ name: NSNotification.Name("CCPDidChannelConnectedSuccess"),
188
+ object: nil
189
+ )
190
+ }
191
+
192
+ @objc private func onChannelOpened(_ notification: Notification) {
193
+ DLog("ChannelOpened.")
194
+ }
195
+
196
+ private func registerMessageReceive() {
197
+ NotificationCenter.default.addObserver(
198
+ self,
199
+ selector: #selector(onMessageReceived(_:)),
200
+ name: NSNotification.Name("CCPDidReceiveMessageNotification"),
201
+ object: nil
202
+ )
203
+ }
204
+
205
+ @objc private func onMessageReceived(_ notification: Notification) {
206
+ DLog("onMessageReceived.")
207
+ let data = (notification.object as? [AnyHashable: Any]) ?? [:]
208
+
209
+ var dict: [AnyHashable: Any] = [:]
210
+ if let title = data["title"] { dict["title"] = title }
211
+ if let body = data["body"] { dict["body"] = body }
212
+ dict["extras"] = notification.userInfo ?? [:]
213
+ dict["type"] = ALIYUN_PUSH_TYPE_MESSAGE
214
+
215
+ sendEventToJs(buildMessage(dict))
216
+ }
217
+
218
+ // MARK: - 发送事件
219
+
220
+ /// 把原生字典组装为 `AliPushMessage` 并分发给 JS 监听器(或缓存首条冷启动消息)。
221
+ private func sendEventToJs(_ message: AliPushMessage) {
222
+ DLog("sendEventToJs:")
223
+ var payload = message
224
+ payload = withAppState(payload)
225
+
226
+ if HybridAliPushPlugin.listeners.isEmpty {
227
+ if HybridAliPushPlugin.initialNotification == nil {
228
+ HybridAliPushPlugin.initialNotification = payload
229
+ }
230
+ return
231
+ }
232
+ for listener in HybridAliPushPlugin.listeners.values {
233
+ listener(payload)
234
+ }
235
+ }
236
+
237
+ private func withAppState(_ message: AliPushMessage) -> AliPushMessage {
238
+ let state: AliPushAppState
239
+ switch UIApplication.shared.applicationState {
240
+ case .active: state = .active
241
+ case .inactive: state = .inactive
242
+ case .background: state = .background
243
+ @unknown default: return message
244
+ }
245
+ return AliPushMessage(
246
+ title: message.title,
247
+ subtitle: message.subtitle,
248
+ body: message.body,
249
+ badge: message.badge,
250
+ extras: message.extras,
251
+ type: message.type,
252
+ actionIdentifier: message.actionIdentifier,
253
+ appState: state,
254
+ date: message.date
255
+ )
256
+ }
257
+
258
+ /// 由 `[AnyHashable: Any]` 组装 `AliPushMessage`。
259
+ private func buildMessage(_ dict: [AnyHashable: Any]) -> AliPushMessage {
260
+ let title = dict["title"] as? String
261
+ let subtitle = dict["subtitle"] as? String
262
+ let body = dict["body"] as? String
263
+ let badge = (dict["badge"] as? NSNumber)?.doubleValue
264
+
265
+ var type: AliPushMessageType?
266
+ if let rawType = dict["type"] as? String, let t = AliPushMessageType(fromString: rawType) {
267
+ type = t
268
+ }
269
+ let actionIdentifier = dict["actionIdentifier"] as? String
270
+
271
+ var appState: AliPushAppState?
272
+ if let rawState = dict["appState"] as? String, let s = AliPushAppState(fromString: rawState) {
273
+ appState = s
274
+ }
275
+
276
+ let extras: AnyMap?
277
+ if let rawExtras = dict["extras"] as? [AnyHashable: Any] {
278
+ var safe: [String: Any?] = [:]
279
+ for (k, v) in rawExtras {
280
+ if let key = k as? String {
281
+ safe[key] = v
282
+ }
283
+ }
284
+ extras = (try? AnyMap.fromDictionaryIgnoreIncompatible(safe)) ?? nil
285
+ } else {
286
+ extras = nil
287
+ }
288
+
289
+ let date: Variant_Double_String?
290
+ if let rawDate = dict["date"] as? Date {
291
+ date = .first(rawDate.timeIntervalSince1970)
292
+ } else if let rawDate = dict["date"] as? String {
293
+ date = .second(rawDate)
294
+ } else if let rawDate = dict["date"] as? NSNumber {
295
+ date = .first(rawDate.doubleValue)
296
+ } else {
297
+ date = nil
298
+ }
299
+
300
+ return AliPushMessage(
301
+ title: title,
302
+ subtitle: subtitle,
303
+ body: body,
304
+ badge: badge,
305
+ extras: extras,
306
+ type: type,
307
+ actionIdentifier: actionIdentifier,
308
+ appState: appState,
309
+ date: date
310
+ )
311
+ }
312
+
313
+ // MARK: - 暴露给 JS 的方法
314
+
315
+ func initPush(appKey: String, appSecret: String) throws -> Promise<Void> {
316
+ // iOS 端初始化在 AppDelegate 中完成,这里直接成功。
317
+ return Promise.resolved()
318
+ }
319
+
320
+ func getDeviceId() throws -> Promise<String> {
321
+ return Promise.async {
322
+ if let deviceId = CloudPushSDK.getDeviceId() {
323
+ return deviceId
324
+ } else {
325
+ throw RuntimeError.error(withMessage: "getDeviceId() failed.")
326
+ }
327
+ }
328
+ }
329
+
330
+ func bindAccount(account: String) throws -> Promise<Void> {
331
+ return Promise.async {
332
+ try await withCheckedThrowingContinuation { continuation in
333
+ CloudPushSDK.bindAccount(account, withCallback: { res in
334
+ if let res = res, res.success {
335
+ continuation.resume()
336
+ } else {
337
+ let err = res?.error
338
+ continuation.resume(throwing: RuntimeError.error(
339
+ withMessage: err?.localizedDescription ?? "unknown error"))
340
+ }
341
+ })
342
+ }
343
+ }
344
+ }
345
+
346
+ func unbindAccount() throws -> Promise<Void> {
347
+ return Promise.async {
348
+ try await withCheckedThrowingContinuation { continuation in
349
+ CloudPushSDK.unbindAccount(withCallback: { res in
350
+ if let res = res, res.success {
351
+ continuation.resume()
352
+ } else {
353
+ let err = res?.error
354
+ continuation.resume(throwing: RuntimeError.error(
355
+ withMessage: err?.localizedDescription ?? "unknown error"))
356
+ }
357
+ })
358
+ }
359
+ }
360
+ }
361
+
362
+ func bindTag(target: Double, tags: [String], alias: Variant_NullType_String?) throws -> Promise<Void> {
363
+ let aliasString: String?
364
+ if case .second(let s) = alias {
365
+ aliasString = s
366
+ } else {
367
+ aliasString = nil
368
+ }
369
+ return Promise.async {
370
+ try await withCheckedThrowingContinuation { continuation in
371
+ CloudPushSDK.bindTag(Int(target), withTags: tags, withAlias: aliasString, withCallback: { res in
372
+ if let res = res, res.success {
373
+ continuation.resume()
374
+ } else {
375
+ let err = res?.error
376
+ continuation.resume(throwing: RuntimeError.error(
377
+ withMessage: err?.localizedDescription ?? "unknown error"))
378
+ }
379
+ })
380
+ }
381
+ }
382
+ }
383
+
384
+ func unbindTag(target: Double, tags: [String], alias: Variant_NullType_String?) throws -> Promise<Void> {
385
+ let aliasString: String?
386
+ if case .second(let s) = alias {
387
+ aliasString = s
388
+ } else {
389
+ aliasString = nil
390
+ }
391
+ return Promise.async {
392
+ try await withCheckedThrowingContinuation { continuation in
393
+ CloudPushSDK.unbindTag(Int(target), withTags: tags, withAlias: aliasString, withCallback: { res in
394
+ if let res = res, res.success {
395
+ continuation.resume()
396
+ } else {
397
+ let err = res?.error
398
+ continuation.resume(throwing: RuntimeError.error(
399
+ withMessage: err?.localizedDescription ?? "unknown error"))
400
+ }
401
+ })
402
+ }
403
+ }
404
+ }
405
+
406
+ func listTags(target: Double) throws -> Promise<String> {
407
+ return Promise.async {
408
+ try await withCheckedThrowingContinuation { continuation in
409
+ CloudPushSDK.listTags(Int(target), withCallback: { res in
410
+ if let res = res, res.success {
411
+ continuation.resume(returning: res.data as? String ?? "")
412
+ } else {
413
+ let err = res?.error
414
+ continuation.resume(throwing: RuntimeError.error(
415
+ withMessage: err?.localizedDescription ?? "unknown error"))
416
+ }
417
+ })
418
+ }
419
+ }
420
+ }
421
+
422
+ func addAlias(alias: String) throws -> Promise<Void> {
423
+ return Promise.async {
424
+ try await withCheckedThrowingContinuation { continuation in
425
+ CloudPushSDK.addAlias(alias, withCallback: { res in
426
+ if let res = res, res.success {
427
+ continuation.resume()
428
+ } else {
429
+ let err = res?.error
430
+ continuation.resume(throwing: RuntimeError.error(
431
+ withMessage: err?.localizedDescription ?? "unknown error"))
432
+ }
433
+ })
434
+ }
435
+ }
436
+ }
437
+
438
+ func removeAlias(alias: String) throws -> Promise<Void> {
439
+ return Promise.async {
440
+ try await withCheckedThrowingContinuation { continuation in
441
+ CloudPushSDK.removeAlias(alias, withCallback: { res in
442
+ if let res = res, res.success {
443
+ continuation.resume()
444
+ } else {
445
+ let err = res?.error
446
+ continuation.resume(throwing: RuntimeError.error(
447
+ withMessage: err?.localizedDescription ?? "unknown error"))
448
+ }
449
+ })
450
+ }
451
+ }
452
+ }
453
+
454
+ func listAliases() throws -> Promise<String> {
455
+ return Promise.async {
456
+ try await withCheckedThrowingContinuation { continuation in
457
+ CloudPushSDK.listAliases(withCallback: { res in
458
+ if let res = res, res.success {
459
+ continuation.resume(returning: res.data as? String ?? "")
460
+ } else {
461
+ let err = res?.error
462
+ continuation.resume(throwing: RuntimeError.error(
463
+ withMessage: err?.localizedDescription ?? "unknown error"))
464
+ }
465
+ })
466
+ }
467
+ }
468
+ }
469
+
470
+ func setApplicationIconBadgeNumber(badge: Double) throws -> Promise<Void> {
471
+ return Promise.async {
472
+ UIApplication.shared.applicationIconBadgeNumber = Int(badge)
473
+ }
474
+ }
475
+
476
+ func getApplicationIconBadgeNumber() throws -> Promise<Double> {
477
+ return Promise.resolved(withResult: Double(UIApplication.shared.applicationIconBadgeNumber))
478
+ }
479
+
480
+ func getInitialMessage() throws -> Promise<Variant_NullType_AliPushMessage> {
481
+ if let cached = HybridAliPushPlugin.initialNotification {
482
+ HybridAliPushPlugin.initialNotification = nil
483
+ return Promise.resolved(withResult: .second(cached))
484
+ }
485
+ return Promise.resolved(withResult: .first(NullType.null))
486
+ }
487
+
488
+ func getAuthorizationStatus() throws -> Promise<Bool> {
489
+ return Promise.async {
490
+ try await withCheckedThrowingContinuation { continuation in
491
+ if #available(iOS 10.0, *) {
492
+ UNUserNotificationCenter.current().getNotificationSettings { settings in
493
+ continuation.resume(returning: settings.authorizationStatus == .authorized)
494
+ }
495
+ } else {
496
+ continuation.resume(returning: true)
497
+ }
498
+ }
499
+ }
500
+ }
501
+
502
+ func syncBadgeNum(badge: Double) throws -> Promise<Void> {
503
+ return Promise.async {
504
+ CloudPushSDK.syncBadgeNum(Int(badge))
505
+ }
506
+ }
507
+
508
+ func addListener(listener: @escaping (AliPushMessage) -> Void) throws -> () -> Void {
509
+ let id = UUID()
510
+ HybridAliPushPlugin.listeners[id] = listener
511
+ if let cached = HybridAliPushPlugin.initialNotification {
512
+ HybridAliPushPlugin.initialNotification = nil
513
+ listener(cached)
514
+ }
515
+ return {
516
+ HybridAliPushPlugin.listeners.removeValue(forKey: id)
517
+ }
518
+ }
519
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,195 @@
1
+ import { ALI_PUSH_EVENT } from './types';
2
+ import type { AliPushEvent, AliPushMessage, AliPushTagTarget } from './types';
3
+ /**
4
+ * 初始化阿里云推送。
5
+ *
6
+ * @remarks
7
+ * **Android**:调用此方法并通过 `appKey` / `appSecret` 向阿里云推送服务注册应用,
8
+ * 必须在 `App` 挂载前调用。需要在 `AndroidManifest.xml` 中配置推送 `AppKey` /
9
+ * `AppSecret`(见 README)。
10
+ *
11
+ * **iOS**:推送初始化在原生 `AppDelegate` 中通过 `CloudPushSDK` 完成,此方法在
12
+ * iOS 上为无操作。
13
+ *
14
+ * @param appKey - 阿里云推送控制台分配的 AppKey。
15
+ * @param appSecret - 阿里云推送控制台分配的 AppSecret。
16
+ * @returns 初始化完成的 Promise。
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * await AliPush.initPush('your_app_key', 'your_app_secret');
21
+ * ```
22
+ */
23
+ export declare function initPush(appKey: string, appSecret: string): Promise<void>;
24
+ /**
25
+ * 获取设备唯一标识 `deviceId`。
26
+ *
27
+ * @returns 解析为设备 `deviceId` 字符串的 Promise。
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const deviceId = await AliPush.getDeviceId();
32
+ * console.log(deviceId);
33
+ * ```
34
+ */
35
+ export declare function getDeviceId(): Promise<string>;
36
+ /**
37
+ * 绑定账号。
38
+ *
39
+ * @param account - 待绑定的账号(字符串,长度建议 ≤ 64)。
40
+ * @returns 操作完成的 Promise。
41
+ */
42
+ export declare function bindAccount(account: string): Promise<void>;
43
+ /**
44
+ * 解绑账号(解绑当前已绑定账号)。
45
+ *
46
+ * @returns 操作完成的 Promise。
47
+ */
48
+ export declare function unbindAccount(): Promise<void>;
49
+ /**
50
+ * 绑定标签。
51
+ *
52
+ * @param target - 目标类型:`1` 设备 / `2` 账号 / `3` 别名。
53
+ * @param tags - 标签数组(字符串)。
54
+ * @param alias - 别名(可空,仅 `target = 3` 时生效)。
55
+ * @returns 操作完成的 Promise。
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * await AliPush.bindTag(1, ['news', 'sports'], null);
60
+ * ```
61
+ */
62
+ export declare function bindTag(target: AliPushTagTarget, tags: string[], alias: string | null): Promise<void>;
63
+ /**
64
+ * 解绑标签。参数语义同 {@link bindTag}。
65
+ *
66
+ * @param target - 目标类型:`1` 设备 / `2` 账号 / `3` 别名。
67
+ * @param tags - 待解绑的标签数组。
68
+ * @param alias - 别名(可空)。
69
+ * @returns 操作完成的 Promise。
70
+ */
71
+ export declare function unbindTag(target: AliPushTagTarget, tags: string[], alias: string | null): Promise<void>;
72
+ /**
73
+ * 列出当前已绑定的标签。
74
+ *
75
+ * @param target - 目标类型:`1` 设备 / `2` 账号 / `3` 别名。
76
+ * @returns 解析为服务端响应字符串(含标签列表)的 Promise。
77
+ */
78
+ export declare function listTags(target: AliPushTagTarget): Promise<string>;
79
+ /**
80
+ * 添加别名。
81
+ *
82
+ * @param alias - 待添加的别名。
83
+ * @returns 操作完成的 Promise。
84
+ */
85
+ export declare function addAlias(alias: string): Promise<void>;
86
+ /**
87
+ * 移除别名。
88
+ *
89
+ * @param alias - 待移除的别名。
90
+ * @returns 操作完成的 Promise。
91
+ */
92
+ export declare function removeAlias(alias: string): Promise<void>;
93
+ /**
94
+ * 列出当前已添加的别名。
95
+ *
96
+ * @returns 解析为服务端响应字符串(含别名列表)的 Promise。
97
+ */
98
+ export declare function listAliases(): Promise<string>;
99
+ /**
100
+ * 设置应用角标(桌面图标右上角数字)。
101
+ *
102
+ * @param badge - 角标数字,`0` 表示清除。
103
+ * @returns 操作完成的 Promise。
104
+ */
105
+ export declare function setApplicationIconBadgeNumber(badge: number): Promise<void>;
106
+ /**
107
+ * 获取应用当前角标数字。
108
+ *
109
+ * @returns 解析为当前角标数字的 Promise。
110
+ */
111
+ export declare function getApplicationIconBadgeNumber(): Promise<number>;
112
+ /**
113
+ * 获取 App 冷启动(被通知唤起)时缓存的首条推送消息。
114
+ *
115
+ * @remarks
116
+ * 当 App 完全退出后被通知点击唤起,JS 尚未完成订阅的窗口期内到达的消息会被原生端
117
+ * 缓存,待 JS 就绪后通过此方法或 {@link ALI_PUSH_EVENT} 事件返回。
118
+ *
119
+ * @returns 缓存消息对象,无则 `null`。
120
+ */
121
+ export declare function getInitialMessage(): Promise<AliPushMessage | null>;
122
+ /**
123
+ * 获取 iOS 通知授权状态。
124
+ *
125
+ * @remarks Android 平台固定返回 `true`(Android 不做通知权限前置拦截)。
126
+ *
127
+ * @returns 解析为是否已授权的布尔值 Promise。
128
+ */
129
+ export declare function getAuthorizationStatus(): Promise<boolean>;
130
+ /**
131
+ * 将角标数字同步到阿里云服务端。
132
+ *
133
+ * @remarks 仅 iOS 有效,Android 为无操作。
134
+ *
135
+ * @param badge - 角标数字。
136
+ * @returns 操作完成的 Promise。
137
+ */
138
+ export declare function syncBadgeNum(badge: number): Promise<void>;
139
+ /**
140
+ * 订阅推送消息事件。
141
+ *
142
+ * @param event - 事件名,本库仅支持 {@link ALI_PUSH_EVENT}(`'aliyunPushReceived'`)。
143
+ * @param listener - 回调,参数为 {@link AliPushMessage}。
144
+ * @returns 退订函数,调用即可取消该监听。
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * const unsubscribe = AliPush.addEventListener('aliyunPushReceived', (msg) => {
149
+ * console.log('收到推送', msg.title, msg.body);
150
+ * });
151
+ * // 不再需要时
152
+ * unsubscribe();
153
+ * ```
154
+ */
155
+ export declare function addEventListener(event: AliPushEvent, listener: (message: AliPushMessage) => void): () => void;
156
+ /**
157
+ * 取消订阅推送消息事件。
158
+ *
159
+ * @param unsubscribe - {@link addEventListener} 返回的退订函数。
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * AliPush.removeEventListener(unsubscribe);
164
+ * ```
165
+ */
166
+ export declare function removeEventListener(unsubscribe: () => void): void;
167
+ /**
168
+ * 默认导出对象(同时支持具名与默认导入)。
169
+ *
170
+ * @public
171
+ */
172
+ declare const AliPush: {
173
+ initPush: typeof initPush;
174
+ getDeviceId: typeof getDeviceId;
175
+ bindAccount: typeof bindAccount;
176
+ unbindAccount: typeof unbindAccount;
177
+ bindTag: typeof bindTag;
178
+ unbindTag: typeof unbindTag;
179
+ listTags: typeof listTags;
180
+ addAlias: typeof addAlias;
181
+ removeAlias: typeof removeAlias;
182
+ listAliases: typeof listAliases;
183
+ setApplicationIconBadgeNumber: typeof setApplicationIconBadgeNumber;
184
+ getApplicationIconBadgeNumber: typeof getApplicationIconBadgeNumber;
185
+ getInitialMessage: typeof getInitialMessage;
186
+ getAuthorizationStatus: typeof getAuthorizationStatus;
187
+ syncBadgeNum: typeof syncBadgeNum;
188
+ addEventListener: typeof addEventListener;
189
+ removeEventListener: typeof removeEventListener;
190
+ /** 事件名常量,便于 `addEventListener(AliPush.ALI_PUSH_EVENT, ...)`。 */
191
+ ALI_PUSH_EVENT: "aliyunPushReceived";
192
+ };
193
+ export { ALI_PUSH_EVENT };
194
+ export type { AliPushEvent, AliPushMessage, AliPushTagTarget };
195
+ export default AliPush;