@pushpushgo/react-native-push 0.4.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.
- package/LICENSE +20 -0
- package/PushPushGoRNPush.podspec +22 -0
- package/README.md +412 -0
- package/android/build.gradle +79 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +10 -0
- package/android/src/main/java/com/pushpushgo/bridge/reactnative/push/PushNotificationsActivityCallbacks.kt +36 -0
- package/android/src/main/java/com/pushpushgo/bridge/reactnative/push/PushNotificationsBeaconTranslator.kt +107 -0
- package/android/src/main/java/com/pushpushgo/bridge/reactnative/push/PushNotificationsContentProvider.kt +72 -0
- package/android/src/main/java/com/pushpushgo/bridge/reactnative/push/PushNotificationsError.kt +6 -0
- package/android/src/main/java/com/pushpushgo/bridge/reactnative/push/PushNotificationsModule.kt +54 -0
- package/android/src/main/java/com/pushpushgo/bridge/reactnative/push/PushNotificationsPackage.kt +36 -0
- package/ios/Bridge/PushNotificationsBeaconTranslator.swift +80 -0
- package/ios/Bridge/PushNotificationsModule.h +10 -0
- package/ios/Bridge/PushNotificationsModule.mm +53 -0
- package/ios/Bridge/PushNotificationsModuleDelegate.swift +68 -0
- package/ios/PushNotificationsRN.swift +35 -0
- package/lib/module/beacon/Beacon.js +51 -0
- package/lib/module/beacon/Beacon.js.map +1 -0
- package/lib/module/beacon/BeaconTag.js +32 -0
- package/lib/module/beacon/BeaconTag.js.map +1 -0
- package/lib/module/index.js +37 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/specs/NativePushNotifications.js +5 -0
- package/lib/module/specs/NativePushNotifications.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/beacon/Beacon.d.ts +38 -0
- package/lib/typescript/src/beacon/Beacon.d.ts.map +1 -0
- package/lib/typescript/src/beacon/BeaconTag.d.ts +31 -0
- package/lib/typescript/src/beacon/BeaconTag.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +12 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativePushNotifications.d.ts +22 -0
- package/lib/typescript/src/specs/NativePushNotifications.d.ts.map +1 -0
- package/package.json +168 -0
- package/src/beacon/Beacon.ts +84 -0
- package/src/beacon/BeaconTag.ts +52 -0
- package/src/index.tsx +62 -0
- package/src/specs/NativePushNotifications.ts +25 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 PushPushGo
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "PushPushGoRNPush"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.homepage = package["homepage"]
|
|
10
|
+
s.license = package["license"]
|
|
11
|
+
s.authors = package["author"]
|
|
12
|
+
|
|
13
|
+
s.platforms = { :ios => min_ios_version_supported }
|
|
14
|
+
s.source = { :git => "https://github.com/ppgco/react-native-sdk.git", :tag => "#{s.version}" }
|
|
15
|
+
|
|
16
|
+
s.source_files = "ios/**/*.{h,m,mm,cpp,swift}"
|
|
17
|
+
s.private_header_files = "ios/**/*.h"
|
|
18
|
+
|
|
19
|
+
s.dependency "PPG_framework", ">= 4.2"
|
|
20
|
+
|
|
21
|
+
install_modules_dependencies(s)
|
|
22
|
+
end
|
package/README.md
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
# React Native SDK
|
|
2
|
+
|
|
3
|
+
PushPushGo Push Notifications SDK for React Native. Supports Android (FCM / HMS) and iOS (APNS).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node 22+
|
|
10
|
+
- Android Studio
|
|
11
|
+
- Xcode
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Expo Projects
|
|
16
|
+
|
|
17
|
+
If you are using the Expo Managed workflow, you will need to eject your project to switch to the Expo Bare workflow.
|
|
18
|
+
|
|
19
|
+
Run the following command in your project root:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx expo prebuild
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Android Integration
|
|
28
|
+
|
|
29
|
+
### Preparation
|
|
30
|
+
|
|
31
|
+
1. Remove other push SDKs or custom FCM/HMS implementations.
|
|
32
|
+
2. Connect your app to a push provider.
|
|
33
|
+
3. Prepare provider configuration files:
|
|
34
|
+
- FCM: `google-services.json`
|
|
35
|
+
- HMS: `agconnect-services.json`
|
|
36
|
+
4. Integrate the provider in the PushPushGo app:
|
|
37
|
+
- Project → Settings → Integration
|
|
38
|
+
- See FCM or HMS sections below for details.
|
|
39
|
+
5. Collect your PushPushGo Project ID and API Key.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
### Installation
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npm install @pushpushgo/react-native-push
|
|
47
|
+
# or
|
|
48
|
+
yarn add @pushpushgo/react-native-push
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### FCM (Firebase Cloud Messaging)
|
|
54
|
+
|
|
55
|
+
#### Provider credentials
|
|
56
|
+
|
|
57
|
+
1. Open **Firebase Console**.
|
|
58
|
+
2. Navigate to **Project settings** → **Cloud Messaging**.
|
|
59
|
+
3. Click **Manage service accounts**.
|
|
60
|
+
4. Select your service account email.
|
|
61
|
+
5. Open the **Keys** tab.
|
|
62
|
+
6. Click **Add key** → **Create new key**.
|
|
63
|
+
7. Choose **JSON** format and download the file.
|
|
64
|
+
8. Upload the JSON file in the PushPushGo **FCM** integration section.
|
|
65
|
+
|
|
66
|
+
#### FCM configuration
|
|
67
|
+
|
|
68
|
+
Place `google-services.json` in the app module root:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
android/app/google-services.json
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### Gradle setup
|
|
75
|
+
|
|
76
|
+
```gradle
|
|
77
|
+
// android/build.gradle
|
|
78
|
+
buildscript {
|
|
79
|
+
dependencies {
|
|
80
|
+
classpath("com.google.gms:google-services:4.4.4")
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```gradle
|
|
86
|
+
// android/app/build.gradle
|
|
87
|
+
|
|
88
|
+
apply plugin: 'com.google.gms.google-services'
|
|
89
|
+
|
|
90
|
+
dependencies {
|
|
91
|
+
implementation platform('com.google.firebase:firebase-bom:34.9.0')
|
|
92
|
+
implementation 'com.google.firebase:firebase-messaging'
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### HMS (Huawei Push Kit)
|
|
99
|
+
|
|
100
|
+
#### Provider credentials
|
|
101
|
+
|
|
102
|
+
1. Open **Huawei Developers Console**.
|
|
103
|
+
2. Navigate to your project.
|
|
104
|
+
3. Open **Project settings**.
|
|
105
|
+
4. Collect the required values:
|
|
106
|
+
- `appId`
|
|
107
|
+
- `authUrl`
|
|
108
|
+
- `pushUrl`
|
|
109
|
+
- `appSecret`
|
|
110
|
+
5. Provide these credentials in the PushPushGo **HMS** integration section.
|
|
111
|
+
|
|
112
|
+
#### HMS configuration
|
|
113
|
+
|
|
114
|
+
Place `agconnect-services.json` in the app module root:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
android/app/agconnect-services.json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
#### Gradle setup
|
|
121
|
+
|
|
122
|
+
```gradle
|
|
123
|
+
// android/build.gradle
|
|
124
|
+
buildscript {
|
|
125
|
+
repositories {
|
|
126
|
+
maven {
|
|
127
|
+
url('https://developer.huawei.com/repo/')
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
dependencies {
|
|
132
|
+
classpath('com.huawei.agconnect:agcp:1.9.1.304')
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
allprojects {
|
|
137
|
+
repositories {
|
|
138
|
+
maven {
|
|
139
|
+
url('https://developer.huawei.com/repo/')
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
```gradle
|
|
146
|
+
// android/app/build.gradle
|
|
147
|
+
|
|
148
|
+
apply plugin: 'com.huawei.agconnect'
|
|
149
|
+
|
|
150
|
+
dependencies {
|
|
151
|
+
implementation 'com.huawei.agconnect:agconnect-core:1.9.1.304'
|
|
152
|
+
implementation 'com.huawei.hms:push:6.13.0.300'
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### Android Configuration
|
|
159
|
+
|
|
160
|
+
#### AndroidManifest.xml
|
|
161
|
+
|
|
162
|
+
Add your Project ID and API Key inside `<application>`:
|
|
163
|
+
|
|
164
|
+
```xml
|
|
165
|
+
<meta-data
|
|
166
|
+
android:name="com.pushpushgo.projectId"
|
|
167
|
+
android:value="{projectId}" />
|
|
168
|
+
|
|
169
|
+
<meta-data
|
|
170
|
+
android:name="com.pushpushgo.apiKey"
|
|
171
|
+
android:value="{apiKey}" />
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
#### Handling notification clicks
|
|
175
|
+
|
|
176
|
+
To ensure correct handling of notification taps:
|
|
177
|
+
|
|
178
|
+
1. Set `android:launchMode` to `singleTop` on your activity.
|
|
179
|
+
2. Add the following `intent-filter`.
|
|
180
|
+
|
|
181
|
+
```xml
|
|
182
|
+
<activity android:launchMode="singleTop">
|
|
183
|
+
<intent-filter>
|
|
184
|
+
<action android:name="APP_PUSH_CLICK" />
|
|
185
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
186
|
+
</intent-filter>
|
|
187
|
+
</activity>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Additional info
|
|
191
|
+
|
|
192
|
+
- https://docs.pushpushgo.company/mobile-push/google-android
|
|
193
|
+
- https://docs.pushpushgo.company/mobile-push/huawei-android
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## iOS Integration
|
|
198
|
+
|
|
199
|
+
### 1. Modify Podfile
|
|
200
|
+
|
|
201
|
+
```rb
|
|
202
|
+
# ios/Podfile
|
|
203
|
+
|
|
204
|
+
# Add PPG_framework pod to existing main application target
|
|
205
|
+
target '<application_name>' do
|
|
206
|
+
|
|
207
|
+
pod 'PPG_framework', :git => 'https://github.com/ppgco/ios-sdk.git', :tag => '4.2.0'
|
|
208
|
+
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Add the following code to the post_install section
|
|
212
|
+
post_install do |installer|
|
|
213
|
+
installer.pods_project.targets.each do |target|
|
|
214
|
+
target.build_configurations.each do |config|
|
|
215
|
+
config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'No'
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 2. Install pods
|
|
222
|
+
|
|
223
|
+
Under ios/ directory run `pod install`.
|
|
224
|
+
|
|
225
|
+
### 3. Open workspace
|
|
226
|
+
|
|
227
|
+
Open iOS project in Xcode (`ios/*.xcworkspace`).
|
|
228
|
+
|
|
229
|
+
### 4. Modify AppDelegate
|
|
230
|
+
|
|
231
|
+
```swift
|
|
232
|
+
// ios/<name>/AppDelegate.swift
|
|
233
|
+
|
|
234
|
+
import PushPushGoRNPush
|
|
235
|
+
|
|
236
|
+
public override func application(
|
|
237
|
+
_ application: UIApplication,
|
|
238
|
+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
|
|
239
|
+
) -> Bool {
|
|
240
|
+
// At the beginning of this method, initialize the PushNotificationsRN library
|
|
241
|
+
|
|
242
|
+
PushNotificationsRN.initialize(
|
|
243
|
+
projectId: "<YOUR-PROJECT-ID>",
|
|
244
|
+
apiKey: "<YOUR-API-KEY>",
|
|
245
|
+
appGroupId: "<YOUR-APP-GROUP-ID>"
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
// ...
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Add the following code
|
|
252
|
+
|
|
253
|
+
public override func applicationDidBecomeActive(_ application: UIApplication) {
|
|
254
|
+
PushNotificationsRN.applicationDidBecomeActive()
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
public override func application(
|
|
258
|
+
_ application: UIApplication,
|
|
259
|
+
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
|
|
260
|
+
) {
|
|
261
|
+
PushNotificationsRN.applicationDidRegisterForRemoteNotificationsWithDeviceToken(deviceToken: deviceToken)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
public override func application(
|
|
265
|
+
_ application: UIApplication,
|
|
266
|
+
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
|
|
267
|
+
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
|
|
268
|
+
) {
|
|
269
|
+
PushNotificationsRN.applicationDidReceiveRemoteNotification(userInfo: userInfo, fetchCompletionHandler: completionHandler)
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### 5. Add required capabilities
|
|
274
|
+
|
|
275
|
+
- Click on top item in your project hierarchy
|
|
276
|
+
- Select your project on target list
|
|
277
|
+
- Select `Signing & Capabilities`
|
|
278
|
+
- You can add capability by clicking on `+ Capability` button that is placed under `Signing & Capabilities` button
|
|
279
|
+
- Add `Background Modes` capability unless it is already on your capability list. Then select `Remote notifications`
|
|
280
|
+
- Add `Push notifications` capability unless it is already on your capability list
|
|
281
|
+
- Add `App Groups`. You can use your default app group ID or add new one
|
|
282
|
+
- Make sure that your `Provisioning Profile` has required capabilities. If you didn't add them while creating `Provisioning Profile` for your app you should go to your Apple Developer Center to add them. Then refresh your profile in Xcode project.
|
|
283
|
+
|
|
284
|
+
#### How to add new group to your provisioning profile?
|
|
285
|
+
|
|
286
|
+
- Go to Apple Developers and navigate to Certificates, Identifiers & Profiles. Then go to Identifiers and in the right corner change App IDs to AppGroups. You can add new group here.
|
|
287
|
+
- Now you can go back to Identifiers, choose your app identifier and add AppGroup capability. Remember to check your new group.
|
|
288
|
+
|
|
289
|
+
### 6. Create Notification Service Extension (NSE)
|
|
290
|
+
|
|
291
|
+
- Go to `File -> New -> Target`
|
|
292
|
+
- Select `Notification Service Extension`
|
|
293
|
+
- Choose a suitable name for it
|
|
294
|
+
- Right click on the created NSE and select `Convert To Group`
|
|
295
|
+
- Select your NSE on target list
|
|
296
|
+
- Select `Signing & Capabilities`
|
|
297
|
+
- Click on `+ Capability` button, under `Signing & Capabilities`, and add AppGroup capability with the exact same appGroupId as in the main application target and in the code
|
|
298
|
+
- Modify `Podfile` and add NSE target
|
|
299
|
+
|
|
300
|
+
```rb
|
|
301
|
+
# ios/Podfile
|
|
302
|
+
|
|
303
|
+
# Replace PushPushGoRNNSE with the name of your NSE
|
|
304
|
+
target 'PushPushGoRNNSE' do
|
|
305
|
+
use_modular_headers!
|
|
306
|
+
|
|
307
|
+
pod 'PPG_framework', :git => 'https://github.com/ppgco/ios-sdk.git', :tag => '4.2.0'
|
|
308
|
+
end
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
- In ios/ directory run `pod install`
|
|
312
|
+
- Select your NSE on target list, in `General` > `Frameworks and Libraries` add `libPPG_framework.a`
|
|
313
|
+
- Modify `NotificationService.swift` file in the created NSE and fill in the appGroupId value
|
|
314
|
+
|
|
315
|
+
```swift
|
|
316
|
+
// ios/<NSE>/NotificationService.swift
|
|
317
|
+
|
|
318
|
+
import PPG_framework
|
|
319
|
+
|
|
320
|
+
// replace didReceive function with the following implementation
|
|
321
|
+
override func didReceive(
|
|
322
|
+
_ request: UNNotificationRequest,
|
|
323
|
+
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
|
|
324
|
+
) {
|
|
325
|
+
self.contentHandler = contentHandler
|
|
326
|
+
self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
|
|
327
|
+
|
|
328
|
+
guard let content = bestAttemptContent else { return }
|
|
329
|
+
|
|
330
|
+
// replace with your appGroupId
|
|
331
|
+
SharedData.shared.appGroupId = "<YOUR-APP-GROUP-ID>"
|
|
332
|
+
|
|
333
|
+
let group = DispatchGroup()
|
|
334
|
+
|
|
335
|
+
group.enter()
|
|
336
|
+
PPG.notificationDelivered(notificationRequest: request) { _ in
|
|
337
|
+
group.leave()
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
group.enter()
|
|
341
|
+
DispatchQueue.global().async { [weak self] in
|
|
342
|
+
self?.bestAttemptContent = PPG.modifyNotification(content)
|
|
343
|
+
group.leave()
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
group.notify(queue: .main) {
|
|
347
|
+
contentHandler(self.bestAttemptContent ?? content)
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### 7. Ensure minimum deployment version
|
|
353
|
+
|
|
354
|
+
Ensure that application and NSE targets have the same minimum iOS version requirement - `General` > `Minimum Deployments`.
|
|
355
|
+
|
|
356
|
+
### 8. Additional info
|
|
357
|
+
|
|
358
|
+
- https://docs.pushpushgo.company/mobile-push/apple-ios
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## Usage
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
import { PushNotifications } from '@pushpushgo/react-native-push';
|
|
366
|
+
|
|
367
|
+
PushNotifications.subscribeToNotifications()
|
|
368
|
+
.then((subscriberId) => console.log(`subscriberId: ${subscriberId}`))
|
|
369
|
+
.catch((e) =>
|
|
370
|
+
console.error(`Cannot subscribe to notifications: ${e?.message}`)
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
PushNotifications.unsubscribeFromNotifications()
|
|
374
|
+
.then(() => console.log('Unsubscribed from notifications'))
|
|
375
|
+
.catch((e) =>
|
|
376
|
+
console.error(`Cannot unsubscribe from notifications: ${e?.message}`)
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
PushNotifications.getSubscriberId()
|
|
380
|
+
.then((subscriberId) =>
|
|
381
|
+
console.log(`subscriberId: ${subscriberId ?? 'unsubscribed'}`)
|
|
382
|
+
)
|
|
383
|
+
.catch((e) => console.error(`Cannot get subscriberId: ${e?.message}`));
|
|
384
|
+
|
|
385
|
+
const beacon = Beacon.builder()
|
|
386
|
+
.set('a-flag', true)
|
|
387
|
+
.set('b-flag', 123)
|
|
388
|
+
.set('c-flag', 'hello-world')
|
|
389
|
+
.appendTag(BeaconTag.fromTagAndLabel('my-tag', 'my-label'))
|
|
390
|
+
.appendTag(
|
|
391
|
+
new BeaconTag({
|
|
392
|
+
tag: 'my-tag-2',
|
|
393
|
+
label: 'my-label-2',
|
|
394
|
+
strategy: BeaconTagStrategy.REWRITE,
|
|
395
|
+
ttl: 1000,
|
|
396
|
+
})
|
|
397
|
+
)
|
|
398
|
+
.setCustomId('my-custom-id')
|
|
399
|
+
.assignToGroup('my-group-name') // Assign subscriber to dynamic group
|
|
400
|
+
.unassignFromGroup('my-group-name') // Unassign subscriber from dynamic group
|
|
401
|
+
.build();
|
|
402
|
+
|
|
403
|
+
PushNotifications.sendBeacon(beacon)
|
|
404
|
+
.then(() => console.log('Beacon sent'))
|
|
405
|
+
.catch((e) => `Cannot send beacon: ${e?.message}`);
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## License
|
|
411
|
+
|
|
412
|
+
MIT
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.getExtOrDefault = {name ->
|
|
3
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ReactNativeSdk_' + name]
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
repositories {
|
|
7
|
+
google()
|
|
8
|
+
mavenCentral()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
dependencies {
|
|
12
|
+
classpath "com.android.tools.build:gradle:9.0.0"
|
|
13
|
+
// noinspection DifferentKotlinGradleVersion
|
|
14
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
apply plugin: "com.android.library"
|
|
20
|
+
apply plugin: "kotlin-android"
|
|
21
|
+
apply plugin: "com.facebook.react"
|
|
22
|
+
|
|
23
|
+
def getExtOrIntegerDefault(name) {
|
|
24
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["ReactNativeSdk_" + name]).toInteger()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
android {
|
|
28
|
+
namespace "com.pushpushgo.bridge.reactnative.push"
|
|
29
|
+
|
|
30
|
+
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
31
|
+
|
|
32
|
+
defaultConfig {
|
|
33
|
+
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
34
|
+
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
buildFeatures {
|
|
38
|
+
buildConfig true
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
buildTypes {
|
|
42
|
+
release {
|
|
43
|
+
minifyEnabled false
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
lintOptions {
|
|
48
|
+
disable "GradleCompatible"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
compileOptions {
|
|
52
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
53
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
sourceSets {
|
|
57
|
+
main {
|
|
58
|
+
java.srcDirs += [
|
|
59
|
+
"generated/java",
|
|
60
|
+
"generated/jni"
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
repositories {
|
|
67
|
+
maven { url 'https://jitpack.io' }
|
|
68
|
+
mavenCentral()
|
|
69
|
+
google()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
73
|
+
|
|
74
|
+
dependencies {
|
|
75
|
+
implementation "com.facebook.react:react-android"
|
|
76
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
77
|
+
implementation "com.github.ppgco.android-sdk:sdk:3.1.0"
|
|
78
|
+
implementation 'com.google.guava:guava:33.5.0-android'
|
|
79
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
2
|
+
<application>
|
|
3
|
+
<provider
|
|
4
|
+
android:name="com.pushpushgo.bridge.reactnative.push.PushNotificationsContentProvider"
|
|
5
|
+
android:authorities="${applicationId}.PushPushGoContentProvider"
|
|
6
|
+
android:exported="false"
|
|
7
|
+
android:initOrder="100"
|
|
8
|
+
/>
|
|
9
|
+
</application>
|
|
10
|
+
</manifest>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
package com.pushpushgo.bridge.reactnative.push
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.app.Application.ActivityLifecycleCallbacks
|
|
5
|
+
import android.os.Bundle
|
|
6
|
+
import com.pushpushgo.sdk.PushPushGo
|
|
7
|
+
|
|
8
|
+
internal class PushNotificationsActivityCallbacks : ActivityLifecycleCallbacks {
|
|
9
|
+
override fun onActivityCreated(
|
|
10
|
+
activity: Activity,
|
|
11
|
+
savedInstanceState: Bundle?,
|
|
12
|
+
) {
|
|
13
|
+
if (PushPushGo.isInitialized() && savedInstanceState == null) {
|
|
14
|
+
PushPushGo.getInstance().handleBackgroundNotificationClick(activity.intent)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override fun onActivityResumed(activity: Activity) {
|
|
19
|
+
if (PushPushGo.isInitialized()) {
|
|
20
|
+
PushPushGo.getInstance().handleBackgroundNotificationClick(activity.intent)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override fun onActivityDestroyed(activity: Activity) = Unit
|
|
25
|
+
|
|
26
|
+
override fun onActivityPaused(activity: Activity) = Unit
|
|
27
|
+
|
|
28
|
+
override fun onActivitySaveInstanceState(
|
|
29
|
+
activity: Activity,
|
|
30
|
+
outState: Bundle,
|
|
31
|
+
) = Unit
|
|
32
|
+
|
|
33
|
+
override fun onActivityStarted(activity: Activity) = Unit
|
|
34
|
+
|
|
35
|
+
override fun onActivityStopped(activity: Activity) = Unit
|
|
36
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
package com.pushpushgo.bridge.reactnative.push
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableMap
|
|
4
|
+
import com.facebook.react.bridge.ReadableType
|
|
5
|
+
import com.pushpushgo.sdk.BeaconBuilder
|
|
6
|
+
import com.pushpushgo.sdk.PushPushGo
|
|
7
|
+
|
|
8
|
+
private data class TranslatedBeaconTag(
|
|
9
|
+
val tag: String,
|
|
10
|
+
val label: String,
|
|
11
|
+
val strategy: String,
|
|
12
|
+
val ttl: Int,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
internal class PushNotificationsBeaconTranslator {
|
|
16
|
+
companion object {
|
|
17
|
+
private fun translateSelectors(
|
|
18
|
+
map: ReadableMap,
|
|
19
|
+
beacon: BeaconBuilder,
|
|
20
|
+
) {
|
|
21
|
+
val selectors = map.getMap("selectors")
|
|
22
|
+
val selectorsIterator = selectors?.keySetIterator()
|
|
23
|
+
|
|
24
|
+
while (selectorsIterator?.hasNextKey() == true) {
|
|
25
|
+
val key = selectorsIterator.nextKey()
|
|
26
|
+
val value: Any? =
|
|
27
|
+
when (selectors.getType(key)) {
|
|
28
|
+
ReadableType.String -> selectors.getString(key)
|
|
29
|
+
ReadableType.Number -> selectors.getDouble(key)
|
|
30
|
+
ReadableType.Boolean -> selectors.getBoolean(key)
|
|
31
|
+
else -> throw PushNotificationsError("Unexpected selector value type")
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
value?.let { beacon.set(key, it) }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private fun translateTag(tag: ReadableMap): TranslatedBeaconTag? {
|
|
39
|
+
val name = tag.getString("tag") ?: return null
|
|
40
|
+
val label = tag.getString("label") ?: "default"
|
|
41
|
+
val strategy = tag.getString("strategy") ?: "append"
|
|
42
|
+
val ttl = tag.getInt("ttl")
|
|
43
|
+
|
|
44
|
+
if (strategy != "append" && strategy != "rewrite") {
|
|
45
|
+
throw PushNotificationsError("Unexpected beacon tag strategy")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return TranslatedBeaconTag(
|
|
49
|
+
tag = name,
|
|
50
|
+
label = label,
|
|
51
|
+
strategy = strategy,
|
|
52
|
+
ttl = ttl,
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private fun translateTags(
|
|
57
|
+
map: ReadableMap,
|
|
58
|
+
beacon: BeaconBuilder,
|
|
59
|
+
) {
|
|
60
|
+
val tags = map.getArray("tags") ?: return
|
|
61
|
+
|
|
62
|
+
for (i in 0 until tags.size()) {
|
|
63
|
+
val rawTag = tags.getMap(i) ?: continue
|
|
64
|
+
val tag = translateTag(rawTag) ?: continue
|
|
65
|
+
|
|
66
|
+
beacon.appendTag(
|
|
67
|
+
tag = tag.tag,
|
|
68
|
+
label = tag.label,
|
|
69
|
+
strategy = tag.strategy,
|
|
70
|
+
ttl = tag.ttl,
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private fun translateTagsToDelete(
|
|
76
|
+
map: ReadableMap,
|
|
77
|
+
beacon: BeaconBuilder,
|
|
78
|
+
) {
|
|
79
|
+
val rawTagsToDelete = map.getArray("tagsToDelete") ?: return
|
|
80
|
+
val tagsToDelete = mutableMapOf<String, String>()
|
|
81
|
+
|
|
82
|
+
for (i in 0 until rawTagsToDelete.size()) {
|
|
83
|
+
val rawTag = rawTagsToDelete.getMap(i) ?: continue
|
|
84
|
+
val tag = translateTag(rawTag) ?: continue
|
|
85
|
+
|
|
86
|
+
tagsToDelete[tag.tag] = tag.label
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
beacon.removeTags(tagsToDelete)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fun translate(map: ReadableMap): BeaconBuilder {
|
|
93
|
+
val beacon = PushPushGo.getInstance().createBeacon()
|
|
94
|
+
|
|
95
|
+
translateSelectors(map, beacon)
|
|
96
|
+
translateTags(map, beacon)
|
|
97
|
+
translateTagsToDelete(map, beacon)
|
|
98
|
+
|
|
99
|
+
beacon.setCustomId(map.getString("customId"))
|
|
100
|
+
|
|
101
|
+
map.getString("assignToGroup")?.let { beacon.assignToGroup(it) }
|
|
102
|
+
map.getString("unassignFromGroup")?.let { beacon.unassignFromGroup(it) }
|
|
103
|
+
|
|
104
|
+
return beacon
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|