@attentive-mobile/attentive-react-native-sdk 2.0.0-beta.7 → 2.0.1

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
@@ -81,7 +81,12 @@ Attentive.initialize(config);
81
81
 
82
82
  #### Android — Initialize from Native Code
83
83
 
84
- On Android, `AttentiveSdk.initialize()` **must** be called from your `Application.onCreate()` in native Kotlin/Java code. This is required so that lifecycle observers (e.g. `AppLaunchTracker`) are registered before the React Native bridge is ready. Calling `initialize()` from TypeScript on Android is a **no-op** — the SDK will not be started and all subsequent event calls will fail.
84
+ On Android, `AttentiveSdk.initialize()` **must** be called from your `Application.onCreate()` in native Kotlin/Java code. There are two reasons for this:
85
+
86
+ 1. **Lifecycle observers must be registered before the React Native bridge is ready.** Internally, the SDK creates an `AppLaunchTracker` that calls `lifecycle.addObserver()` on the `ProcessLifecycleOwner`. If initialization happens after the bridge starts, early app-launch events can be missed.
87
+ 2. **`lifecycle.addObserver()` requires the main thread.** AndroidX enforces this with an `IllegalStateException` if called from a background thread. `Application.onCreate()` is guaranteed by the Android system to run on the main thread, so calling `initialize` there satisfies this requirement automatically — no extra threading machinery needed.
88
+
89
+ > **Do not** call `AttentiveSdk.initialize()` from a background thread or a coroutine dispatcher other than `Dispatchers.Main`. Doing so will throw an `IllegalStateException` from inside the AndroidX Lifecycle library.
85
90
 
86
91
  Add the following to your `MainApplication.kt` (or `MainApplication.java`):
87
92
 
@@ -90,7 +95,6 @@ import android.app.Application
90
95
  import com.attentive.androidsdk.AttentiveConfig
91
96
  import com.attentive.androidsdk.AttentiveSdk
92
97
  import com.attentive.androidsdk.AttentiveLogLevel
93
- import com.facebook.react.bridge.UiThreadUtil
94
98
 
95
99
  class MainApplication : Application(), ReactApplication {
96
100
 
@@ -105,19 +109,43 @@ class MainApplication : Application(), ReactApplication {
105
109
  .applicationContext(this)
106
110
  .domain("YOUR_ATTENTIVE_DOMAIN")
107
111
  .mode(AttentiveConfig.Mode.PRODUCTION) // or Mode.DEBUG for testing
112
+ .notificationIconId(R.drawable.ic_stat_notification)
108
113
  .skipFatigueOnCreatives(false)
109
114
  .logLevel(AttentiveLogLevel.VERBOSE)
110
115
  .build()
111
116
 
112
- // AttentiveSdk.initialize registers lifecycle observers and must run on the main thread.
113
- UiThreadUtil.runOnUiThread {
114
- AttentiveSdk.initialize(config)
115
- }
117
+ // Application.onCreate() is always called on the main thread by the Android system,
118
+ // so no thread-switching wrapper is needed here.
119
+ AttentiveSdk.initialize(config)
116
120
  }
117
121
  }
118
122
  ```
119
123
 
120
- After the native initialization, all other SDK operations (`identify`, `recordAddToCartEvent`, `recordPurchaseEvent`, etc.) are called from TypeScript as normal on both platforms. The TypeScript `initialize()` call is still required on iOS but is safely ignored on Android.
124
+ ##### Android notification small icon
125
+
126
+ 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.
127
+
128
+ Add the icon to your Android app's drawable resources:
129
+
130
+ ```text
131
+ android/app/src/main/res/drawable/ic_stat_notification.png
132
+ ```
133
+
134
+ 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.
135
+
136
+ Then add the icon to your existing `AttentiveConfig.Builder()` chain in `MainApplication.kt` before `build()`:
137
+
138
+ ```text
139
+ android/app/src/main/java/<your-package>/MainApplication.kt
140
+ ```
141
+
142
+ ```kotlin
143
+ .notificationIconId(R.drawable.ic_stat_notification)
144
+ ```
145
+
146
+ `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.
147
+
148
+ After the native initialization, all other SDK operations (`identify`, `recordAddToCartEvent`, `recordPurchaseEvent`, etc.) are called from TypeScript as normal on both platforms.
121
149
 
