@attentive-mobile/attentive-react-native-sdk 2.0.0-beta.7 → 2.0.0-beta.8
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 +63 -111
- package/android/src/main/kotlin/com/attentivereactnativesdk/AttentiveReactNativeSdkModule.kt +35 -45
- package/package.json +1 -1
- package/ios/AttentiveReactNativeSdk.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/ios/AttentiveReactNativeSdk.xcodeproj/project.xcworkspace/xcuserdata/zheref.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/AttentiveReactNativeSdk.xcodeproj/xcuserdata/zheref.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
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.
|
|
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
|
|
|
@@ -109,15 +113,14 @@ class MainApplication : Application(), ReactApplication {
|
|
|
109
113
|
.logLevel(AttentiveLogLevel.VERBOSE)
|
|
110
114
|
.build()
|
|
111
115
|
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
+
// Application.onCreate() is always called on the main thread by the Android system,
|
|
117
|
+
// so no thread-switching wrapper is needed here.
|
|
118
|
+
AttentiveSdk.initialize(config)
|
|
116
119
|
}
|
|
117
120
|
}
|
|
118
121
|
```
|
|
119
122
|
|
|
120
|
-
After the native initialization, all other SDK operations (`identify`, `recordAddToCartEvent`, `recordPurchaseEvent`, etc.) are called from TypeScript as normal on both platforms.
|
|
123
|
+
After the native initialization, all other SDK operations (`identify`, `recordAddToCartEvent`, `recordPurchaseEvent`, etc.) are called from TypeScript as normal on both platforms.
|
|
121
124
|
|
|
122
125
|
> **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
126
|
|
|
@@ -218,7 +221,7 @@ Attentive.identify({phone: '+15556667777'};)
|
|
|
218
221
|
|
|
219
222
|
### Push Notifications (iOS and Android)
|
|
220
223
|
|
|
221
|
-
The SDK supports push notification integration on both iOS (APNs) and Android (
|
|
224
|
+
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
225
|
|
|
223
226
|
> **iOS — required setup:** Your AppDelegate **must** forward notification
|
|
224
227
|
> responses to the SDK for push tracking to work. Add this single line to your
|
|
@@ -243,22 +246,9 @@ The SDK supports push notification integration on both iOS (APNs) and Android (r
|
|
|
243
246
|
|
|
244
247
|
### App Events on Android
|
|
245
248
|
|
|
246
|
-
|
|
249
|
+
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.
|
|
247
250
|
|
|
248
|
-
|
|
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. |
|
|
255
|
-
|
|
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.
|
|
251
|
+
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
252
|
|
|
263
253
|
#### Prerequisites
|
|
264
254
|
|
|
@@ -271,115 +261,78 @@ This section describes how to implement Attentive app events on Android so they
|
|
|
271
261
|
</manifest>
|
|
272
262
|
```
|
|
273
263
|
|
|
274
|
-
2. **
|
|
275
|
-
|
|
276
|
-
#### 1. On app launch (Android)
|
|
264
|
+
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
265
|
|
|
278
|
-
|
|
266
|
+
#### TypeScript setup (Android)
|
|
279
267
|
|
|
280
|
-
|
|
281
|
-
2. Call `handleRegularOpen(authStatus)` with that status.
|
|
282
|
-
3. Optionally call `registerForPushNotifications()` to prompt for permission (Android 13+).
|
|
268
|
+
After native initialization, the only required TypeScript call is `identify()`:
|
|
283
269
|
|
|
284
270
|
```typescript
|
|
285
271
|
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';
|
|
272
|
+
import { initialize, identify } from 'attentive-react-native-sdk';
|
|
295
273
|
|
|
296
274
|
// 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
275
|
if (Platform.OS === 'ios') {
|
|
301
276
|
initialize(config);
|
|
302
277
|
}
|
|
303
278
|
|
|
304
279
|
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
280
|
```
|
|
317
281
|
|
|
318
|
-
####
|
|
282
|
+
#### Push notifications on Android (FCM)
|
|
319
283
|
|
|
320
|
-
|
|
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.
|
|
321
285
|
|
|
322
|
-
|
|
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
|
-
```
|
|
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`:
|
|
342
287
|
|
|
343
|
-
|
|
288
|
+
```kotlin
|
|
289
|
+
import com.attentive.androidsdk.AttentiveSdk
|
|
290
|
+
import com.google.firebase.messaging.FirebaseMessagingService
|
|
291
|
+
import com.google.firebase.messaging.RemoteMessage
|
|
344
292
|
|
|
345
|
-
|
|
293
|
+
class AttentiveMessagingService : FirebaseMessagingService() {
|
|
346
294
|
|
|
347
|
-
|
|
295
|
+
override fun onNewToken(token: String) {
|
|
296
|
+
super.onNewToken(token)
|
|
297
|
+
// Register the FCM token with the Attentive SDK
|
|
298
|
+
AttentiveSdk.registerDeviceToken(token)
|
|
299
|
+
}
|
|
348
300
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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);
|
|
301
|
+
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
|
302
|
+
super.onMessageReceived(remoteMessage)
|
|
303
|
+
// Handle foreground push delivery
|
|
304
|
+
AttentiveSdk.handleForegroundPush(remoteMessage.data)
|
|
361
305
|
}
|
|
362
|
-
|
|
363
|
-
});
|
|
306
|
+
}
|
|
364
307
|
```
|
|
365
308
|
|
|
366
|
-
|
|
309
|
+
For notification opens (when the user taps a push notification), handle the intent in your main `Activity`:
|
|
367
310
|
|
|
368
|
-
|
|
311
|
+
```kotlin
|
|
312
|
+
import com.attentive.androidsdk.AttentiveSdk
|
|
369
313
|
|
|
370
|
-
|
|
371
|
-
- **Notification received while app in foreground:** `handleForegroundPush(payload, authorizationStatus)`
|
|
314
|
+
class MainActivity : ReactActivity() {
|
|
372
315
|
|
|
373
|
-
|
|
316
|
+
override fun onResume() {
|
|
317
|
+
super.onResume()
|
|
318
|
+
intent?.let { AttentiveSdk.handlePushOpen(it) }
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
374
322
|
|
|
375
|
-
|
|
323
|
+
Declare the service in your `AndroidManifest.xml`:
|
|
376
324
|
|
|
377
|
-
|
|
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
|
+
```
|
|
378
334
|
|
|
379
|
-
|
|
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()`.
|
|
335
|
+
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
336
|
|
|
384
337
|
---
|
|
385
338
|
|
|
@@ -393,9 +346,9 @@ import { registerForPushNotifications } from 'attentive-react-native-sdk';
|
|
|
393
346
|
registerForPushNotifications();
|
|
394
347
|
```
|
|
395
348
|
|
|
396
|
-
#### Register Device Token (iOS
|
|
349
|
+
#### Register Device Token (iOS)
|
|
397
350
|
|
|
398
|
-
When your app receives
|
|
351
|
+
When your iOS app receives an APNs device token, register it with the Attentive backend:
|
|
399
352
|
|
|
400
353
|
```typescript
|
|
401
354
|
import { registerDeviceToken } from 'attentive-react-native-sdk';
|
|
@@ -412,7 +365,7 @@ The `authorizationStatus` parameter should be one of:
|
|
|
412
365
|
- `'provisional'` - Provisional authorization (quiet notifications)
|
|
413
366
|
- `'ephemeral'` - App Clip notifications
|
|
414
367
|
|
|
415
|
-
#### Handle Push Notification Opens (iOS
|
|
368
|
+
#### Handle Push Notification Opens (iOS)
|
|
416
369
|
|
|
417
370
|
When a user taps on a push notification, track the event:
|
|
418
371
|
|
|
@@ -428,7 +381,7 @@ handlePushOpened(
|
|
|
428
381
|
);
|
|
429
382
|
```
|
|
430
383
|
|
|
431
|
-
#### Handle Foreground Notifications (iOS
|
|
384
|
+
#### Handle Foreground Notifications (iOS)
|
|
432
385
|
|
|
433
386
|
When a notification arrives while the app is in the foreground:
|
|
434
387
|
|
|
@@ -523,9 +476,8 @@ func application(
|
|
|
523
476
|
```
|
|
524
477
|
|
|
525
478
|
**Documentation:**
|
|
526
|
-
- [Push
|
|
527
|
-
- [
|
|
528
|
-
- [Push Notifications Setup](./PUSH_NOTIFICATIONS_SETUP.md) - General push notification setup
|
|
479
|
+
- [Push Notifications Integration Guide](./docs/PUSH_NOTIFICATIONS_INTEGRATION.md) - Callback-based registration, complete AppDelegate implementation, Android and iOS token flow
|
|
480
|
+
- [Push Notifications Setup](./docs/PUSH_NOTIFICATIONS_SETUP.md) - Apple Developer Portal, APNs certificates, and TestFlight configuration
|
|
529
481
|
- [iOS Native SDK documentation](https://github.com/attentive-mobile/attentive-ios-sdk) - Native SDK reference
|
|
530
482
|
|
|
531
|
-
For
|
|
483
|
+
For Android push notification integration, see the **[App Events on Android](#app-events-on-android)** section above.
|
package/android/src/main/kotlin/com/attentivereactnativesdk/AttentiveReactNativeSdkModule.kt
CHANGED
|
@@ -88,7 +88,7 @@ class AttentiveReactNativeSdkModule(reactContext: ReactApplicationContext) :
|
|
|
88
88
|
) {
|
|
89
89
|
debugHelper.initialize(enableDebugger)
|
|
90
90
|
|
|
91
|
-
Log.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
Binary file
|
|
@@ -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>
|