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

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 +215 -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 +516 -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 +29 -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,516 @@
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
+ @objc(HybridAliPushPlugin)
29
+ class HybridAliPushPlugin: HybridAliPushPluginSpec, UNUserNotificationCenterDelegate {
30
+ /// 由 AppDelegate 创建的权威实例(持有 UNUserNotificationCenter 代理与 CloudPushSDK 回调)。
31
+ private static var sharedInstance: HybridAliPushPlugin?
32
+ /// JS 注册的监听器(静态池,AppDelegate 实例与 JS 实例共享)。
33
+ private static var listeners: [UUID: (AliPushMessage) -> Void] = [:]
34
+ /// App 冷启动(被通知唤起)时、JS 尚未完成订阅的窗口期内到达的首条消息缓存。
35
+ private static var initialNotification: AliPushMessage?
36
+
37
+ // MARK: - 单例(供 AppDelegate 使用)
38
+
39
+ @objc static func shared() -> HybridAliPushPlugin {
40
+ if let instance = sharedInstance { return instance }
41
+ let instance = HybridAliPushPlugin()
42
+ sharedInstance = instance
43
+ return instance
44
+ }
45
+
46
+ // MARK: - 生命周期 / Nitro 必填
47
+
48
+ override init() {
49
+ super.init()
50
+ }
51
+
52
+ // MARK: - 由原生 AppDelegate 调用完成 iOS 端推送初始化(不应从 JS 调用)
53
+
54
+ @objc func setParams(_ appKey: String,
55
+ appSecret: String,
56
+ lauchOptions: [AnyHashable: Any]?,
57
+ createNotificationCategoryHandler: @escaping () -> Void) {
58
+ registerAPNs(createNotificationCategoryHandler)
59
+ initCloudPush(appKey: appKey, appSecret: appSecret)
60
+ listenerOnChannelOpened()
61
+ registerMessageReceive()
62
+ CloudPushSDK.sendNotificationAck(lauchOptions)
63
+ }
64
+
65
+ // MARK: - APNs 注册
66
+
67
+ private func registerAPNs(_ createNotificationCategoryHandler: (() -> Void)?) {
68
+ let center = UNUserNotificationCenter.current()
69
+ createNotificationCategoryHandler?()
70
+ center.delegate = self
71
+
72
+ center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
73
+ if granted {
74
+ DLog("User authorized notification.")
75
+ DispatchQueue.main.async {
76
+ UIApplication.shared.registerForRemoteNotifications()
77
+ }
78
+ } else {
79
+ DLog("User denied notification: \(String(describing: error))")
80
+ }
81
+ }
82
+ }
83
+
84
+ // MARK: - SDK 初始化
85
+
86
+ private func initCloudPush(appKey: String, appSecret: String) {
87
+ CloudPushSDK.start(withAppkey: appKey, appSecret: appSecret) { res in
88
+ if res?.success ?? false {
89
+ DLog("Push SDK init success, deviceId: \(String(describing: CloudPushSDK.getDeviceId())).")
90
+ } else {
91
+ DLog("Push SDK init failed, error: \(String(describing: res?.error)).")
92
+ }
93
+ }
94
+ }
95
+
96
+ // MARK: - AppDelegate 转发方法
97
+
98
+ @objc func application(_ application: UIApplication,
99
+ didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
100
+ CloudPushSDK.registerDevice(deviceToken) { res in
101
+ if res?.success ?? false {
102
+ DLog("Register deviceToken success.")
103
+ } else {
104
+ DLog("Register deviceToken failed, error: \(String(describing: res?.error)).")
105
+ }
106
+ }
107
+ }
108
+
109
+ @objc func application(_ application: UIApplication,
110
+ didFailToRegisterForRemoteNotificationsWithError error: Error) {
111
+ DLog("Get deviceToken failed, error: \(error.localizedDescription)")
112
+ }
113
+
114
+ @objc func application(_ application: UIApplication,
115
+ didReceiveRemoteNotification userInfo: [AnyHashable: Any],
116
+ fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
117
+ CloudPushSDK.sendNotificationAck(userInfo)
118
+ completionHandler(.newData)
119
+ }
120
+
121
+ // MARK: - UNUserNotificationCenterDelegate
122
+
123
+ /// App 处于前台时收到通知。
124
+ func userNotificationCenter(_ center: UNUserNotificationCenter,
125
+ willPresent notification: UNNotification,
126
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
127
+ DLog("Receive a notification in foreground.")
128
+ let content = notification.request.content
129
+ let userInfo = content.userInfo
130
+
131
+ var dict: [AnyHashable: Any] = [:]
132
+ dict["date"] = notification.date
133
+ dict["title"] = content.title
134
+ dict["subtitle"] = content.subtitle
135
+ if let body = content.body as String? { dict["body"] = body }
136
+ if let badge = content.badge as? NSNumber { dict["badge"] = badge }
137
+ UIApplication.shared.applicationIconBadgeNumber = content.badge?.intValue ?? 0
138
+ dict["extras"] = userInfo
139
+ dict["type"] = ALIYUN_PUSH_TYPE_NOTIFICATION
140
+
141
+ sendEventToJs(buildMessage(dict))
142
+ CloudPushSDK.sendNotificationAck(userInfo)
143
+
144
+ completionHandler(content.body.isEmpty ? [] : [.sound, .alert, .badge])
145
+ }
146
+
147
+ /// 用户点击 / 删除 / 自定义 action 回调。
148
+ func userNotificationCenter(_ center: UNUserNotificationCenter,
149
+ didReceive response: UNNotificationResponse,
150
+ withCompletionHandler completionHandler: @escaping () -> Void) {
151
+ DLog("Open/delete a notification.")
152
+ let content = response.notification.request.content
153
+ let userInfo = content.userInfo
154
+
155
+ var dict: [AnyHashable: Any] = [:]
156
+ dict["date"] = response.notification.date
157
+ dict["title"] = content.title
158
+ dict["subtitle"] = content.subtitle
159
+ if let body = content.body as String? { dict["body"] = body }
160
+ if let badge = content.badge as? NSNumber { dict["badge"] = badge }
161
+ UIApplication.shared.applicationIconBadgeNumber = content.badge?.intValue ?? 0
162
+ dict["extras"] = userInfo
163
+ dict["type"] = ALIYUN_PUSH_TYPE_NOTIFICATION
164
+
165
+ if response.actionIdentifier == UNNotificationDefaultActionIdentifier {
166
+ dict["actionIdentifier"] = "opened"
167
+ } else if response.actionIdentifier == UNNotificationDismissActionIdentifier {
168
+ dict["actionIdentifier"] = "removed"
169
+ } else {
170
+ dict["actionIdentifier"] = response.actionIdentifier
171
+ }
172
+
173
+ sendEventToJs(buildMessage(dict))
174
+ CloudPushSDK.sendNotificationAck(userInfo)
175
+ completionHandler()
176
+ }
177
+
178
+ // MARK: - 通道 / 消息监听
179
+
180
+ private func listenerOnChannelOpened() {
181
+ NotificationCenter.default.addObserver(
182
+ self,
183
+ selector: #selector(onChannelOpened(_:)),
184
+ name: NSNotification.Name("CCPDidChannelConnectedSuccess"),
185
+ object: nil
186
+ )
187
+ }
188
+
189
+ @objc private func onChannelOpened(_ notification: Notification) {
190
+ DLog("ChannelOpened.")
191
+ }
192
+
193
+ private func registerMessageReceive() {
194
+ NotificationCenter.default.addObserver(
195
+ self,
196
+ selector: #selector(onMessageReceived(_:)),
197
+ name: NSNotification.Name("CCPDidReceiveMessageNotification"),
198
+ object: nil
199
+ )
200
+ }
201
+
202
+ @objc private func onMessageReceived(_ notification: Notification) {
203
+ DLog("onMessageReceived.")
204
+ let data = (notification.object as? [AnyHashable: Any]) ?? [:]
205
+
206
+ var dict: [AnyHashable: Any] = [:]
207
+ if let title = data["title"] { dict["title"] = title }
208
+ if let body = data["body"] { dict["body"] = body }
209
+ dict["extras"] = notification.userInfo ?? [:]
210
+ dict["type"] = ALIYUN_PUSH_TYPE_MESSAGE
211
+
212
+ sendEventToJs(buildMessage(dict))
213
+ }
214
+
215
+ // MARK: - 发送事件
216
+
217
+ /// 把原生字典组装为 `AliPushMessage` 并分发给 JS 监听器(或缓存首条冷启动消息)。
218
+ private func sendEventToJs(_ message: AliPushMessage) {
219
+ DLog("sendEventToJs:")
220
+ var payload = message
221
+ payload = withAppState(payload)
222
+
223
+ if HybridAliPushPlugin.listeners.isEmpty {
224
+ if HybridAliPushPlugin.initialNotification == nil {
225
+ HybridAliPushPlugin.initialNotification = payload
226
+ }
227
+ return
228
+ }
229
+ for listener in HybridAliPushPlugin.listeners.values {
230
+ listener(payload)
231
+ }
232
+ }
233
+
234
+ private func withAppState(_ message: AliPushMessage) -> AliPushMessage {
235
+ let state: AliPushAppState
236
+ switch UIApplication.shared.applicationState {
237
+ case .active: state = .active
238
+ case .inactive: state = .inactive
239
+ case .background: state = .background
240
+ @unknown default: return message
241
+ }
242
+ return AliPushMessage(
243
+ title: message.title,
244
+ subtitle: message.subtitle,
245
+ body: message.body,
246
+ badge: message.badge,
247
+ extras: message.extras,
248
+ type: message.type,
249
+ actionIdentifier: message.actionIdentifier,
250
+ appState: state,
251
+ date: message.date
252
+ )
253
+ }
254
+
255
+ /// 由 `[AnyHashable: Any]` 组装 `AliPushMessage`。
256
+ private func buildMessage(_ dict: [AnyHashable: Any]) -> AliPushMessage {
257
+ let title = dict["title"] as? String
258
+ let subtitle = dict["subtitle"] as? String
259
+ let body = dict["body"] as? String
260
+ let badge = (dict["badge"] as? NSNumber)?.doubleValue
261
+
262
+ var type: AliPushMessageType?
263
+ if let rawType = dict["type"] as? String, let t = AliPushMessageType(fromString: rawType) {
264
+ type = t
265
+ }
266
+ let actionIdentifier = dict["actionIdentifier"] as? String
267
+
268
+ var appState: AliPushAppState?
269
+ if let rawState = dict["appState"] as? String, let s = AliPushAppState(fromString: rawState) {
270
+ appState = s
271
+ }
272
+
273
+ let extras: AnyMap?
274
+ if let rawExtras = dict["extras"] as? [AnyHashable: Any] {
275
+ var safe: [String: Any?] = [:]
276
+ for (k, v) in rawExtras {
277
+ if let key = k as? String {
278
+ safe[key] = v
279
+ }
280
+ }
281
+ extras = (try? AnyMap.fromDictionaryIgnoreIncompatible(safe)) ?? nil
282
+ } else {
283
+ extras = nil
284
+ }
285
+
286
+ let date: Variant_Double_String?
287
+ if let rawDate = dict["date"] as? Date {
288
+ date = .first(rawDate.timeIntervalSince1970)
289
+ } else if let rawDate = dict["date"] as? String {
290
+ date = .second(rawDate)
291
+ } else if let rawDate = dict["date"] as? NSNumber {
292
+ date = .first(rawDate.doubleValue)
293
+ } else {
294
+ date = nil
295
+ }
296
+
297
+ return AliPushMessage(
298
+ title: title,
299
+ subtitle: subtitle,
300
+ body: body,
301
+ badge: badge,
302
+ extras: extras,
303
+ type: type,
304
+ actionIdentifier: actionIdentifier,
305
+ appState: appState,
306
+ date: date
307
+ )
308
+ }
309
+
310
+ // MARK: - 暴露给 JS 的方法
311
+
312
+ func initPush(appKey: String, appSecret: String) throws -> Promise<Void> {
313
+ // iOS 端初始化在 AppDelegate 中完成,这里直接成功。
314
+ return Promise.resolved()
315
+ }
316
+
317
+ func getDeviceId() throws -> Promise<String> {
318
+ return Promise.async {
319
+ if let deviceId = CloudPushSDK.getDeviceId() {
320
+ return deviceId
321
+ } else {
322
+ throw RuntimeError.error(withMessage: "getDeviceId() failed.")
323
+ }
324
+ }
325
+ }
326
+
327
+ func bindAccount(account: String) throws -> Promise<Void> {
328
+ return Promise.async {
329
+ try await withCheckedThrowingContinuation { continuation in
330
+ CloudPushSDK.bindAccount(account, withCallback: { res in
331
+ if let res = res, res.success {
332
+ continuation.resume()
333
+ } else {
334
+ let err = res?.error
335
+ continuation.resume(throwing: RuntimeError.error(
336
+ withMessage: err?.localizedDescription ?? "unknown error"))
337
+ }
338
+ })
339
+ }
340
+ }
341
+ }
342
+
343
+ func unbindAccount() throws -> Promise<Void> {
344
+ return Promise.async {
345
+ try await withCheckedThrowingContinuation { continuation in
346
+ CloudPushSDK.unbindAccount(withCallback: { res in
347
+ if let res = res, res.success {
348
+ continuation.resume()
349
+ } else {
350
+ let err = res?.error
351
+ continuation.resume(throwing: RuntimeError.error(
352
+ withMessage: err?.localizedDescription ?? "unknown error"))
353
+ }
354
+ })
355
+ }
356
+ }
357
+ }
358
+
359
+ func bindTag(target: Double, tags: [String], alias: Variant_NullType_String?) throws -> Promise<Void> {
360
+ let aliasString: String?
361
+ if case .second(let s) = alias {
362
+ aliasString = s
363
+ } else {
364
+ aliasString = nil
365
+ }
366
+ return Promise.async {
367
+ try await withCheckedThrowingContinuation { continuation in
368
+ CloudPushSDK.bindTag(Int(target), withTags: tags, withAlias: aliasString, withCallback: { res in
369
+ if let res = res, res.success {
370
+ continuation.resume()
371
+ } else {
372
+ let err = res?.error
373
+ continuation.resume(throwing: RuntimeError.error(
374
+ withMessage: err?.localizedDescription ?? "unknown error"))
375
+ }
376
+ })
377
+ }
378
+ }
379
+ }
380
+
381
+ func unbindTag(target: Double, tags: [String], alias: Variant_NullType_String?) throws -> Promise<Void> {
382
+ let aliasString: String?
383
+ if case .second(let s) = alias {
384
+ aliasString = s
385
+ } else {
386
+ aliasString = nil
387
+ }
388
+ return Promise.async {
389
+ try await withCheckedThrowingContinuation { continuation in
390
+ CloudPushSDK.unbindTag(Int(target), withTags: tags, withAlias: aliasString, withCallback: { res in
391
+ if let res = res, res.success {
392
+ continuation.resume()
393
+ } else {
394
+ let err = res?.error
395
+ continuation.resume(throwing: RuntimeError.error(
396
+ withMessage: err?.localizedDescription ?? "unknown error"))
397
+ }
398
+ })
399
+ }
400
+ }
401
+ }
402
+
403
+ func listTags(target: Double) throws -> Promise<String> {
404
+ return Promise.async {
405
+ try await withCheckedThrowingContinuation { continuation in
406
+ CloudPushSDK.listTags(Int(target), withCallback: { res in
407
+ if let res = res, res.success {
408
+ continuation.resume(returning: res.data as? String ?? "")
409
+ } else {
410
+ let err = res?.error
411
+ continuation.resume(throwing: RuntimeError.error(
412
+ withMessage: err?.localizedDescription ?? "unknown error"))
413
+ }
414
+ })
415
+ }
416
+ }
417
+ }
418
+
419
+ func addAlias(alias: String) throws -> Promise<Void> {
420
+ return Promise.async {
421
+ try await withCheckedThrowingContinuation { continuation in
422
+ CloudPushSDK.addAlias(alias, withCallback: { res in
423
+ if let res = res, res.success {
424
+ continuation.resume()
425
+ } else {
426
+ let err = res?.error
427
+ continuation.resume(throwing: RuntimeError.error(
428
+ withMessage: err?.localizedDescription ?? "unknown error"))
429
+ }
430
+ })
431
+ }
432
+ }
433
+ }
434
+
435
+ func removeAlias(alias: String) throws -> Promise<Void> {
436
+ return Promise.async {
437
+ try await withCheckedThrowingContinuation { continuation in
438
+ CloudPushSDK.removeAlias(alias, withCallback: { res in
439
+ if let res = res, res.success {
440
+ continuation.resume()
441
+ } else {
442
+ let err = res?.error
443
+ continuation.resume(throwing: RuntimeError.error(
444
+ withMessage: err?.localizedDescription ?? "unknown error"))
445
+ }
446
+ })
447
+ }
448
+ }
449
+ }
450
+
451
+ func listAliases() throws -> Promise<String> {
452
+ return Promise.async {
453
+ try await withCheckedThrowingContinuation { continuation in
454
+ CloudPushSDK.listAliases(withCallback: { res in
455
+ if let res = res, res.success {
456
+ continuation.resume(returning: res.data as? String ?? "")
457
+ } else {
458
+ let err = res?.error
459
+ continuation.resume(throwing: RuntimeError.error(
460
+ withMessage: err?.localizedDescription ?? "unknown error"))
461
+ }
462
+ })
463
+ }
464
+ }
465
+ }
466
+
467
+ func setApplicationIconBadgeNumber(badge: Double) throws -> Promise<Void> {
468
+ return Promise.async {
469
+ UIApplication.shared.applicationIconBadgeNumber = Int(badge)
470
+ }
471
+ }
472
+
473
+ func getApplicationIconBadgeNumber() throws -> Promise<Double> {
474
+ return Promise.resolved(withResult: Double(UIApplication.shared.applicationIconBadgeNumber))
475
+ }
476
+
477
+ func getInitialMessage() throws -> Promise<Variant_NullType_AliPushMessage> {
478
+ if let cached = HybridAliPushPlugin.initialNotification {
479
+ HybridAliPushPlugin.initialNotification = nil
480
+ return Promise.resolved(withResult: .second(cached))
481
+ }
482
+ return Promise.resolved(withResult: .first(NullType.null))
483
+ }
484
+
485
+ func getAuthorizationStatus() throws -> Promise<Bool> {
486
+ return Promise.async {
487
+ try await withCheckedThrowingContinuation { continuation in
488
+ if #available(iOS 10.0, *) {
489
+ UNUserNotificationCenter.current().getNotificationSettings { settings in
490
+ continuation.resume(returning: settings.authorizationStatus == .authorized)
491
+ }
492
+ } else {
493
+ continuation.resume(returning: true)
494
+ }
495
+ }
496
+ }
497
+ }
498
+
499
+ func syncBadgeNum(badge: Double) throws -> Promise<Void> {
500
+ return Promise.async {
501
+ CloudPushSDK.syncBadgeNum(Int(badge))
502
+ }
503
+ }
504
+
505
+ func addListener(listener: @escaping (AliPushMessage) -> Void) throws -> () -> Void {
506
+ let id = UUID()
507
+ HybridAliPushPlugin.listeners[id] = listener
508
+ if let cached = HybridAliPushPlugin.initialNotification {
509
+ HybridAliPushPlugin.initialNotification = nil
510
+ listener(cached)
511
+ }
512
+ return {
513
+ HybridAliPushPlugin.listeners.removeValue(forKey: id)
514
+ }
515
+ }
516
+ }
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;