react-native-qpush 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 (98) hide show
  1. package/README.md +439 -2
  2. package/android/build.gradle +77 -0
  3. package/android/gradle.properties +5 -0
  4. package/android/proguard-rules.pro +5 -0
  5. package/android/src/main/AndroidManifest.xml +29 -0
  6. package/android/src/main/java/com/qpush/reactnative/QPushDeviceInfo.kt +96 -0
  7. package/android/src/main/java/com/qpush/reactnative/QPushEventBus.kt +153 -0
  8. package/android/src/main/java/com/qpush/reactnative/QPushFcm.kt +108 -0
  9. package/android/src/main/java/com/qpush/reactnative/QPushHttp.kt +92 -0
  10. package/android/src/main/java/com/qpush/reactnative/QPushImages.kt +103 -0
  11. package/android/src/main/java/com/qpush/reactnative/QPushLog.kt +39 -0
  12. package/android/src/main/java/com/qpush/reactnative/QPushMessagingService.kt +77 -0
  13. package/android/src/main/java/com/qpush/reactnative/QPushNotificationOpenActivity.kt +121 -0
  14. package/android/src/main/java/com/qpush/reactnative/QPushNotificationRenderer.kt +256 -0
  15. package/android/src/main/java/com/qpush/reactnative/QPushPayload.kt +114 -0
  16. package/android/src/main/java/com/qpush/reactnative/QPushPushModule.kt +368 -0
  17. package/android/src/main/java/com/qpush/reactnative/QPushPushPackage.kt +15 -0
  18. package/android/src/main/java/com/qpush/reactnative/QPushStore.kt +108 -0
  19. package/android/src/main/res/values/qpush_strings.xml +6 -0
  20. package/app.plugin.js +1 -0
  21. package/ios/Extension/QPushNotificationServiceExtension.swift +261 -0
  22. package/ios/Extension/QPushPushExtension.podspec +34 -0
  23. package/ios/QPushPush.m +62 -0
  24. package/ios/QPushPush.swift +186 -0
  25. package/ios/QPushPushBridge.h +5 -0
  26. package/ios/QPushPushCore.swift +457 -0
  27. package/ios/QPushPushHooks.m +237 -0
  28. package/ios/QPushPushSupport.swift +249 -0
  29. package/ios_nse_template/Info.plist +38 -0
  30. package/ios_nse_template/NotificationService.entitlements +10 -0
  31. package/ios_nse_template/NotificationService.swift +44 -0
  32. package/lib/NativeQPushPush.d.ts +44 -0
  33. package/lib/NativeQPushPush.js +4 -0
  34. package/lib/QPush.d.ts +117 -0
  35. package/lib/QPush.js +206 -0
  36. package/lib/core/QPushCore.d.ts +148 -0
  37. package/lib/core/QPushCore.js +1387 -0
  38. package/lib/core/constants.d.ts +37 -0
  39. package/lib/core/constants.js +40 -0
  40. package/lib/core/events.d.ts +11 -0
  41. package/lib/core/events.js +40 -0
  42. package/lib/core/http.d.ts +41 -0
  43. package/lib/core/http.js +123 -0
  44. package/lib/core/logger.d.ts +18 -0
  45. package/lib/core/logger.js +43 -0
  46. package/lib/core/operationQueue.d.ts +117 -0
  47. package/lib/core/operationQueue.js +264 -0
  48. package/lib/core/operations.d.ts +80 -0
  49. package/lib/core/operations.js +88 -0
  50. package/lib/core/payload.d.ts +20 -0
  51. package/lib/core/payload.js +187 -0
  52. package/lib/core/platform.d.ts +72 -0
  53. package/lib/core/platform.js +7 -0
  54. package/lib/core/state.d.ts +51 -0
  55. package/lib/core/state.js +74 -0
  56. package/lib/core/storage.d.ts +34 -0
  57. package/lib/core/storage.js +68 -0
  58. package/lib/core/subscription.d.ts +67 -0
  59. package/lib/core/subscription.js +98 -0
  60. package/lib/core/tags.d.ts +39 -0
  61. package/lib/core/tags.js +123 -0
  62. package/lib/core/url.d.ts +17 -0
  63. package/lib/core/url.js +64 -0
  64. package/lib/core/uuid.d.ts +2 -0
  65. package/lib/core/uuid.js +18 -0
  66. package/lib/index.d.ts +7 -0
  67. package/lib/index.js +15 -0
  68. package/lib/notification.d.ts +67 -0
  69. package/lib/notification.js +73 -0
  70. package/lib/reactNativePlatform.d.ts +3 -0
  71. package/lib/reactNativePlatform.js +164 -0
  72. package/lib/types.d.ts +157 -0
  73. package/lib/types.js +31 -0
  74. package/package.json +70 -4
  75. package/plugin/withQPush.js +330 -0
  76. package/react-native-qpush.podspec +30 -0
  77. package/react-native.config.js +18 -0
  78. package/src/NativeQPushPush.ts +57 -0
  79. package/src/QPush.ts +292 -0
  80. package/src/core/QPushCore.ts +1515 -0
  81. package/src/core/constants.ts +42 -0
  82. package/src/core/events.ts +34 -0
  83. package/src/core/http.ts +146 -0
  84. package/src/core/logger.ts +42 -0
  85. package/src/core/operationQueue.ts +324 -0
  86. package/src/core/operations.ts +166 -0
  87. package/src/core/payload.ts +175 -0
  88. package/src/core/platform.ts +84 -0
  89. package/src/core/state.ts +127 -0
  90. package/src/core/storage.ts +76 -0
  91. package/src/core/subscription.ts +133 -0
  92. package/src/core/tags.ts +116 -0
  93. package/src/core/url.ts +58 -0
  94. package/src/core/uuid.ts +13 -0
  95. package/src/index.ts +23 -0
  96. package/src/notification.ts +113 -0
  97. package/src/reactNativePlatform.ts +172 -0
  98. package/src/types.ts +174 -0
