appambit-push-notifications 0.3.1 → 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.
- package/AppAmbitSdkPushNotifications.podspec +14 -4
- package/README.md +184 -105
- package/android/build.gradle +21 -3
- package/android/src/main/AndroidManifest.xml +107 -1
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitContextHolder.kt +22 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitHeadlessService.kt +177 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitInitProvider.kt +73 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitMessagingService.kt +12 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitNotificationSerializer.kt +88 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitPayloadUtils.kt +59 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitPushEventEmitter.kt +100 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitRNServiceExtension.kt +75 -0
- package/android/src/main/java/com/appambitpushnotifications/AppAmbitRemoteMessageStore.kt +26 -0
- package/android/src/main/java/com/appambitpushnotifications/AppambitPushNotificationsModule.kt +377 -76
- package/ios/AppAmbitNotificationSwizzler.m +290 -0
- package/ios/AppAmbitPushWrapper.swift +165 -25
- package/ios/AppAmbitRNNotificationService.swift +46 -0
- package/ios/AppambitPushNotifications.mm +264 -10
- package/lib/module/NativeAppambitPushNotifications.js.map +1 -1
- package/lib/module/index.js +46 -10
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeAppambitPushNotifications.d.ts +2 -1
- package/lib/typescript/src/NativeAppambitPushNotifications.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +32 -6
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NativeAppambitPushNotifications.ts +7 -1
- package/src/index.tsx +93 -20
|
@@ -13,10 +13,20 @@ Pod::Spec.new do |s|
|
|
|
13
13
|
s.platforms = { :ios => min_ios_version_supported }
|
|
14
14
|
s.source = { :git => "https://github.com/AppAmbit/appambit-sdk-react-native.git", :tag => "#{s.version}" }
|
|
15
15
|
|
|
16
|
-
s.
|
|
17
|
-
s.private_header_files = "ios/**/*.h"
|
|
16
|
+
s.default_subspec = 'Core'
|
|
18
17
|
|
|
19
|
-
s.
|
|
18
|
+
s.subspec 'Core' do |core|
|
|
19
|
+
core.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
|
|
20
|
+
core.exclude_files = "ios/AppAmbitRNNotificationService.swift"
|
|
21
|
+
core.private_header_files = "ios/**/*.h"
|
|
22
|
+
core.frameworks = 'Network'
|
|
23
|
+
core.dependency 'AppAmbitPushNotifications', '~> 1.0.0'
|
|
24
|
+
core.dependency 'AppAmbitSdk'
|
|
25
|
+
install_modules_dependencies(core)
|
|
26
|
+
end
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
s.subspec 'Extension' do |ext|
|
|
29
|
+
ext.source_files = "ios/AppAmbitRNNotificationService.swift"
|
|
30
|
+
ext.dependency 'AppAmbitPushNotifications', '~> 1.0.0'
|
|
31
|
+
end
|
|
22
32
|
end
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Seamlessly integrate push notifications with your AppAmbit analytics.**
|
|
4
4
|
|
|
5
|
-
This SDK is an extension of the core AppAmbit
|
|
5
|
+
This SDK is an extension of the core AppAmbit SDK, providing a simple and powerful way to handle Firebase Cloud Messaging (FCM) notifications on both Android and iOS.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -13,203 +13,282 @@ This SDK is an extension of the core AppAmbit Android SDK, providing a simple an
|
|
|
13
13
|
* [Install](#install)
|
|
14
14
|
* [Quickstart](#quickstart)
|
|
15
15
|
* [Usage](#usage)
|
|
16
|
-
* [
|
|
16
|
+
* [Native Implementation Setup](#native-implementation-setup)
|
|
17
|
+
* [Android Setup](#android-setup)
|
|
18
|
+
* [iOS Setup](#ios-setup)
|
|
19
|
+
* [iOS Notification Service Extension (Rich Notifications)](#ios-notification-service-extension-rich-notifications)
|
|
17
20
|
|
|
18
21
|
---
|
|
19
22
|
|
|
20
23
|
## Features
|
|
21
24
|
|
|
25
|
+
* **Zero-Config iOS**: No AppDelegate changes required — the SDK wires itself up automatically via method swizzling.
|
|
22
26
|
* **Simple Setup**: Integrates in minutes.
|
|
23
27
|
* **Enable/Disable Notifications**: Easily manage user preferences at both the business and FCM level.
|
|
24
|
-
* **
|
|
25
|
-
* **
|
|
26
|
-
* **
|
|
27
|
-
* **
|
|
28
|
+
* **Robust Event Listeners**: Separate callbacks for Foreground and Opened (tapped) notifications on both platforms, Background listener is Android-only.
|
|
29
|
+
* **Android Headless JS Support**: Handle background notifications via React Native Headless JS tasks even when the app is completely closed.
|
|
30
|
+
* **Automatic Field Handling**: Automatically uses standard FCM payload fields like `color`, `icon`, `channel_id`, `click_action`, and rich images.
|
|
31
|
+
* **Rich Media Support**: Full iOS Notification Service Extension support for rich payloads, badges, and media attachments.
|
|
32
|
+
* **Permission Helpers**: Utilities to request and check the `POST_NOTIFICATIONS` permission.
|
|
28
33
|
|
|
29
34
|
---
|
|
30
35
|
|
|
31
36
|
## Requirements
|
|
32
37
|
|
|
33
|
-
* **AppAmbit Core SDK**:
|
|
34
|
-
* **Firebase Project**: A configured Firebase project
|
|
35
|
-
* Android API level 21 (Lollipop) or newer.
|
|
38
|
+
* **AppAmbit Core SDK**: Requires the core `appambit` SDK to be installed and configured.
|
|
39
|
+
* **Firebase Project**: A configured Firebase project with `google-services.json` (Android) and `GoogleService-Info.plist` (iOS) in your application.
|
|
40
|
+
* **OS Versions**: Android API level 21 (Lollipop) or newer / iOS 13.0 or newer.
|
|
36
41
|
|
|
37
42
|
---
|
|
38
43
|
|
|
39
44
|
## Install
|
|
40
|
-
To install the library from NPM, run the following commands in your project directory:
|
|
41
45
|
|
|
42
46
|
```bash
|
|
43
47
|
npm install appambit
|
|
44
|
-
&
|
|
45
48
|
npm install appambit-push-notifications
|
|
46
49
|
```
|
|
47
50
|
|
|
48
|
-
|
|
51
|
+
### Android Dependencies
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
Add the following to your Gradle files. Your app is responsible for providing the Firebase BOM and Firebase Messaging to ensure version compatibility.
|
|
51
54
|
|
|
52
|
-
**`android/app/build.gradle
|
|
55
|
+
**`android/app/build.gradle`** (Groovy)
|
|
53
56
|
```groovy
|
|
54
57
|
apply plugin: "com.google.gms.google-services"
|
|
55
58
|
|
|
56
59
|
dependencies {
|
|
57
|
-
|
|
58
|
-
implementation
|
|
59
|
-
implementation ("com.google.firebase:firebase-messaging:23.4.0")
|
|
60
|
+
implementation platform('com.google.firebase:firebase-bom:33.1.2')
|
|
61
|
+
implementation 'com.google.firebase:firebase-messaging:23.4.0'
|
|
60
62
|
}
|
|
61
63
|
```
|
|
62
|
-
|
|
64
|
+
|
|
65
|
+
**`android/build.gradle`** (Groovy)
|
|
63
66
|
```groovy
|
|
64
67
|
dependencies {
|
|
65
68
|
classpath("com.google.gms:google-services:4.3.15")
|
|
66
69
|
}
|
|
67
70
|
```
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
<details>
|
|
73
|
+
<summary>Kotlin DSL</summary>
|
|
74
|
+
|
|
75
|
+
**`android/app/build.gradle.kts`**
|
|
76
|
+
```kotlin
|
|
77
|
+
apply(plugin = "com.google.gms.google-services")
|
|
73
78
|
|
|
74
79
|
dependencies {
|
|
75
|
-
|
|
76
|
-
implementation
|
|
77
|
-
implementation 'com.google.firebase:firebase-messaging:23.4.0'
|
|
80
|
+
implementation(platform("com.google.firebase:firebase-bom:33.1.2"))
|
|
81
|
+
implementation("com.google.firebase:firebase-messaging:23.4.0")
|
|
78
82
|
}
|
|
79
83
|
```
|
|
80
84
|
|
|
81
|
-
**`android/build.gradle`**
|
|
82
|
-
```
|
|
85
|
+
**`android/build.gradle.kts`**
|
|
86
|
+
```kotlin
|
|
83
87
|
dependencies {
|
|
84
88
|
classpath("com.google.gms:google-services:4.3.15")
|
|
85
89
|
}
|
|
86
90
|
```
|
|
91
|
+
</details>
|
|
87
92
|
|
|
88
|
-
|
|
93
|
+
### iOS Dependencies
|
|
94
|
+
|
|
95
|
+
After installing the npm package, run:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
cd ios && pod install
|
|
99
|
+
```
|
|
89
100
|
|
|
90
101
|
---
|
|
91
102
|
|
|
92
103
|
## Quickstart
|
|
93
104
|
|
|
94
|
-
|
|
105
|
+
In your `App.tsx` (or application entry point), initialize both SDKs in order:
|
|
95
106
|
|
|
96
107
|
```javascript
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
108
|
+
import * as AppAmbit from "appambit";
|
|
109
|
+
import * as PushNotifications from "appambit-push-notifications";
|
|
110
|
+
|
|
111
|
+
AppAmbit.start("<YOUR-APPKEY>");
|
|
112
|
+
PushNotifications.start();
|
|
113
|
+
PushNotifications.requestNotificationPermission();
|
|
101
114
|
```
|
|
102
115
|
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Usage
|
|
103
119
|
|
|
104
|
-
|
|
120
|
+
### Event Listeners
|
|
105
121
|
|
|
106
|
-
|
|
107
|
-
AppAmbit.start("<YOUR-APPKEY>");
|
|
108
|
-
```
|
|
122
|
+
All listeners hold a single subscription — calling them again silently replaces the previous one. Each returns a cleanup function to call on unmount (e.g. in `useEffect`'s return).
|
|
109
123
|
|
|
110
|
-
|
|
124
|
+
#### Foreground Listener
|
|
125
|
+
Fires when a notification arrives while the app is active and open.
|
|
111
126
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
127
|
+
```javascript
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
const unsubscribe = PushNotifications.setForegroundListener((payload) => {
|
|
130
|
+
console.log("Foreground notification:", payload);
|
|
131
|
+
});
|
|
132
|
+
return () => unsubscribe();
|
|
133
|
+
}, []);
|
|
134
|
+
```
|
|
115
135
|
|
|
116
|
-
|
|
136
|
+
#### Background Listener
|
|
137
|
+
Fires when a notification arrives while the app is backgrounded or (on Android) killed.
|
|
117
138
|
|
|
118
|
-
|
|
119
|
-
PushNotifications.requestNotificationPermission();
|
|
120
|
-
```
|
|
139
|
+
> **Android only**: To handle notifications when the app is completely killed, you must also register a Headless JS task — see [Android Setup](#android-setup).
|
|
121
140
|
|
|
122
|
-
|
|
141
|
+
```javascript
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
const unsubscribe = PushNotifications.Android.setBackgroundListener(async (payload) => {
|
|
144
|
+
console.log("Background notification:", payload);
|
|
145
|
+
// The SDK automatically signals the OS when your Promise resolves
|
|
146
|
+
});
|
|
147
|
+
return () => unsubscribe();
|
|
148
|
+
}, []);
|
|
149
|
+
```
|
|
123
150
|
|
|
124
|
-
|
|
151
|
+
#### Opened Listener
|
|
152
|
+
Fires when the user taps a notification. Works regardless of whether the app was in the foreground, background, or killed.
|
|
125
153
|
|
|
126
|
-
|
|
154
|
+
```javascript
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
const unsubscribe = PushNotifications.setOpenedListener((payload) => {
|
|
157
|
+
console.log("Notification tapped:", payload);
|
|
158
|
+
});
|
|
159
|
+
return () => unsubscribe();
|
|
160
|
+
}, []);
|
|
161
|
+
```
|
|
127
162
|
|
|
128
|
-
###
|
|
163
|
+
### Notification Payload
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
interface NotificationPayload {
|
|
167
|
+
title: string | null;
|
|
168
|
+
body: string | null;
|
|
169
|
+
imageUrl: string | null;
|
|
170
|
+
data: Record<string, string>;
|
|
171
|
+
android: {
|
|
172
|
+
color: string | null;
|
|
173
|
+
smallIconName: string | null;
|
|
174
|
+
ticker: string | null;
|
|
175
|
+
sticky: boolean | null;
|
|
176
|
+
visibility: string | null;
|
|
177
|
+
channelId: string | null;
|
|
178
|
+
tag: string | null;
|
|
179
|
+
sound: string | null;
|
|
180
|
+
clickAction: string | null;
|
|
181
|
+
} | null;
|
|
182
|
+
ios: {
|
|
183
|
+
badge: number | null;
|
|
184
|
+
sound: string | null;
|
|
185
|
+
category: string | null;
|
|
186
|
+
threadId: string | null;
|
|
187
|
+
} | null;
|
|
188
|
+
}
|
|
189
|
+
```
|
|
129
190
|
|
|
130
|
-
|
|
191
|
+
### Permission Helpers
|
|
131
192
|
|
|
132
193
|
```javascript
|
|
133
|
-
//
|
|
134
|
-
PushNotifications.
|
|
194
|
+
// Fire-and-forget — shows the system permission dialog
|
|
195
|
+
PushNotifications.requestNotificationPermission();
|
|
196
|
+
|
|
197
|
+
// Returns Promise<boolean> with the user's decision
|
|
198
|
+
const granted = await PushNotifications.requestNotificationPermissionWithResult();
|
|
135
199
|
|
|
136
|
-
//
|
|
137
|
-
PushNotifications.
|
|
200
|
+
// Check current permission status without prompting the user
|
|
201
|
+
const hasPermission = await PushNotifications.hasNotificationPermission();
|
|
138
202
|
```
|
|
139
203
|
|
|
140
|
-
|
|
204
|
+
### Enable / Disable Notifications
|
|
141
205
|
|
|
142
206
|
```javascript
|
|
143
|
-
|
|
207
|
+
PushNotifications.setNotificationsEnabled(false); // opt out
|
|
208
|
+
PushNotifications.setNotificationsEnabled(true); // opt back in
|
|
209
|
+
|
|
210
|
+
const isEnabled = await PushNotifications.isNotificationsEnabled();
|
|
144
211
|
```
|
|
145
212
|
|
|
146
|
-
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Native Implementation Setup
|
|
147
216
|
|
|
148
|
-
|
|
217
|
+
### Android Setup
|
|
218
|
+
|
|
219
|
+
The SDK's `AndroidManifest.xml` automatically merges the required permissions (`POST_NOTIFICATIONS`, `RECEIVE_BOOT_COMPLETED`), `AppAmbitInitProvider`, and `AppAmbitHeadlessService` into your app — no manifest changes needed.
|
|
220
|
+
|
|
221
|
+
To handle notifications when the app is completely killed, register a Headless JS task in your `index.js`:
|
|
149
222
|
|
|
150
223
|
```javascript
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
224
|
+
import { AppRegistry, Platform } from 'react-native';
|
|
225
|
+
import * as PushNotifications from 'appambit-push-notifications';
|
|
226
|
+
import App from './src/App';
|
|
227
|
+
import { name as appName } from './app.json';
|
|
228
|
+
|
|
229
|
+
if (Platform.OS === 'android') {
|
|
230
|
+
AppRegistry.registerHeadlessTask(
|
|
231
|
+
PushNotifications.BACKGROUND_NOTIFICATION_TASK,
|
|
232
|
+
() => async (payload) => {
|
|
233
|
+
console.log('Background notification (killed state):', payload);
|
|
158
234
|
}
|
|
159
|
-
);
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
AppRegistry.registerComponent(appName, () => App);
|
|
160
239
|
```
|
|
161
240
|
|
|
162
|
-
|
|
241
|
+
> Use `AppRegistry.registerHeadlessTask` with `BACKGROUND_NOTIFICATION_TASK` — not `BackgroundFetch` or any other API.
|
|
163
242
|
|
|
164
|
-
|
|
243
|
+
---
|
|
165
244
|
|
|
166
|
-
|
|
245
|
+
### iOS Setup
|
|
167
246
|
|
|
168
|
-
|
|
247
|
+
#### Push Notifications Capability & APNs Entitlement
|
|
169
248
|
|
|
170
|
-
|
|
249
|
+
Enable **Push Notifications** in Xcode under your target's *Signing & Capabilities* tab. This automatically injects the `aps-environment` entitlement into your `.entitlements` file.
|
|
171
250
|
|
|
172
|
-
|
|
251
|
+
If you manage `Runner.entitlements` manually (e.g. via version control or CI), make sure this key is present — without it APNs will reject device registration and no token will ever be delivered:
|
|
173
252
|
|
|
174
|
-
|
|
253
|
+
```xml
|
|
254
|
+
<!-- ios/Runner/Runner.entitlements -->
|
|
255
|
+
<key>aps-environment</key>
|
|
256
|
+
<string>development</string> <!-- use "production" for App Store builds -->
|
|
257
|
+
```
|
|
175
258
|
|
|
176
|
-
|
|
177
|
-
- **`body`**: The notification's main text.
|
|
259
|
+
---
|
|
178
260
|
|
|
179
|
-
|
|
261
|
+
### iOS Notification Service Extension (Rich Notifications)
|
|
180
262
|
|
|
181
|
-
|
|
263
|
+
To display rich notifications with image attachments, create a Notification Service Extension in Xcode.
|
|
182
264
|
|
|
183
|
-
|
|
265
|
+
1. **Create the extension**: Go to **File > New > Target**, select **Notification Service Extension**, and give it a name (e.g. `NotificationService`).
|
|
184
266
|
|
|
185
|
-
|
|
267
|
+
2. **Add the pod** to your `Podfile` outside the main target:
|
|
268
|
+
```ruby
|
|
269
|
+
target 'NotificationService' do
|
|
270
|
+
pod 'AppAmbitPushNotificationsExtension', '~> 1.0.0'
|
|
271
|
+
end
|
|
272
|
+
```
|
|
273
|
+
Then run `pod install` under `ios/`.
|
|
186
274
|
|
|
187
|
-
**
|
|
275
|
+
3. **Subclass `AppAmbitNotificationService`** in `NotificationService.swift`:
|
|
188
276
|
|
|
189
|
-
|
|
277
|
+
```swift
|
|
278
|
+
import UserNotifications
|
|
279
|
+
import AppAmbitPushNotificationsExtension
|
|
190
280
|
|
|
191
|
-
|
|
281
|
+
class NotificationService: AppAmbitNotificationService {
|
|
282
|
+
override func didReceive(
|
|
283
|
+
_ request: UNNotificationRequest,
|
|
284
|
+
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
|
|
285
|
+
) {
|
|
286
|
+
// Base class handles rich media download and attachment automatically.
|
|
287
|
+
super.didReceive(request, withContentHandler: contentHandler)
|
|
288
|
+
}
|
|
192
289
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
"key1": "Mark as Read",
|
|
199
|
-
"key2": "MARK_AS_READ_ACTION",
|
|
200
|
-
"any_other_key": "any_value"
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
2. **Register the `NotificationCustomizer`** and use your custom keys:
|
|
206
|
-
|
|
207
|
-
```javascript
|
|
208
|
-
PushNotifications.setNotificationCustomizer((payload: PushNotifications.NotificationPayload) => {
|
|
209
|
-
console.log("Payload:", payload);
|
|
210
|
-
console.log("Data:", payload.data);
|
|
211
|
-
console.log("Title:", payload.title);
|
|
212
|
-
console.log("Body:", payload.body);
|
|
213
|
-
});
|
|
214
|
-
PushNotifications.start();
|
|
215
|
-
```
|
|
290
|
+
override func serviceExtensionTimeWillExpire() {
|
|
291
|
+
super.serviceExtensionTimeWillExpire()
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
package/android/build.gradle
CHANGED
|
@@ -15,10 +15,8 @@ buildscript {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
19
18
|
apply plugin: "com.android.library"
|
|
20
19
|
apply plugin: "kotlin-android"
|
|
21
|
-
|
|
22
20
|
apply plugin: "com.facebook.react"
|
|
23
21
|
|
|
24
22
|
def getExtOrIntegerDefault(name) {
|
|
@@ -72,7 +70,27 @@ repositories {
|
|
|
72
70
|
def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
73
71
|
|
|
74
72
|
dependencies {
|
|
75
|
-
|
|
73
|
+
// ─── Remote Push SDK Dependency ─────────────────────────────────────────────
|
|
74
|
+
// 'api' (not 'implementation') is required so that classes like PushNotifications
|
|
75
|
+
// are visible at compile time to the consuming app (e.g. MainActivity.kt).
|
|
76
|
+
api 'com.appambit:appambit.push.notifications:1.0.0'
|
|
77
|
+
|
|
78
|
+
// ─── Core SDK (compile-time only) ───────────────────────────────────────────
|
|
79
|
+
// The Push SDK depends on the AppAmbit Core SDK. We reference Core's `AppAmbit`
|
|
80
|
+
// class (e.g. AppAmbit.isInitialized()) at compile time, but it is provided at
|
|
81
|
+
// runtime by the consuming app's Core SDK dependency, so use `compileOnly` to
|
|
82
|
+
// avoid bundling a second copy and risking duplicate-class conflicts.
|
|
83
|
+
compileOnly 'com.appambit:appambit:1.0.0'
|
|
84
|
+
|
|
85
|
+
// ─── Firebase (required transitively by the push AAR) ──────────────────────
|
|
86
|
+
implementation platform('com.google.firebase:firebase-bom:33.6.0')
|
|
87
|
+
implementation 'com.google.firebase:firebase-messaging'
|
|
88
|
+
|
|
89
|
+
// ─── AndroidX transitive deps ───────────────────────────────────────────────
|
|
90
|
+
implementation 'androidx.appcompat:appcompat:1.7.0'
|
|
91
|
+
implementation 'androidx.activity:activity:1.9.0'
|
|
92
|
+
|
|
93
|
+
// ─── React Native ─────────────────────────────────────────────────────────────
|
|
76
94
|
implementation "com.facebook.react:react-android"
|
|
77
95
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
78
96
|
}
|
|
@@ -1,2 +1,108 @@
|
|
|
1
|
-
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
|
+
xmlns:tools="http://schemas.android.com/tools">
|
|
4
|
+
|
|
5
|
+
<!--
|
|
6
|
+
AppAmbit Push Notifications — React Native Bridge Manifest
|
|
7
|
+
|
|
8
|
+
This manifest is MERGED into the consuming application's manifest.
|
|
9
|
+
It registers:
|
|
10
|
+
1. AppAmbitInitProvider — ContentProvider that seeds AppAmbitContextHolder
|
|
11
|
+
before Application.onCreate() runs, enabling the SDK
|
|
12
|
+
to function even when the process is started solely
|
|
13
|
+
to handle an FCM message (killed state).
|
|
14
|
+
2. AppAmbitMessagingService — Subclasses com.appambit.sdk.MessagingService to
|
|
15
|
+
capture the full RemoteMessage (including all
|
|
16
|
+
RemoteMessage.Notification fields) before the AppAmbit
|
|
17
|
+
SDK strips them into its own AppAmbitNotification model.
|
|
18
|
+
3. AppAmbitHeadlessService — Starts Headless JS for background/killed notifications.
|
|
19
|
+
4. NotificationServiceExtension meta-data — tells MessagingService which extension class to load.
|
|
20
|
+
|
|
21
|
+
The consuming app must also declare:
|
|
22
|
+
- INTERNET permission
|
|
23
|
+
- POST_NOTIFICATIONS permission (Android 13+)
|
|
24
|
+
- google-services plugin and google-services.json
|
|
25
|
+
-->
|
|
26
|
+
|
|
27
|
+
<!-- ── Permissions (merged into host app) ───────────────────────────── -->
|
|
28
|
+
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
|
29
|
+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
30
|
+
|
|
31
|
+
<application>
|
|
32
|
+
|
|
33
|
+
<!--
|
|
34
|
+
AppAmbitInitProvider
|
|
35
|
+
Initialises AppAmbitContextHolder at the very first moment of process startup,
|
|
36
|
+
before Application.onCreate(). This is required so that the Headless JS service
|
|
37
|
+
can obtain a valid Context even in killed state (when the React Native bridge
|
|
38
|
+
has not started yet).
|
|
39
|
+
|
|
40
|
+
authorities uses ${applicationId} to avoid clashes between apps.
|
|
41
|
+
initOrder="100" makes it run before other providers with lower values.
|
|
42
|
+
-->
|
|
43
|
+
<provider
|
|
44
|
+
android:name="com.appambitpushnotifications.AppAmbitInitProvider"
|
|
45
|
+
android:authorities="${applicationId}.appambit-init-provider"
|
|
46
|
+
android:exported="false"
|
|
47
|
+
android:initOrder="100" />
|
|
48
|
+
|
|
49
|
+
<!--
|
|
50
|
+
Remove the base AppAmbit SDK's FirebaseMessagingService declaration so our
|
|
51
|
+
subclass (AppAmbitMessagingService) is the only handler for FCM events.
|
|
52
|
+
This library has higher manifest-merge priority than the AppAmbit SDK AAR,
|
|
53
|
+
so tools:node="remove" takes effect before the final manifest is assembled.
|
|
54
|
+
-->
|
|
55
|
+
<service
|
|
56
|
+
android:name="com.appambit.sdk.MessagingService"
|
|
57
|
+
tools:node="remove" />
|
|
58
|
+
|
|
59
|
+
<!--
|
|
60
|
+
AppAmbitMessagingService
|
|
61
|
+
Extends com.appambit.sdk.MessagingService (which extends FirebaseMessagingService).
|
|
62
|
+
Captures the full RemoteMessage in onMessageReceived, stores it in
|
|
63
|
+
AppAmbitRemoteMessageStore, then delegates to the AppAmbit SDK via super.onMessageReceived().
|
|
64
|
+
|
|
65
|
+
AppAmbitNotificationSerializer and AppAmbitHeadlessService read from the store
|
|
66
|
+
to populate notification fields not surfaced by AppAmbitNotification (e.g.
|
|
67
|
+
channelId, sound, tag, ticker, visibility, notificationPriority, vibrateTimings, etc.).
|
|
68
|
+
-->
|
|
69
|
+
<service
|
|
70
|
+
android:name="com.appambitpushnotifications.AppAmbitMessagingService"
|
|
71
|
+
android:exported="false">
|
|
72
|
+
<intent-filter>
|
|
73
|
+
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
|
74
|
+
</intent-filter>
|
|
75
|
+
</service>
|
|
76
|
+
|
|
77
|
+
<!--
|
|
78
|
+
AppAmbitHeadlessService
|
|
79
|
+
Runs the registered Headless JS task ("AppAmbitBackgroundNotification")
|
|
80
|
+
when a push notification arrives in background / killed state.
|
|
81
|
+
|
|
82
|
+
exported="false" — only started internally, not from other apps.
|
|
83
|
+
|
|
84
|
+
Note: we do NOT declare android:foregroundServiceType because
|
|
85
|
+
HeadlessJsTaskService does not require foreground-service privileges.
|
|
86
|
+
Starting it with startService() is sufficient and avoids the strict
|
|
87
|
+
ForegroundServiceStartNotAllowedException on Android 12+ (API 31+).
|
|
88
|
+
-->
|
|
89
|
+
<service
|
|
90
|
+
android:name="com.appambitpushnotifications.AppAmbitHeadlessService"
|
|
91
|
+
android:exported="false" />
|
|
92
|
+
|
|
93
|
+
<!--
|
|
94
|
+
NotificationServiceExtension meta-data
|
|
95
|
+
Tells MessagingService which class to reflectively load as the
|
|
96
|
+
IAppAmbitNotificationServiceExtension implementation.
|
|
97
|
+
|
|
98
|
+
If the consuming app provides its OWN extension, they must
|
|
99
|
+
override this meta-data entry in their app's AndroidManifest.xml
|
|
100
|
+
with tools:replace="android:value".
|
|
101
|
+
-->
|
|
102
|
+
<meta-data
|
|
103
|
+
android:name="com.appambit.sdk.NotificationServiceExtension"
|
|
104
|
+
android:value="com.appambitpushnotifications.AppAmbitRNServiceExtension" />
|
|
105
|
+
|
|
106
|
+
</application>
|
|
107
|
+
|
|
2
108
|
</manifest>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
package com.appambitpushnotifications
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Holds a reference to the Application context so that the
|
|
8
|
+
* [AppAmbitHeadlessService] can start itself even when no Activity is alive
|
|
9
|
+
* (killed state / background).
|
|
10
|
+
*
|
|
11
|
+
* Set once in [AppambitPushNotificationsModule.initialize] via the
|
|
12
|
+
* ReactApplicationContext, which outlives individual activities.
|
|
13
|
+
*/
|
|
14
|
+
internal object AppAmbitContextHolder {
|
|
15
|
+
@Volatile
|
|
16
|
+
var applicationContext: Context? = null
|
|
17
|
+
private set
|
|
18
|
+
|
|
19
|
+
fun set(context: Context) {
|
|
20
|
+
applicationContext = context.applicationContext
|
|
21
|
+
}
|
|
22
|
+
}
|