122
150
  > **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.
123
151
 
@@ -218,7 +246,7 @@ Attentive.identify({phone: '+15556667777'};)
218
246
 
219
247
  ### Push Notifications (iOS and Android)
220
248
 
221
- The SDK supports push notification integration on both iOS (APNs) and Android (runtime permission + optional FCM). The following sections cover iOS-specific flows and a full **App events on Android** implementation that mirrors the behavior of the [Bonni](https://github.com/attentive-mobile/attentive-react-native-sdk/tree/main/Bonni) example app.
249
+ The SDK supports push notification integration on both iOS (APNs) and Android (FCM). The following sections cover iOS-specific setup flows. On Android, push notification integration is handled entirely in native Kotlin/Java code see [App Events on Android](#app-events-on-android) for details.
222
250
 
223
251
  > **iOS — required setup:** Your AppDelegate **must** forward notification
224
252
  > responses to the SDK for push tracking to work. Add this single line to your
@@ -243,22 +271,9 @@ The SDK supports push notification integration on both iOS (APNs) and Android (r
243
271
 
244
272
  ### App Events on Android
245
273
 
246
- This section describes how to implement Attentive app events on Android so they behave like the iOS flow: **regular app opens** (launch and resume from background) and **notification permission** are handled using the SDK’s native Android APIs. You can add FCM token registration and push open handling when your app uses Firebase Cloud Messaging.
247
-
248
- | SDK method | Purpose on Android |
249
- |------------|--------------------|
250
- | `getPushAuthorizationStatus()` | Returns `authorized`, `denied`, or `notDetermined` (uses `POST_NOTIFICATIONS` on API 33+). Use before `handleRegularOpen` so tracking uses the correct status. |
251
- | `registerForPushNotifications()` | Requests `POST_NOTIFICATIONS` on Android 13+; no-op on older versions. |
252
- | `handleRegularOpen(authStatus)` | Tracks a regular app open (launch or return to foreground). Call after `identify()` and pass the result of `getPushAuthorizationStatus()`. |
253
- | `registerDeviceToken` / `registerDeviceTokenWithCallback` | Optional. Register your FCM token when using Firebase Cloud Messaging. |
254
- | `handlePushOpen` / `handleForegroundPush` | Optional. Call when the user opens a notification or receives one in the foreground. |
274
+ On Android, **regular app open and foreground events are handled automatically** by the native Android SDK once `AttentiveSdk.initialize()` is called from `Application.onCreate()` (see [Android Native Initialization](#android--initialize-from-native-code)). The lifecycle observers registered during initialization (e.g. `AppLaunchTracker`) take care of this transparently there is no need to manually call `handleRegularOpen` or subscribe to `AppState` changes.
255
275
 
256
- #### Overview
257
-
258
- - **Regular app open** – Call `handleRegularOpen(authorizationStatus)` when the app is opened (launch or returning to foreground). The SDK uses this for tracking and the `/mtctrl` endpoint.
259
- - **Permission status** – On Android 13+ (API 33+), notification permission is `POST_NOTIFICATIONS`. The SDK exposes `getPushAuthorizationStatus()` so you can pass the correct status into `handleRegularOpen`.
260
- - **Requesting permission** – Call `registerForPushNotifications()` to trigger the system permission dialog on Android 13+; it is a no-op on older versions.
261
- - **Order of operations** – Always call `identify()` before any `handleRegularOpen()` so the SDK has user context for network requests.
276
+ The only TypeScript-side step required on Android is calling `identify()` with any available user identifiers as early as possible in your app’s lifecycle (e.g. in the root component `useEffect`).
262
277
 
263
278
  #### Prerequisites
264
279
 
@@ -271,115 +286,66 @@ This section describes how to implement Attentive app events on Android so they
271
286
  </manifest>
272
287
  ```
273
288
 
274
- 2. **Initialize and identify first** – The SDK must be initialized natively from `Application.onCreate()` on Android (see [Android Native Initialization](#android--initialize-from-native-code) above). Then, in your app entry (e.g. root component `useEffect`), call `identify(identifiers)` before any push or app-event logic.
275
-
276
- #### 1. On app launch (Android)
289
+ 2. **Native initialization** – The SDK must be initialized from `Application.onCreate()` on Android (see [Android Native Initialization](#android--initialize-from-native-code) above). App open and lifecycle events are then tracked automatically.
277
290
 
278
- Right after `identify()`, do the following for the Android path:
291
+ #### TypeScript setup (Android)
279
292
 
280
- 1. Get the current notification authorization status with `getPushAuthorizationStatus()`.
281
- 2. Call `handleRegularOpen(authStatus)` with that status.
282
- 3. Optionally call `registerForPushNotifications()` to prompt for permission (Android 13+).
293
+ After native initialization, the only required TypeScript call is `identify()`:
283
294
 
284
295
  ```typescript
285
296
  import { Platform } from 'react-native';
286
- import {
287
- initialize,
288
- identify,
289
- getPushAuthorizationStatus,
290
- registerForPushNotifications,
291
- handleRegularOpen,
292
- type AttentiveSdkConfiguration,
293
- type PushAuthorizationStatus,
294
- } from 'attentive-react-native-sdk';
297
+ import { initialize, identify } from 'attentive-react-native-sdk';
295
298
 
296
299
  // Inside your root component (e.g. App.tsx useEffect):
297
-
298
- // iOS only: initialize from TypeScript.
299
- // Android: initialization must be done natively from Application.onCreate() — see README.
300
300
  if (Platform.OS === 'ios') {
301
301
  initialize(config);
302
302
  }
303
303
 
304
304
  identify({ email: 'user@example.com', clientUserId: 'id-123' });
305
-
306
- if (Platform.OS === 'android') {
307
- getPushAuthorizationStatus()
308
- .then((authStatus: PushAuthorizationStatus) => {
309
- handleRegularOpen(authStatus);
310
- })
311
- .catch(() => {
312
- handleRegularOpen('authorized'); // fallback
313
- });
314
- registerForPushNotifications(); // Shows permission dialog on Android 13+
315
- }
316
305
  ```
317
306
 
318
- #### 2. When app returns to foreground (Android)
307
+ #### Push notifications on Android (FCM)
319
308
 
320
- Subscribe to `AppState` and, when the app becomes `active`, get the current status and call `handleRegularOpen` again:
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.
321
310
 
322
- ```typescript
323
- import { AppState } from 'react-native';
324
- import { getPushAuthorizationStatus, handleRegularOpen } from 'attentive-react-native-sdk';
325
- import type { PushAuthorizationStatus } from 'attentive-react-native-sdk';
326
-
327
- const subscription = AppState.addEventListener('change', (nextAppState) => {
328
- if (nextAppState === 'active' && Platform.OS === 'android') {
329
- getPushAuthorizationStatus()
330
- .then((authStatus: PushAuthorizationStatus) => {
331
- handleRegularOpen(authStatus);
332
- })
333
- .catch(() => {
334
- handleRegularOpen('authorized');
335
- });
336
- }
337
- });
338
-
339
- // Cleanup on unmount:
340
- return () => subscription.remove();
341
- ```
311
+ ##### If you already have a FirebaseMessagingService subclass
342
312
 
343
- #### 3. Optional: Register FCM token (Android)
313
+ If your app has an existing `FirebaseMessagingService` subclass for other purposes, route Attentive messages through to the SDK:
344
314
 
345
- **Recommended:** This React Native SDK’s Android native module depends on Attentive Android SDK **2.1.1**, which exposes `AttentiveSdk.getPushTokenWithCallback`. Calling `registerForPushNotifications()` from JS triggers that API: the SDK requests permission (when needed), fetches the FCM token, and registers it with Attentive. No separate native code is required.
315
+ ```kotlin
316
+ import com.attentive.androidsdk.AttentiveSdk
317
+ import com.google.firebase.messaging.FirebaseMessagingService
318
+ import com.google.firebase.messaging.RemoteMessage
346
319
 
347
- **Alternative (token from JS):** If you obtain the FCM token elsewhere (e.g. Firebase Messaging), use `registerDeviceTokenWithCallback` and then call `handleRegularOpen` in the callback:
320
+ class YourFirebaseMessagingService : FirebaseMessagingService() {
348
321
 
349
- ```typescript
350
- import { registerDeviceTokenWithCallback, handleRegularOpen } from 'attentive-react-native-sdk';
351
-
352
- getPushAuthorizationStatus().then((authStatus) => {
353
- registerDeviceTokenWithCallback(
354
- fcmToken,
355
- authStatus,
356
- (data, url, response, error) => {
357
- if (error) {
358
- console.error('Attentive token registration failed', error);
359
- }
360
- handleRegularOpen(authStatus);
322
+ override fun onMessageReceived(remoteMessage: RemoteMessage) {
323
+ super.onMessageReceived(remoteMessage)
324
+ if (AttentiveSdk.isAttentiveFirebaseMessage(remoteMessage)) {
325
+ AttentiveSdk.sendNotification(remoteMessage)
326
+ }
327
+ // Handle your own messages below...
361
328
  }
362
- );
363
- });
329
+ }
364
330
  ```
365
331
 
366
- #### 4. Optional: Handle notification opens and foreground (Android)
367
-
368
- If you handle FCM messages (e.g. with `@react-native-firebase/messaging`), you can report notification opens and foreground receives the same way as on iOS:
332
+ ##### Notification opens (singleTask apps)
369
333
 
370
- - **User opened notification (background/inactive):** `handlePushOpen(payload, authorizationStatus)`
371
- - **Notification received while app in foreground:** `handleForegroundPush(payload, authorizationStatus)`
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:
372
335
 
373
- Get `authorizationStatus` via `getPushAuthorizationStatus()` when handling the event.
336
+ ```kotlin
337
+ import android.content.Intent
374
338
 
375
- #### Complete Android flow (reference)
339
+ class MainActivity : ReactActivity() {
376
340
 
377
- The [Bonni](https://github.com/attentive-mobile/attentive-react-native-sdk/tree/main/Bonni) example app ([App.tsx](https://github.com/attentive-mobile/attentive-react-native-sdk/blob/main/Bonni/App.tsx)) implements the full flow:
341
+ override fun onNewIntent(intent: Intent?) {
342
+ super.onNewIntent(intent)
343
+ intent?.let { setIntent(it) }
344
+ }
345
+ }
346
+ ```
378
347
 
379
- 1. **Launch:** Native `AttentiveSdk.initialize(config)` (from `Application.onCreate()`) TypeScript `identify` `getPushAuthorizationStatus()` `handleRegularOpen(authStatus)` `registerForPushNotifications()`.
380
- 2. **Foreground:** `AppState.addEventListener('change', …)` → when `active` and Android → `getPushAuthorizationStatus()` → `handleRegularOpen(authStatus)`.
381
- 3. **Optional:** When FCM token is available → `registerDeviceTokenWithCallback(token, authStatus, callback)` → in callback call `handleRegularOpen(authStatus)`.
382
- 4. **Optional:** When user opens a notification or receives one in foreground → `handlePushOpen` / `handleForegroundPush` with payload and status from `getPushAuthorizationStatus()`.
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.
383
349
 
384
350
  ---
385
351
 
@@ -393,9 +359,9 @@ import { registerForPushNotifications } from 'attentive-react-native-sdk';
393
359
  registerForPushNotifications();
394
360
  ```
395
361
 
396
- #### Register Device Token (iOS: APNs / Android: FCM)
362
+ #### Register Device Token (iOS)
397
363
 
398
- When your app receives a device token (APNs on iOS, FCM on Android), register it with the Attentive backend:
364
+ When your iOS app receives an APNs device token, register it with the Attentive backend:
399
365
 
400
366
  ```typescript
401
367
  import { registerDeviceToken } from 'attentive-react-native-sdk';
@@ -412,7 +378,7 @@ The `authorizationStatus` parameter should be one of:
412
378
  - `'provisional'` - Provisional authorization (quiet notifications)
413
379
  - `'ephemeral'` - App Clip notifications
414
380
 
415
- #### Handle Push Notification Opens (iOS and Android)
381
+ #### Handle Push Notification Opens (iOS)
416
382
 
417
383
  When a user taps on a push notification, track the event:
418
384
 
@@ -428,7 +394,7 @@ handlePushOpened(
428
394
  );
429
395
  ```
430
396
 
431
- #### Handle Foreground Notifications (iOS and Android)
397
+ #### Handle Foreground Notifications (iOS)
432
398
 
433
399
  When a notification arrives while the app is in the foreground:
434
400
 
@@ -523,9 +489,8 @@ func application(
523
489
  ```
524
490
 
525
491
  **Documentation:**
526
- - [Push Token Registration Guide](./PUSH_TOKEN_REGISTRATION_GUIDE.md) - Detailed guide for callback-based registration
527
- - [AppDelegate Callback Example](./APPDELEGATE_CALLBACK_EXAMPLE.md) - Complete AppDelegate implementation
528
- - [Push Notifications Setup](./PUSH_NOTIFICATIONS_SETUP.md) - General push notification setup
492
+ - [Push Notifications Integration Guide](./docs/PUSH_NOTIFICATIONS_INTEGRATION.md) - Callback-based registration, complete AppDelegate implementation, Android and iOS token flow
493
+ - [Push Notifications Setup](./docs/PUSH_NOTIFICATIONS_SETUP.md) - Apple Developer Portal, APNs certificates, and TestFlight configuration
529
494
  - [iOS Native SDK documentation](https://github.com/attentive-mobile/attentive-ios-sdk) - Native SDK reference
530
495
 
531
- For a full Android implementation (app launch, foreground, permission, and optional FCM), see the **[App Events on Android](#app-events-on-android)** section above.
496
+ For Android push notification integration, see the **[App Events on Android](#app-events-on-android)** section above.
@@ -88,7 +88,7 @@ class AttentiveReactNativeSdkModule(reactContext: ReactApplicationContext) :
88
88
  ) {
89
89
  debugHelper.initialize(enableDebugger)
90
90
 
91
- Log.w(
91
+ Log.d(
92
92
  TAG,
93
93
  "[AttentiveSDK] initialize() called from TypeScript is a NO-OP on Android. " +
94
94
  "You must call AttentiveSdk.initialize(config) from your Application.onCreate() " +
@@ -187,17 +187,7 @@ class AttentiveReactNativeSdkModule(reactContext: ReactApplicationContext) :
187
187
  val itemsList = buildItems(items)
188
188
  val productViewEvent = ProductViewEvent.Builder().items(itemsList).deeplink(deeplink).build()
189
189
 
190
- try {
191
- AttentiveSdk.recordEvent(productViewEvent)
192
- } catch (e: Exception) {
193
- Log.e(
194
- TAG,
195
- "[AttentiveSDK] recordProductViewEvent failed — SDK may not be initialized. " +
196
- "On Android, call AttentiveSdk.initialize(config) from Application.onCreate() " +
197
- "before recording events. Error: ${e.message}"
198
- )
199
- return
200
- }
190
+ if (!recordEventSafely("recordProductViewEvent") { AttentiveSdk.recordEvent(productViewEvent) }) return
201
191
 
202
192
  if (debugHelper.isDebuggingEnabled()) {
203
193
  val debugData = mutableMapOf<String, Any>()
@@ -227,17 +217,7 @@ class AttentiveReactNativeSdkModule(reactContext: ReactApplicationContext) :
227
217
  }
228
218
  val purchaseEvent = purchaseBuilder.build()
229
219
 
230
- try {
231
- AttentiveSdk.recordEvent(purchaseEvent)
232
- } catch (e: Exception) {
233
- Log.e(
234
- TAG,
235
- "[AttentiveSDK] recordPurchaseEvent failed — SDK may not be initialized. " +
236
- "On Android, call AttentiveSdk.initialize(config) from Application.onCreate() " +
237
- "before recording events. Error: ${e.message}"
238
- )
239
- return
240
- }
220
+ if (!recordEventSafely("recordPurchaseEvent") { AttentiveSdk.recordEvent(purchaseEvent) }) return
241
221
 
242
222
  if (debugHelper.isDebuggingEnabled()) {
243
223
  val debugData = mutableMapOf<String, Any>()
@@ -260,17 +240,7 @@ class AttentiveReactNativeSdkModule(reactContext: ReactApplicationContext) :
260
240
  val itemsList = buildItems(items)
261
241
  val addToCartEvent = AddToCartEvent.Builder().items(itemsList).deeplink(deeplink).build()
262
242
 
263
- try {
264
- AttentiveSdk.recordEvent(addToCartEvent)
265
- } catch (e: Exception) {
266
- Log.e(
267
- TAG,
268
- "[AttentiveSDK] recordAddToCartEvent failed — SDK may not be initialized. " +
269
- "On Android, call AttentiveSdk.initialize(config) from Application.onCreate() " +
270
- "before recording events. Error: ${e.message}"
271
- )
272
- return
273
- }
243
+ if (!recordEventSafely("recordAddToCartEvent") { AttentiveSdk.recordEvent(addToCartEvent) }) return
274
244
 
275
245
  if (debugHelper.isDebuggingEnabled()) {
276
246
  val debugData = mutableMapOf<String, Any>()
@@ -290,17 +260,7 @@ class AttentiveReactNativeSdkModule(reactContext: ReactApplicationContext) :
290
260
  val propertiesMap = convertToStringMap(properties.toHashMap())
291
261
  val customEvent = CustomEvent.Builder().type(type).properties(propertiesMap).build()
292
262
 
293
- try {
294
- AttentiveSdk.recordEvent(customEvent)
295
- } catch (e: Exception) {
296
- Log.e(
297
- TAG,
298
- "[AttentiveSDK] recordCustomEvent failed — SDK may not be initialized. " +
299
- "On Android, call AttentiveSdk.initialize(config) from Application.onCreate() " +
300
- "before recording events. Error: ${e.message}"
301
- )
302
- return
303
- }
263
+ if (!recordEventSafely("recordCustomEvent") { AttentiveSdk.recordEvent(customEvent) }) return
304
264
 
305
265
  if (debugHelper.isDebuggingEnabled()) {
306
266
  val debugData = mutableMapOf<String, Any>()
@@ -844,6 +804,36 @@ class AttentiveReactNativeSdkModule(reactContext: ReactApplicationContext) :
844
804
  * @param rawItems The raw item array as received from the React Native bridge.
845
805
  * @return A list of maps, one per item, containing all present fields.
846
806
  */
807
+ /**
808
+ * Executes [block] (which calls [AttentiveSdk.recordEvent]) and catches any [Exception].
809
+ *
810
+ * When an exception is caught the log always includes the exception's simple class name so
811
+ * callers can distinguish an uninitialized-SDK error (typically [IllegalStateException]) from
812
+ * a programming mistake such as [NullPointerException] or [IllegalArgumentException] in event
813
+ * construction — both of which would have been silently misattributed to initialization
814
+ * failure under the previous broad catch-and-blame pattern.
815
+ *
816
+ * @param callerName Method name to include in the log for quick triage (e.g. "recordPurchaseEvent").
817
+ * @param block Lambda that performs the [AttentiveSdk.recordEvent] call.
818
+ * @return `true` if [block] completed without throwing, `false` if an exception was caught.
819
+ */
820
+ private fun recordEventSafely(callerName: String, block: () -> Unit): Boolean {
821
+ return try {
822
+ block()
823
+ true
824
+ } catch (e: Exception) {
825
+ // Include the exception class so the developer can tell apart an uninitialized SDK
826
+ // (IllegalStateException) from a malformed-event bug (NullPointerException, etc.)
827
+ Log.e(
828
+ TAG,
829
+ "[AttentiveSDK] $callerName failed with ${e.javaClass.simpleName}: ${e.message}. " +
830
+ "If the SDK was not initialized via AttentiveSdk.initialize() in Application.onCreate(), " +
831
+ "that is the most likely cause. Otherwise, inspect the exception type above."
832
+ )
833
+ false
834
+ }
835
+ }
836
+
847
837
  private fun extractItemsDebugData(rawItems: ReadableArray): List<Map<String, Any>> {
848
838
  val result = mutableListOf<Map<String, Any>>()
849
839
  for (i in 0 until rawItems.size()) {
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.7",
3
+ "version": "2.0.1",
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
@@ -1,7 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <Workspace
3
- version = "1.0">
4
- <FileRef
5
- location = "self:">
6
- </FileRef>
7
- </Workspace>
@@ -1,14 +0,0 @@
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>SchemeUserState</key>
6
- <dict>
7
- <key>AttentiveReactNativeSdk.xcscheme_^#shared#^_</key>
8
- <dict>
9
- <key>orderHint</key>
10
- <integer>0</integer>
11
- </dict>
12
- </dict>
13
- </dict>
14
- </plist>