@@ -0,0 +1,249 @@
1
+ import Foundation
2
+ import UIKit
3
+
4
+ // MARK: - Logging
5
+
6
+ /// Leveled logger using the same numeric levels as the JS `LogLevel` enum.
7
+ enum QPushLog {
8
+ static var level: Int = 3 // Warn
9
+
10
+ static func error(_ message: @autoclosure () -> String) { log(2, "ERROR", message()) }
11
+ static func warn(_ message: @autoclosure () -> String) { log(3, "WARN", message()) }
12
+ static func info(_ message: @autoclosure () -> String) { log(4, "INFO", message()) }
13
+ static func debug(_ message: @autoclosure () -> String) { log(5, "DEBUG", message()) }
14
+
15
+ private static func log(_ threshold: Int, _ tag: String, _ message: String) {
16
+ guard level >= threshold else { return }
17
+ NSLog("[QPush] %@: %@", tag, message)
18
+ }
19
+ }
20
+
21
+ // MARK: - Storage
22
+
23
+ /// Key/value storage shared with the JS layer. `app_id`, `server_url` and
24
+ /// `subscription_id` are mirrored into the App Group `group.{bundle_id}.qpush`
25
+ /// so the Notification Service Extension can read them.
26
+ final class QPushStorage {
27
+ static let shared = QPushStorage()
28
+
29
+ static let appIdKey = "app_id"
30
+ static let serverUrlKey = "server_url"
31
+ static let subscriptionIdKey = "subscription_id"
32
+ static let sharedKeys: Set<String> = [appIdKey, serverUrlKey, subscriptionIdKey]
33
+
34
+ private static let autoOpenUrlsKey = "qpush_native_auto_open_urls"
35
+ /// Info.plist switch (Boolean) disabling URL opening on notification tap.
36
+ private static let suppressLaunchUrlsPlistKey = "QPush_suppress_launch_urls"
37
+ /// Optional Info.plist override of the App Group name.
38
+ static let appGroupPlistKey = "QPushAppGroup"
39
+
40
+ private let defaults: UserDefaults
41
+ private let appGroupDefaults: UserDefaults?
42
+
43
+ private init() {
44
+ defaults = UserDefaults(suiteName: "com.qpush.sdk.storage") ?? UserDefaults.standard
45
+ appGroupDefaults = UserDefaults(suiteName: QPushStorage.appGroupName())
46
+ // Mirror existing values (e.g. the App Group was added after install).
47
+ for key in QPushStorage.sharedKeys {
48
+ if let value = defaults.string(forKey: key), appGroupDefaults?.string(forKey: key) != value {
49
+ appGroupDefaults?.set(value, forKey: key)
50
+ }
51
+ }
52
+ }
53
+
54
+ /// `group.{main app bundle id}.qpush`, overridable with `QPushAppGroup` in Info.plist.
55
+ static func appGroupName() -> String {
56
+ if let custom = Bundle.main.object(forInfoDictionaryKey: appGroupPlistKey) as? String, !custom.isEmpty {
57
+ return custom
58
+ }
59
+ let bundleId = Bundle.main.bundleIdentifier ?? ""
60
+ return "group.\(bundleId).qpush"
61
+ }
62
+
63
+ func string(_ key: String) -> String? {
64
+ return defaults.string(forKey: key)
65
+ }
66
+
67
+ func set(_ value: String, forKey key: String) {
68
+ defaults.set(value, forKey: key)
69
+ if QPushStorage.sharedKeys.contains(key) {
70
+ appGroupDefaults?.set(value, forKey: key)
71
+ }
72
+ }
73
+
74
+ func remove(_ key: String) {
75
+ defaults.removeObject(forKey: key)
76
+ if QPushStorage.sharedKeys.contains(key) {
77
+ appGroupDefaults?.removeObject(forKey: key)
78
+ }
79
+ }
80
+
81
+ var autoOpenUrls: Bool {
82
+ get {
83
+ if defaults.object(forKey: QPushStorage.autoOpenUrlsKey) != nil {
84
+ return defaults.bool(forKey: QPushStorage.autoOpenUrlsKey)
85
+ }
86
+ let suppress = Bundle.main.object(forInfoDictionaryKey: QPushStorage.suppressLaunchUrlsPlistKey) as? Bool ?? false
87
+ return !suppress
88
+ }
89
+ set {
90
+ defaults.set(newValue, forKey: QPushStorage.autoOpenUrlsKey)
91
+ }
92
+ }
93
+ }
94
+
95
+ // MARK: - HTTP
96
+
97
+ /// Native calls that do not need the JS runtime (notification open / receipt).
98
+ enum QPushHTTP {
99
+ static let sdkVersion = "qpush-react-native/1.0.0"
100
+ private static let deviceTypeIOS = 0
101
+ private static let maxAttempts = 3
102
+
103
+ static func reportReceived(notificationId: String) {
104
+ guard var body = baseBody() else { return }
105
+ body["device_type"] = deviceTypeIOS
106
+ put(path: "/notifications/\(encode(notificationId))/report_received", body: body, attempt: 1)
107
+ }
108
+
109
+ static func reportOpened(notificationId: String, actionId: String?) {
110
+ guard var body = baseBody() else { return }
111
+ body["opened"] = true
112
+ body["device_type"] = deviceTypeIOS
113
+ if let actionId = actionId, !actionId.isEmpty { body["action_id"] = actionId }
114
+ put(path: "/notifications/\(encode(notificationId))", body: body, attempt: 1)
115
+ }
116
+
117
+ private static func encode(_ segment: String) -> String {
118
+ var allowed = CharacterSet.urlPathAllowed
119
+ allowed.remove(charactersIn: "/")
120
+ return segment.addingPercentEncoding(withAllowedCharacters: allowed) ?? segment
121
+ }
122
+
123
+ static func trimTrailingSlashes(_ value: String) -> String {
124
+ var result = value
125
+ while result.hasSuffix("/") { result.removeLast() }
126
+ return result
127
+ }
128
+
129
+ private static func baseBody() -> [String: Any]? {
130
+ let storage = QPushStorage.shared
131
+ guard let appId = storage.string(QPushStorage.appIdKey), !appId.isEmpty else {
132
+ QPushLog.warn("Cannot report notification event: SDK was never initialized")
133
+ return nil
134
+ }
135
+ var body: [String: Any] = ["app_id": appId]
136
+ if let subscriptionId = storage.string(QPushStorage.subscriptionIdKey) {
137
+ body["subscription_id"] = subscriptionId
138
+ }
139
+ return body
140
+ }
141
+
142
+ private static func put(path: String, body: [String: Any], attempt: Int) {
143
+ let storage = QPushStorage.shared
144
+ guard let base = storage.string(QPushStorage.serverUrlKey), !base.isEmpty,
145
+ let url = URL(string: QPushHTTP.trimTrailingSlashes(base) + path),
146
+ let data = try? JSONSerialization.data(withJSONObject: body, options: [])
147
+ else { return }
148
+
149
+ var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 15)
150
+ request.httpMethod = "PUT"
151
+ request.httpBody = data
152
+ request.setValue("application/json", forHTTPHeaderField: "Content-Type")
153
+ request.setValue("application/json", forHTTPHeaderField: "Accept")
154
+ request.setValue(sdkVersion, forHTTPHeaderField: "SDK-Version")
155
+ if let subscriptionId = storage.string(QPushStorage.subscriptionIdKey) {
156
+ request.setValue(subscriptionId, forHTTPHeaderField: "QPush-Subscription-Id")
157
+ }
158
+
159
+ URLSession.shared.dataTask(with: request) { _, response, error in
160
+ let status = (response as? HTTPURLResponse)?.statusCode ?? 0
161
+ QPushLog.debug("PUT \(path) -> \(status)")
162
+ let retryable = error != nil || status == 429 || status >= 500
163
+ if retryable && attempt < QPushHTTP.maxAttempts {
164
+ DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(attempt)) {
165
+ QPushHTTP.put(path: path, body: body, attempt: attempt + 1)
166
+ }
167
+ }
168
+ }.resume()
169
+ }
170
+ }
171
+
172
+ // MARK: - Device info
173
+
174
+ enum QPushDeviceInfo {
175
+ static func collect() -> [String: Any] {
176
+ var info: [String: Any] = ["platform": "ios"]
177
+ info["deviceModel"] = modelIdentifier()
178
+ info["deviceOs"] = UIDevice.current.systemVersion
179
+ if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String {
180
+ info["appVersion"] = version
181
+ }
182
+ info["timezone"] = TimeZone.current.identifier
183
+ let locale = Locale.preferredLanguages.first ?? Locale.current.identifier
184
+ info["locale"] = locale
185
+ if let language = locale.split(whereSeparator: { $0 == "-" || $0 == "_" }).first {
186
+ info["language"] = String(language).lowercased()
187
+ }
188
+ if let country = regionCode() { info["country"] = country }
189
+ info["rooted"] = false
190
+ if let testType = provisioningTestType() {
191
+ info["testType"] = testType
192
+ } else {
193
+ info["testType"] = NSNull()
194
+ }
195
+ return info
196
+ }
197
+
198
+ private static func regionCode() -> String? {
199
+ if #available(iOS 16.0, *) {
200
+ return Locale.current.region?.identifier
201
+ }
202
+ return Locale.current.regionCode
203
+ }
204
+
205
+ /// `iPhone15,2`-style identifier (simulator: the simulated model).
206
+ static func modelIdentifier() -> String {
207
+ if let simulated = ProcessInfo.processInfo.environment["SIMULATOR_MODEL_IDENTIFIER"] {
208
+ return simulated
209
+ }
210
+ var systemInfo = utsname()
211
+ uname(&systemInfo)
212
+ let mirror = Mirror(reflecting: systemInfo.machine)
213
+ let identifier = mirror.children.reduce(into: "") { result, element in
214
+ guard let value = element.value as? Int8, value != 0 else { return }
215
+ result.append(Character(UnicodeScalar(UInt8(value))))
216
+ }
217
+ return identifier.isEmpty ? UIDevice.current.model : identifier
218
+ }
219
+
220
+ /// `1` development (sandbox APNs), `2` ad-hoc, `nil` App Store / TestFlight / enterprise.
221
+ static func provisioningTestType() -> Int? {
222
+ #if targetEnvironment(simulator)
223
+ return 1
224
+ #else
225
+ guard let path = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision"),
226
+ let data = FileManager.default.contents(atPath: path),
227
+ let content = String(data: data, encoding: .isoLatin1),
228
+ let start = content.range(of: "<?xml"),
229
+ let end = content.range(of: "</plist>")
230
+ else {
231
+ return nil
232
+ }
233
+ let plistText = String(content[start.lowerBound..<end.upperBound])
234
+ guard let plistData = plistText.data(using: .isoLatin1),
235
+ let plist = (try? PropertyListSerialization.propertyList(from: plistData, options: [], format: nil)) as? [String: Any]
236
+ else {
237
+ return nil
238
+ }
239
+ let entitlements = plist["Entitlements"] as? [String: Any]
240
+ if let environment = entitlements?["aps-environment"] as? String, environment == "development" {
241
+ return 1
242
+ }
243
+ if plist["ProvisionedDevices"] != nil {
244
+ return 2
245
+ }
246
+ return nil
247
+ #endif
248
+ }
249
+ }
@@ -0,0 +1,38 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
7
+ <key>CFBundleDisplayName</key>
8
+ <string>QPushNotificationServiceExtension</string>
9
+ <key>CFBundleExecutable</key>
10
+ <string>$(EXECUTABLE_NAME)</string>
11
+ <key>CFBundleIdentifier</key>
12
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13
+ <key>CFBundleInfoDictionaryVersion</key>
14
+ <string>6.0</string>
15
+ <key>CFBundleName</key>
16
+ <string>$(PRODUCT_NAME)</string>
17
+ <key>CFBundlePackageType</key>
18
+ <string>XPC!</string>
19
+ <key>CFBundleShortVersionString</key>
20
+ <string>{{VERSION}}</string>
21
+ <key>CFBundleVersion</key>
22
+ <string>{{BUILD_NUMBER}}</string>
23
+ <key>QPushAppGroup</key>
24
+ <string>{{APP_GROUP}}</string>
25
+ <key>NSExtension</key>
26
+ <dict>
27
+ <key>NSExtensionPointIdentifier</key>
28
+ <string>com.apple.usernotifications.service</string>
29
+ <key>NSExtensionPrincipalClass</key>
30
+ <string>$(PRODUCT_MODULE_NAME).NotificationService</string>
31
+ </dict>
32
+ <key>NSAppTransportSecurity</key>
33
+ <dict>
34
+ <key>NSAllowsLocalNetworking</key>
35
+ <true/>
36
+ </dict>
37
+ </dict>
38
+ </plist>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>com.apple.security.application-groups</key>
6
+ <array>
7
+ <string>{{APP_GROUP}}</string>
8
+ </array>
9
+ </dict>
10
+ </plist>
@@ -0,0 +1,44 @@
1
+ import UserNotifications
2
+
3
+ // Provided by the `QPushPushExtension` pod. If you prefer not to use the pod,
4
+ // add `QPushNotificationServiceExtension.swift` (from
5
+ // node_modules/react-native-qpush/ios/Extension/) to this target instead.
6
+ #if canImport(QPushPushExtension)
7
+ import QPushPushExtension
8
+ #endif
9
+
10
+ class NotificationService: UNNotificationServiceExtension {
11
+ var contentHandler: ((UNNotificationContent) -> Void)?
12
+ var receivedRequest: UNNotificationRequest!
13
+ var bestAttemptContent: UNMutableNotificationContent?
14
+
15
+ override func didReceive(
16
+ _ request: UNNotificationRequest,
17
+ withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
18
+ ) {
19
+ self.receivedRequest = request
20
+ self.contentHandler = contentHandler
21
+ self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
22
+
23
+ guard let bestAttemptContent = bestAttemptContent else {
24
+ contentHandler(request.content)
25
+ return
26
+ }
27
+
28
+ // Customize `bestAttemptContent` here if you need to, then let QPush
29
+ // attach the image, register the action buttons and confirm delivery.
30
+ QPushNotificationServiceExtension.didReceiveNotificationExtensionRequest(
31
+ request,
32
+ with: bestAttemptContent,
33
+ withContentHandler: contentHandler
34
+ )
35
+ }
36
+
37
+ override func serviceExtensionTimeWillExpire() {
38
+ // Called just before the extension is terminated: deliver what we have.
39
+ guard let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent else { return }
40
+ if QPushNotificationServiceExtension.serviceExtensionTimeWillExpireRequest(receivedRequest, with: bestAttemptContent) {
41
+ contentHandler(bestAttemptContent)
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * TurboModule spec of the native module `QPushPush`.
3
+ *
4
+ * The native implementations are classic bridge modules
5
+ * (`ReactContextBaseJavaModule` / `RCTEventEmitter`). They work on the old
6
+ * architecture and, through React Native's interop layer, on the New
7
+ * Architecture / bridgeless mode. This spec documents the contract and gives
8
+ * typed access through `TurboModuleRegistry` (which falls back to
9
+ * `NativeModules` on the old architecture). Codegen is intentionally not
10
+ * configured in package.json, so no generated code is required at build time.
11
+ */
12
+ import type { TurboModule } from 'react-native';
13
+ export interface Spec extends TurboModule {
14
+ getItem(key: string): Promise<string | null>;
15
+ setItem(key: string, value: string): Promise<void>;
16
+ removeItem(key: string): Promise<void>;
17
+ /** DeviceInfo (see src/core/subscription.ts). */
18
+ getDeviceInfo(): Promise<Object>;
19
+ /**
20
+ * Android: FCM params from android_params.js (or null for the default
21
+ * FirebaseApp). iOS: ignored. Resolves `{ token, notificationTypes?, error? }`.
22
+ */
23
+ registerForPush(fcmParams: Object | null): Promise<Object>;
24
+ /** 'notDetermined' | 'denied' | 'granted' | 'provisional' | 'ephemeral' */
25
+ getPermissionStatus(): Promise<string>;
26
+ requestPermission(fallbackToSettings: boolean): Promise<boolean>;
27
+ registerForProvisionalAuthorization(): Promise<boolean>;
28
+ canRequestPermission(): Promise<boolean>;
29
+ clearAll(): void;
30
+ removeNotification(notificationId: string): void;
31
+ removeGroupedNotifications(groupKey: string): void;
32
+ clearBadge(): Promise<number>;
33
+ setJsReady(): void;
34
+ displayForegroundNotification(displayId: string): void;
35
+ preventForegroundDisplay(displayId: string): void;
36
+ setAutoOpenUrls(enabled: boolean): void;
37
+ setLogLevel(level: number): void;
38
+ beginBackgroundTask(): Promise<number>;
39
+ endBackgroundTask(taskId: number): void;
40
+ addListener(eventName: string): void;
41
+ removeListeners(count: number): void;
42
+ }
43
+ declare const _default: Spec | null;
44
+ export default _default;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const react_native_1 = require("react-native");
4
+ exports.default = react_native_1.TurboModuleRegistry.get('QPushPush');
package/lib/QPush.d.ts ADDED
@@ -0,0 +1,117 @@
1
+ import { QPushCore } from './core/QPushCore';
2
+ import type { PlatformAdapter } from './core/platform';
3
+ import type { NotificationClickEvent, NotificationWillDisplayEvent } from './notification';
4
+ import type { QPushInitOptions, LogLevel, NotificationPermission, PushSubscriptionChangedState, UserChangedState } from './types';
5
+ /** Events of `QPush.Notifications.addEventListener`. */
6
+ export interface NotificationEventTypeMap {
7
+ click: NotificationClickEvent;
8
+ foregroundWillDisplay: NotificationWillDisplayEvent;
9
+ permissionChange: boolean;
10
+ }
11
+ export type NotificationEventName = keyof NotificationEventTypeMap;
12
+ /** Events of `QPush.User.pushSubscription.addEventListener`. */
13
+ export interface PushSubscriptionEventTypeMap {
14
+ change: PushSubscriptionChangedState;
15
+ }
16
+ /** Events of `QPush.User.addEventListener`. */
17
+ export interface UserEventTypeMap {
18
+ change: UserChangedState;
19
+ }
20
+ /** @internal Testing hook: replaces the platform used by the singleton. */
21
+ export declare function __setPlatformFactoryForTests(factory: () => PlatformAdapter): QPushCore;
22
+ /**
23
+ * QPush SDK entry point.
24
+ *
25
+ * ```ts
26
+ * QPush.initialize('APP_ID'); // qpush cloud: https://qpush.dev/api/v1
27
+ * await QPush.Notifications.requestPermission(true);
28
+ * QPush.login('user-123');
29
+ * ```
30
+ */
31
+ export declare const QPush: {
32
+ /**
33
+ * Initializes the SDK. Call once, as early as possible (e.g. in index.js or
34
+ * your root component). Safe to call API methods right after it.
35
+ */
36
+ initialize(appId: string, options?: QPushInitOptions): void;
37
+ /** Identifies the current user with your user id (`external_id`). */
38
+ login(externalId: string): void;
39
+ /** Detaches the device from the identified user (a new anonymous user is created). */
40
+ logout(): void;
41
+ /** When `true`, nothing is sent until `setConsentGiven(true)`. Call before `initialize`. */
42
+ setConsentRequired(required: boolean): void;
43
+ setConsentGiven(given: boolean): void;
44
+ Debug: {
45
+ /** Sets the SDK log level (JS console and native logs). */
46
+ setLogLevel(level: LogLevel): void;
47
+ };
48
+ Notifications: {
49
+ /**
50
+ * Shows the OS permission prompt (Android 13+ / iOS). With
51
+ * `fallbackToSettings`, opens the app notification settings when the
52
+ * prompt can no longer be shown (permission permanently denied).
53
+ */
54
+ requestPermission(fallbackToSettings?: boolean): Promise<boolean>;
55
+ /** `true` when the app can currently display notifications. */
56
+ getPermissionAsync(): Promise<boolean>;
57
+ /** Detailed native permission state. */
58
+ permissionNative(): Promise<NotificationPermission>;
59
+ /** `true` when calling `requestPermission` would show the OS prompt. */
60
+ canRequestPermission(): Promise<boolean>;
61
+ /** iOS 12+: quiet "provisional" authorization without a prompt. Android: same as getPermissionAsync. */
62
+ registerForProvisionalAuthorization(): Promise<boolean>;
63
+ addEventListener<K extends NotificationEventName>(event: K, listener: (event: NotificationEventTypeMap[K]) => void): void;
64
+ removeEventListener<K extends NotificationEventName>(event: K, listener: (event: NotificationEventTypeMap[K]) => void): void;
65
+ /** Removes every QPush notification from the notification center and clears the badge. */
66
+ clearAll(): void;
67
+ /** Removes a single notification by its QPush notification id. */
68
+ removeNotification(notificationId: string): void;
69
+ /** Removes the notifications of a group (Android group / iOS thread-id). */
70
+ removeGroupedNotifications(groupKey: string): void;
71
+ /**
72
+ * Enables / disables opening the notification URL on tap (default enabled).
73
+ * Persisted natively, so it also applies to cold-start taps on next launches.
74
+ * Build-time switch: Android manifest meta-data `com.qpush.suppressLaunchURLs`
75
+ * / iOS Info.plist `QPush_suppress_launch_urls`.
76
+ */
77
+ setAutoOpenUrls(enabled: boolean): void;
78
+ };
79
+ User: {
80
+ pushSubscription: {
81
+ /** Subscription id of this device, `null` until the server created it. */
82
+ getIdAsync(): Promise<string | null>;
83
+ /** FCM token (Android) / hex APNs token (iOS). */
84
+ getTokenAsync(): Promise<string | null>;
85
+ /** `true` when the device can receive pushes (permission + token + not opted out). */
86
+ getOptedInAsync(): Promise<boolean>;
87
+ /** Re-enables pushes; prompts for permission when it was never asked. */
88
+ optIn(): void;
89
+ /** Disables pushes for this device without touching the OS permission. */
90
+ optOut(): void;
91
+ addEventListener<K extends keyof PushSubscriptionEventTypeMap>(_event: K, listener: (event: PushSubscriptionEventTypeMap[K]) => void): void;
92
+ removeEventListener<K extends keyof PushSubscriptionEventTypeMap>(_event: K, listener: (event: PushSubscriptionEventTypeMap[K]) => void): void;
93
+ };
94
+ /** Adds or updates a tag. Values are stored as strings. */
95
+ addTag(key: string, value: string | number | boolean): void;
96
+ addTags(tags: Record<string, string | number | boolean>): void;
97
+ removeTag(key: string): void;
98
+ removeTags(keys: string[]): void;
99
+ /** Local copy of the user's tags (refreshed from the server on app start and login). */
100
+ getTags(): Promise<Record<string, string>>;
101
+ /** Adds a custom alias (e.g. `crm_id`). Use `QPush.login` for `external_id`. */
102
+ addAlias(label: string, id: string): void;
103
+ addAliases(aliases: Record<string, string>): void;
104
+ removeAlias(label: string): void;
105
+ removeAliases(labels: string[]): void;
106
+ /** ISO 639-1 language code, e.g. `pt`. Defaults to the device language. */
107
+ setLanguage(language: string): void;
108
+ /** QPush user id (`qpush_id`), `null` until the server created the user. */
109
+ getQPushId(): Promise<string | null>;
110
+ /** Alias of `getQPushId` for code migrated from OneSignal. */
111
+ getOnesignalId(): Promise<string | null>;
112
+ getExternalId(): Promise<string | null>;
113
+ addEventListener<K extends keyof UserEventTypeMap>(_event: K, listener: (event: UserEventTypeMap[K]) => void): void;
114
+ removeEventListener<K extends keyof UserEventTypeMap>(_event: K, listener: (event: UserEventTypeMap[K]) => void): void;
115
+ };
116
+ };
117
+ export type QPushType = typeof QPush;