@attentive-mobile/attentive-react-native-sdk 2.0.0-beta.8 → 2.0.2

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/README.md CHANGED
@@ -9,6 +9,18 @@ This project uses **npm** as the preferred package manager for consistency and a
9
9
 
10
10
  **Note on package managers:** Modern npm (v7+) has significantly improved performance and features, making it the recommended choice for React Native projects. Both npm and yarn work well with React Native, but this project standardizes on npm for development workflows.
11
11
 
12
+ ## Requirements
13
+
14
+ | Tool | Version |
15
+ |------|---------|
16
+ | Node.js | >= 18.0.0 |
17
+ | React Native | >= 0.74 |
18
+ | Ruby | >= 3.3 |
19
+ | CocoaPods | ~> 1.16 |
20
+ | Xcode | >= 15 |
21
+ | Android SDK | API 24+ |
22
+ | JDK | 17 |
23
+
12
24
  ## Installation
13
25
 
14
26
  Run `npm install @attentive-mobile/attentive-react-native-sdk` from your app's root directory.
@@ -22,23 +34,23 @@ __*** NOTE: Please refrain from using any private or undocumented classes or met
22
34
  ### Import the SDK
23
35
 
24
36
  ```typescript
25
- import { Attentive, <other types you need here> } from 'attentive-react-native-sdk';
37
+ import { initialize, identify, triggerCreative, recordPurchaseEvent, /* ... */ } from '@attentive-mobile/attentive-react-native-sdk';
26
38
  ```
27
39
 
28
40
  ### Create the AttentiveConfig
29
41
 
30
42
  ```typescript
31
- // Create an AttentiveConfiguration with your attentive domain, in production mode
32
- const config : AttentiveConfiguration = {
43
+ // Create an AttentiveSdkConfiguration with your attentive domain, in production mode
44
+ const config: AttentiveSdkConfiguration = {
33
45
  attentiveDomain: 'YOUR_ATTENTIVE_DOMAIN',
34
- mode: Mode.Production,
46
+ mode: 'production',
35
47
  }
36
48
  ```
37
49
  ```typescript
38
50
  // Alternatively, use "debug" mode. When in debug mode, the Creative will not be shown, but instead a popup will show with debug information about your creative and any reason the Creative wouldn't show.
39
- const config : AttentiveConfiguration = {
51
+ const config: AttentiveSdkConfiguration = {
40
52
  attentiveDomain: 'YOUR_ATTENTIVE_DOMAIN',
41
- mode: Mode.Debug,
53
+ mode: 'debug',
42
54
  }
43
55
  ```
44
56
 
@@ -47,9 +59,9 @@ const config : AttentiveConfiguration = {
47
59
  The SDK includes debugging helpers to show what data is being sent and received. Enable debugging by setting `enableDebugger: true`:
48
60
 
49
61
  ```typescript
50
- const config : AttentiveConfiguration = {
62
+ const config: AttentiveSdkConfiguration = {
51
63
  attentiveDomain: 'YOUR_ATTENTIVE_DOMAIN',
52
- mode: Mode.Debug,
64
+ mode: 'debug',
53
65
  enableDebugger: true, // Shows debug overlays for events and creatives
54
66
  }
55
67
  ```
@@ -61,7 +73,7 @@ When enabled, debug overlays will automatically appear when:
61
73
  You can also manually invoke the debug helper:
62
74
 
63
75
  ```typescript
64
- Attentive.invokeAttentiveDebugHelper();
76
+ invokeAttentiveDebugHelper();
65
77
  ```
66
78
 
67
79
  See [DEBUGGING.md](./DEBUGGING.md) for detailed information about debugging features.
@@ -76,7 +88,7 @@ On iOS, call `initialize` from TypeScript as early as possible (e.g. the root `A
76
88
 
77
89
  ```typescript
78
90
  // Called once per app session, before any other SDK operations.
79
- Attentive.initialize(config);
91
+ initialize(config);
80
92
  ```
81
93
 
82
94
  #### Android — Initialize from Native Code
@@ -109,6 +121,7 @@ class MainApplication : Application(), ReactApplication {
109
121
  .applicationContext(this)
110
122
  .domain("YOUR_ATTENTIVE_DOMAIN")
111
123
  .mode(AttentiveConfig.Mode.PRODUCTION) // or Mode.DEBUG for testing
124
+ .notificationIconId(R.drawable.ic_stat_notification)
112
125
  .skipFatigueOnCreatives(false)
113
126
  .logLevel(AttentiveLogLevel.VERBOSE)
114
127
  .build()
@@ -120,6 +133,30 @@ class MainApplication : Application(), ReactApplication {
120
133
  }
121
134
  ```
122
135
 
136
+ ##### Android notification small icon
137
+
138
+ Android requires push notifications to use a small status-bar icon. If `notificationIconId` is not set, the Attentive Android SDK uses its default fallback icon. To use your app's branding, add a notification small icon resource to your host app and pass its resource ID during native initialization.
139
+
140
+ Add the icon to your Android app's drawable resources:
141
+
142
+ ```text
143
+ android/app/src/main/res/drawable/ic_stat_notification.png
144
+ ```
145
+
146
+ Use a white-only transparent PNG designed for Android notification status bars. Do not use the full-color launcher icon from `mipmap-*`, because Android masks small notification icons and it can render poorly.
147
+
148
+ Then add the icon to your existing `AttentiveConfig.Builder()` chain in `MainApplication.kt` before `build()`:
149
+
150
+ ```text
151
+ android/app/src/main/java/<your-package>/MainApplication.kt
152
+ ```
153
+
154
+ ```kotlin
155
+ .notificationIconId(R.drawable.ic_stat_notification)
156
+ ```
157
+
158
+ `MainApplication.kt` is host-app code, not generated by this SDK at runtime. If `R.drawable.ic_stat_notification` does not resolve, confirm the drawable file name matches exactly and that you are referencing your app module's `R` class.
159
+
123
160
  After the native initialization, all other SDK operations (`identify`, `recordAddToCartEvent`, `recordPurchaseEvent`, etc.) are called from TypeScript as normal on both platforms.
124
161
 
125
162
  > **Tip:** If you see `[AttentiveSDK] recordAddToCartEvent failed — SDK may not be initialized` in your Android logcat, it means `AttentiveSdk.initialize()` was not called from native code before the event was recorded. Check your `Application.onCreate()` setup.
@@ -128,22 +165,22 @@ After the native initialization, all other SDK operations (`identify`, `recordAd
128
165
 
129
166
  ```typescript
130
167
  // This will remove the creative along with its web view
131
- Attentive.destroyCreative();
168
+ destroyCreative();
132
169
  ```
133
170
 
134
171
 
135
172
  ### Identify the current user
136
173
  ```typescript
137
174
  // Before loading the creative or sending events, if you have any user identifiers, they will need to be registered. Each identifier is optional. It is okay to skip this step if you have no identifiers about the user yet.
138
- const identifiers : UserIdentifiers = {
139
- 'phone': '+15556667777',
140
- 'email': 'some_email@gmailfake.com',
141
- 'klaviyoId': 'userKlaviyoId',
142
- 'shopifyId': 'userShopifyId',
143
- 'clientUserId': 'userClientUserId',
144
- 'customIdentifiers': { 'customIdKey': 'customIdValue' }
175
+ const identifiers: UserIdentifiers = {
176
+ phone: '+15556667777',
177
+ email: 'some_email@gmailfake.com',
178
+ klaviyoId: 'userKlaviyoId',
179
+ shopifyId: 'userShopifyId',
180
+ clientUserId: 'userClientUserId',
181
+ customIdentifiers: { customIdKey: 'customIdValue' }
145
182
  };
146
- Attentive.identify(identifiers);
183
+ identify(identifiers);
147
184
  ```
148
185
 
149
186
  The more identifiers that are passed to `identify`, the better the SDK will function. Here is the list of possible identifiers:
@@ -160,46 +197,34 @@ The more identifiers that are passed to `identify`, the better the SDK will func
160
197
 
161
198
  ```typescript
162
199
  // Trigger the Creative. This will show the Creative as a pop-up over the rest of the app.
163
- Attentive.triggerCreative();
200
+ triggerCreative();
164
201
  ```
165
202
 
166
203
  ### Record user events
167
204
 
168
- The SDK currently supports `PurchaseEvent`, `AddToCartEvent`, `ProductViewEvent`, and `CustomEvent`.
205
+ The SDK currently supports `Purchase`, `AddToCart`, `ProductView`, and `CustomEvent`.
169
206
 
170
207
  ```typescript
171
208
  // Construct one or more "Item"s, which represents the product(s) purchased
172
- const items : Item[] = [
173
- {
174
- productId: '555',
175
- productVariantId: '777',
176
- price: {
177
- price: '14.99',
178
- currency: 'USD',
179
- },
180
- },
181
- ];
182
-
183
- // Construct an "Order", which represents the order for the purchase
184
- const order : Order = {
185
- orderId: '88888'
186
- }
187
-
188
- // (Optional) Construct a "Cart", which represents the cart this Purchase was made from
189
- const cart : Cart = {
190
- cartId: '555555',
191
- cartCoupon: 'SOME-DISCOUNT'
192
- }
193
-
194
- // Construct a PurchaseEvent, which ties together the preceding objects
195
- const purchaseEvent : PurchaseEvent = {
209
+ const items: Item[] = [
210
+ {
211
+ productId: '555',
212
+ productVariantId: '777',
213
+ price: '14.99',
214
+ currency: 'USD',
215
+ },
216
+ ];
217
+
218
+ // Construct a Purchase event
219
+ const purchase: Purchase = {
196
220
  items: items,
197
- order: order,
198
- cart: cart
221
+ orderId: '88888',
222
+ cartId: '555555', // optional
223
+ cartCoupon: 'SOME-DISCOUNT', // optional
199
224
  }
200
225
 
201
226
  // Record the PurchaseEvent
202
- Attentive.recordPurchaseEvent(purchaseEvent);
227
+ recordPurchaseEvent(purchase);
203
228
  ```
204
229
 
205
230
  The process is similar for the other events. See [eventTypes.tsx](https://github.com/attentive-mobile/attentive-react-native-sdk/blob/main/src/eventTypes.tsx) for all events.
@@ -208,12 +233,12 @@ The process is similar for the other events. See [eventTypes.tsx](https://github
208
233
 
209
234
  ```typescript
210
235
  // If new identifiers are available for the user, register them
211
- Attentive.identify({email: 'theusersemail@gmail.com'});
236
+ identify({email: 'theusersemail@gmail.com'});
212
237
  ```
213
238
 
214
239
  ```typescript
215
- Attentive.identify({email: 'theusersemail@gmail.com'});
216
- Attentive.identify({phone: '+15556667777'};)
240
+ identify({email: 'theusersemail@gmail.com'});
241
+ identify({phone: '+15556667777'});
217
242
  // The SDK will have these two identifiers:
218
243
  // email: 'theusersemail@gmail.com'
219
244
  // phone: '+15556667777'
@@ -281,57 +306,45 @@ identify({ email: 'user@example.com', clientUserId: 'id-123' });
281
306
 
282
307
  #### Push notifications on Android (FCM)
283
308
 
284
- On Android, FCM token registration and push notification handling are managed natively in Kotlin/Java. This gives you full control over the Firebase Messaging lifecycle and ensures events are tracked before the React Native bridge initialises.
309
+ The Attentive Android SDK registers its own `FirebaseMessagingService` automatically **you do not need to create a subclass**. As long as your app is registered with Firebase and includes a valid `google-services.json`, the SDK handles FCM token registration and foreground push delivery for you. Follow the [Firebase Android setup guide](https://firebase.google.com/docs/cloud-messaging/android/client) to add FCM to your project.
285
310
 
286
- Add Firebase Cloud Messaging to your app following the [Firebase Android setup guide](https://firebase.google.com/docs/cloud-messaging/android/client), then handle token registration and notification events in your native `FirebaseMessagingService`:
311
+ ##### If you already have a FirebaseMessagingService subclass
312
+
313
+ If your app has an existing `FirebaseMessagingService` subclass for other purposes, route Attentive messages through to the SDK:
287
314
 
288
315
  ```kotlin
289
316
  import com.attentive.androidsdk.AttentiveSdk
290
317
  import com.google.firebase.messaging.FirebaseMessagingService
291
318
  import com.google.firebase.messaging.RemoteMessage
292
319
 
293
- class AttentiveMessagingService : FirebaseMessagingService() {
294
-
295
- override fun onNewToken(token: String) {
296
- super.onNewToken(token)
297
- // Register the FCM token with the Attentive SDK
298
- AttentiveSdk.registerDeviceToken(token)
299
- }
320
+ class YourFirebaseMessagingService : FirebaseMessagingService() {
300
321
 
301
322
  override fun onMessageReceived(remoteMessage: RemoteMessage) {
302
323
  super.onMessageReceived(remoteMessage)
303
- // Handle foreground push delivery
304
- AttentiveSdk.handleForegroundPush(remoteMessage.data)
324
+ if (AttentiveSdk.isAttentiveFirebaseMessage(remoteMessage)) {
325
+ AttentiveSdk.sendNotification(remoteMessage)
326
+ }
327
+ // Handle your own messages below...
305
328
  }
306
329
  }
307
330
  ```
308
331
 
309
- For notification opens (when the user taps a push notification), handle the intent in your main `Activity`:
332
+ ##### Notification opens (singleTask apps)
333
+
334
+ React Native apps use `singleTask` launch mode by default. When a push notification is tapped while the app is in the background, Android delivers the intent via `onNewIntent()` rather than recreating the activity. Override `onNewIntent` in your `MainActivity` so the SDK can detect the notification tap:
310
335
 
311
336
  ```kotlin
312
- import com.attentive.androidsdk.AttentiveSdk
337
+ import android.content.Intent
313
338
 
314
339
  class MainActivity : ReactActivity() {
315
340
 
316
- override fun onResume() {
317
- super.onResume()
318
- intent?.let { AttentiveSdk.handlePushOpen(it) }
341
+ override fun onNewIntent(intent: Intent?) {
342
+ super.onNewIntent(intent)
343
+ intent?.let { setIntent(it) }
319
344
  }
320
345
  }
321
346
  ```
322
347
 
323
- Declare the service in your `AndroidManifest.xml`:
324
-
325
- ```xml
326
- <service
327
- android:name=".AttentiveMessagingService"
328
- android:exported="false">
329
- <intent-filter>
330
- <action android:name="com.google.firebase.MESSAGING_EVENT" />
331
- </intent-filter>
332
- </service>
333
- ```
334
-
335
348
  Refer to the [Attentive Android SDK documentation](https://github.com/attentive-mobile/attentive-android-sdk) for the full list of native APIs available for push notification integration.
336
349
 
337
350
  ---
@@ -1,7 +1,6 @@
1
1
  require "json"
2
2
 
3
3
  package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
- folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
5
4
 
6
5
  Pod::Spec.new do |s|
7
6
  s.name = "attentive-react-native-sdk"
@@ -15,23 +14,10 @@ Pod::Spec.new do |s|
15
14
  s.source = { :git => "https://github.com/attentive-mobile/attentive-react-native-sdk.git", :tag => "#{s.version}" }
16
15
 
17
16
  s.source_files = "ios/**/*.{h,m,mm,swift}"
17
+ s.public_header_files = "ios/AttentiveReactNativeSdk.h"
18
18
 
19
19
  s.dependency 'attentive-ios-sdk', '2.0.13'
20
20
  s.swift_versions = ['5']
21
- s.dependency "React-Core"
22
21
 
23
- # Don't install the dependencies when we run `pod install` in the old architecture.
24
- if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
25
- s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
26
- s.pod_target_xcconfig = {
27
- "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/Headers/Public/React-NativeModulesApple\" \"$(PODS_ROOT)/Headers/Private/React-NativeModulesApple\" \"$(PODS_ROOT)/Headers/Private/React-Codegen/react/renderer/components\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Codegen/React_Codegen.framework/Headers\"",
28
- "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
29
- "CLANG_CXX_LANGUAGE_STANDARD" => "c++20"
30
- }
31
- s.dependency "React-Codegen"
32
- s.dependency "RCT-Folly"
33
- s.dependency "RCTRequired"
34
- s.dependency "RCTTypeSafety"
35
- s.dependency "ReactCommon/turbomodule/core"
36
- end
22
+ install_modules_dependencies(s)
37
23
  end
@@ -5,14 +5,7 @@
5
5
  // Created by Wyatt Davis on 2/13/23.
6
6
  //
7
7
 
8
- #ifdef RCT_NEW_ARCH_ENABLED
9
- #import "AttentiveReactNativeSdkSpec.h"
10
-
11
- @interface AttentiveReactNativeSdk : NSObject <NativeAttentiveReactNativeSdkSpec>
12
- #else
13
8
  #import <React/RCTBridgeModule.h>
14
9
 
15
10
  @interface AttentiveReactNativeSdk : NSObject <RCTBridgeModule>
16
- #endif
17
-
18
11
  @end
@@ -4,17 +4,31 @@
4
4
  //
5
5
  // Created by Wyatt Davis on 2/13/23.
6
6
  //
7
+ // NOTE: This file contains both new arch and old arch implementations. Only the new arch path
8
+ // (RCT_NEW_ARCH_ENABLED) is functional. The old arch #else branch does not compile and is
9
+ // retained as scaffolding for future old arch support work (MSDK-350).
10
+ //
7
11
 
8
12
  #import "AttentiveReactNativeSdk.h"
9
13
  #import <UserNotifications/UserNotifications.h>
10
14
 
11
- #if __has_include(<AttentiveReactNativeSdk-Swift.h>)
15
+ #ifdef RCT_NEW_ARCH_ENABLED
16
+ #import "AttentiveReactNativeSdkSpec.h"
17
+ #endif
18
+
19
+ #if __has_include(<attentive_react_native_sdk/attentive_react_native_sdk-Swift.h>)
20
+ #import <attentive_react_native_sdk/attentive_react_native_sdk-Swift.h>
21
+ #elif __has_include(<AttentiveReactNativeSdk-Swift.h>)
12
22
  #import "AttentiveReactNativeSdk-Swift.h"
13
23
  #else
14
- // Load the headers from the attentive-ios-sdk Pod
15
24
  #import "attentive_react_native_sdk-Swift.h"
16
25
  #endif
17
26
 
27
+ #ifdef RCT_NEW_ARCH_ENABLED
28
+ @interface AttentiveReactNativeSdk () <NativeAttentiveReactNativeSdkSpec>
29
+ @end
30
+ #endif
31
+
18
32
  @implementation AttentiveReactNativeSdk {
19
33
  ATTNNativeSDK* _sdk;
20
34
  }
@@ -190,8 +204,9 @@ customIdentifiers:(NSDictionary *)customIdentifiers {
190
204
  }
191
205
 
192
206
  #else
193
- // Old Architecture implementation with dictionary parameters.
194
- // Initialize is invoked only from TypeScript (e.g. Bonni App); native must not auto-initialize.
207
+ // Old Architecture implementation currently does not compile (missing RCT_EXPORT_METHOD macros,
208
+ // bridge module registration, etc.). Kept here as a starting point for restoring old arch support
209
+ // in a future ticket (MSDK-350).
195
210
  - (void)initialize:(NSDictionary*)configuration {
196
211
  _sdk = [[ATTNNativeSDK alloc] initWithDomain:configuration[@"attentiveDomain"]
197
212
  mode:configuration[@"mode"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@attentive-mobile/attentive-react-native-sdk",
3
- "version": "2.0.0-beta.8",
3
+ "version": "2.0.2",
4
4
  "description": "React Native Module for the Attentive SDK",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -16,6 +16,10 @@
16
16
  "*.podspec",
17
17
  "!lib/typescript/example",
18
18
  "!ios/build",
19
+ "!ios/Pods",
20
+ "!ios/Podfile.lock",
21
+ "!ios/*.xcworkspace",
22
+ "!**/xcuserdata",
19
23
  "!android/build",
20
24
  "!android/gradle",
21
25
  "!android/gradlew",
@@ -111,7 +115,7 @@
111
115
  "release-it": {
112
116
  "git": {
113
117
  "commitMessage": "chore: release ${version}",
114
- "tagName": "v${version}"
118
+ "tagName": "${version}"
115
119
  },
116
120
  "npm": {
117
121
  "publish": true