expo-facebook-analytics 1.0.6 โ†’ 1.1.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.
Files changed (27) hide show
  1. package/README.md +36 -196
  2. package/android/CMakeLists.txt +16 -0
  3. package/android/build.gradle +36 -11
  4. package/android/src/main/cpp/cpp-adapter.cpp +14 -0
  5. package/android/src/main/java/com/nitrofbanalytics/FacebookAnalyticsPackage.kt +30 -0
  6. package/android/src/main/java/com/nitrofbanalytics/HybridFacebookAnalytics.kt +63 -8
  7. package/expo-facebook-analytics.podspec +1 -1
  8. package/ios/HybridFacebookAnalytics.swift +54 -9
  9. package/lib/index.d.ts +33 -0
  10. package/lib/index.js +76 -19
  11. package/lib/specs/FacebookAnalytics.nitro.d.ts +10 -0
  12. package/nitro.json +8 -2
  13. package/nitrogen/generated/android/NitroFBAnalyticsOnLoad.cpp +2 -2
  14. package/nitrogen/generated/android/c++/JHybridFacebookAnalyticsSpec.cpp +24 -0
  15. package/nitrogen/generated/android/c++/JHybridFacebookAnalyticsSpec.hpp +8 -2
  16. package/nitrogen/generated/android/kotlin/com/margelo/nitro/com/nitrofbanalytics/HybridFacebookAnalyticsSpec.kt +24 -0
  17. package/nitrogen/generated/ios/NitroFBAnalytics+autolinking.rb +2 -0
  18. package/nitrogen/generated/ios/c++/HybridFacebookAnalyticsSpecSwift.hpp +36 -0
  19. package/nitrogen/generated/ios/swift/HybridFacebookAnalyticsSpec.swift +6 -0
  20. package/nitrogen/generated/ios/swift/HybridFacebookAnalyticsSpec_cxx.swift +66 -0
  21. package/nitrogen/generated/shared/c++/HybridFacebookAnalyticsSpec.cpp +6 -0
  22. package/nitrogen/generated/shared/c++/HybridFacebookAnalyticsSpec.hpp +6 -0
  23. package/package.json +9 -7
  24. package/plugin/build/withFacebookAnalyticsIOS.js +3 -1
  25. package/react-native.config.js +9 -1
  26. package/src/index.ts +84 -19
  27. package/src/specs/FacebookAnalytics.nitro.ts +12 -0
package/README.md CHANGED
@@ -2,45 +2,21 @@
2
2
 
3
3
  High-performance Facebook Analytics for React Native using [Nitro Modules](https://github.com/mrousavy/nitro).
4
4
 
5
- ## Features
5
+ ๐Ÿ“– **[Documentation](https://jasperaelvoet.github.io/expo-facebook-analytics/)** ยท ๐Ÿงช **[Example app](./example)**
6
6
 
7
- - Direct native Facebook SDK integration via Nitro Modules (zero-copy bridge)
8
- - Full event logging, user identity management, and device identifier access
9
- - Expo config plugin for automatic native setup
10
- - TypeScript-first with predefined event and parameter constants
11
- - iOS 13+ and Android SDK 21+
7
+ > **Minimal by design.** This library wraps only the Facebook **App Events /
8
+ > Analytics** APIs โ€” event logging, user identity, and device identifiers. It is
9
+ > **not** a full Facebook SDK (no Login, Sharing, Graph API, or Gaming). If you
10
+ > only need analytics and conversion tracking, that's the point: a tiny, fast
11
+ > surface area built on a zero-overhead Nitro/JSI bridge to the native SDK.
12
12
 
13
13
  ## Installation
14
14
 
15
15
  ```sh
16
- bun add expo-facebook-analytics react-native-nitro-modules
16
+ npx expo install expo-facebook-analytics react-native-nitro-modules
17
17
  ```
18
18
 
19
- or
20
-
21
- ```sh
22
- npm install expo-facebook-analytics react-native-nitro-modules
23
- ```
24
-
25
- ### Peer Dependencies
26
-
27
- - `react-native` >= 0.71
28
- - `react-native-nitro-modules` >= 0.35.0
29
- - `expo` >= 55.0.0 _(optional, for config plugin)_
30
-
31
- ### iOS
32
-
33
- ```sh
34
- cd ios && pod install
35
- ```
36
-
37
- ### Android
38
-
39
- No additional steps required โ€” Gradle handles the Facebook SDK dependency automatically.
40
-
41
- ## Expo Setup
42
-
43
- Add the plugin to your `app.json` / `app.config.js`:
19
+ Add the config plugin to your `app.json`:
44
20
 
45
21
  ```json
46
22
  {
@@ -50,8 +26,7 @@ Add the plugin to your `app.json` / `app.config.js`:
50
26
  "expo-facebook-analytics",
51
27
  {
52
28
  "appID": "YOUR_FACEBOOK_APP_ID",
53
- "clientToken": "YOUR_FACEBOOK_CLIENT_TOKEN",
54
- "displayName": "Your App Name"
29
+ "clientToken": "YOUR_FACEBOOK_CLIENT_TOKEN"
55
30
  }
56
31
  ]
57
32
  ]
@@ -59,183 +34,48 @@ Add the plugin to your `app.json` / `app.config.js`:
59
34
  }
60
35
  ```
61
36
 
62
- ### Plugin Options
37
+ The module ships native code, so it requires a [development build](https://docs.expo.dev/develop/development-builds/introduction/) โ€” it can't run in Expo Go.
63
38
 
64
- | Option | Type | Default | Description |
65
- | ------------------------------- | --------------------- | ------------- | ------------------------------------------ |
66
- | `appID` | `string` | **required** | Facebook App ID |
67
- | `clientToken` | `string` | **required** | Facebook Client Token |
68
- | `displayName` | `string` | App name | Display name for Facebook |
69
- | `scheme` | `string` | `fb{appID}` | URL scheme for deep linking |
70
- | `isAutoInitEnabled` | `boolean` | `true` | Auto-initialize Facebook SDK |
71
- | `autoLogAppEventsEnabled` | `boolean` | `true` | Automatically log app events |
72
- | `advertiserIDCollectionEnabled` | `boolean` | `true` | Enable advertiser ID collection |
73
- | `iosUserTrackingPermission` | `string` \| `false` | ATT prompt | Custom tracking permission text or disable |
74
-
75
- ### Manual Native Setup
76
-
77
- If you're not using Expo, refer to the [Facebook SDK documentation](https://developers.facebook.com/docs/app-events/getting-started-app-events-android/) for manual iOS and Android configuration.
78
-
79
- ## Usage
80
-
81
- ### Log Events
39
+ ## Quick start
82
40
 
83
41
  ```typescript
84
- import { logEvent, logPurchase, AppEvents, AppEventParams } from 'expo-facebook-analytics';
42
+ import { logEvent, logPurchase, AppEvents } from 'expo-facebook-analytics';
85
43
 
86
- // Simple event
87
44
  logEvent(AppEvents.ViewedContent);
88
-
89
- // Event with a numeric value
90
- logEvent(AppEvents.Searched, 1);
91
-
92
- // Event with parameters
93
- logEvent(AppEvents.AddedToCart, {
94
- [AppEventParams.ContentID]: 'product-123',
95
- [AppEventParams.ContentType]: 'product',
96
- [AppEventParams.Currency]: 'USD',
97
- });
98
-
99
- // Event with value and parameters
100
- logEvent(AppEvents.Purchased, 29.99, {
101
- [AppEventParams.Currency]: 'USD',
102
- [AppEventParams.NumItems]: 2,
103
- });
104
-
105
- // Log a purchase
106
- logPurchase(29.99, 'USD', {
107
- [AppEventParams.ContentID]: 'product-123',
108
- });
109
-
110
- // Log push notification open
111
- logPushNotificationOpen({ campaign: 'summer-sale' });
112
- ```
113
-
114
- ### User Identity
115
-
116
- ```typescript
117
- import { setUserID, getUserID, clearUserID, setUserData } from 'expo-facebook-analytics';
118
-
119
- // Set user ID for analytics
120
- setUserID('user-123');
121
-
122
- // Get current user ID
123
- const userId = getUserID();
124
-
125
- // Clear user ID
126
- clearUserID();
127
-
128
- // Set user data for advanced matching
129
- setUserData({
130
- email: 'user@example.com',
131
- firstName: 'John',
132
- lastName: 'Doe',
133
- gender: 'm',
134
- city: 'San Francisco',
135
- state: 'CA',
136
- country: 'US',
137
- });
45
+ logEvent(AppEvents.AddedToCart, { product: 'sku-123' });
46
+ logPurchase(29.99, 'USD');
138
47
  ```
139
48
 
140
- ### Device Identifiers
49
+ For deferred (consent-gated) initialization, set `isAutoInitEnabled: false` in the
50
+ plugin and call `initialize()` yourself. Enable the Facebook SDK's native logging
51
+ with `setLoggingEnabled(true)`. See the [documentation](https://jasperaelvoet.github.io/expo-facebook-analytics/) for the full API.
141
52
 
142
- ```typescript
143
- import { getAnonymousID, getAdvertiserID } from 'expo-facebook-analytics';
144
-
145
- const anonId = await getAnonymousID();
146
- const advertiserId = await getAdvertiserID(); // IDFA on iOS, AAID on Android
147
- ```
53
+ See the **[documentation](https://jasperaelvoet.github.io/expo-facebook-analytics/)** for the full API,
54
+ config-plugin options, manual initialization, and predefined constants.
148
55
 
149
- ### Configuration
150
-
151
- ```typescript
152
- import { setFlushBehavior, flush, setPushNotificationsDeviceToken, setPushNotificationsRegistrationId } from 'expo-facebook-analytics';
153
-
154
- // Control event batching: 'auto' (default) or 'explicit_only'
155
- setFlushBehavior('explicit_only');
156
-
157
- // Manually flush queued events
158
- flush();
159
-
160
- // Push notification tokens
161
- setPushNotificationsDeviceToken(apnsToken); // iOS
162
- setPushNotificationsRegistrationId(fcmToken); // Android
163
- ```
164
-
165
- ## API Reference
166
-
167
- ### Event Logging
168
-
169
- | Function | Description |
170
- | --------------------------- | ------------------------------------ |
171
- | `logEvent(name, ...args)` | Log a custom or predefined event |
172
- | `logPurchase(amount, currency, params?)` | Log a purchase event |
173
- | `logPushNotificationOpen(payload?)` | Log a push notification open |
174
-
175
- ### User Identity
176
-
177
- | Function | Description |
178
- | ----------------------- | ---------------------------------- |
179
- | `setUserID(id)` | Set the user ID for analytics |
180
- | `clearUserID()` | Clear the current user ID |
181
- | `getUserID()` | Get the current user ID |
182
- | `setUserData(data)` | Set user data for advanced matching|
183
-
184
- ### Device Identifiers
185
-
186
- | Function | Description |
187
- | --------------------- | ------------------------------------------- |
188
- | `getAnonymousID()` | Get the anonymous device ID |
189
- | `getAdvertiserID()` | Get IDFA (iOS) or AAID (Android) |
190
-
191
- ### Configuration
192
-
193
- | Function | Description |
194
- | ------------------------------------- | ---------------------------------- |
195
- | `setFlushBehavior(behavior)` | Set event flush behavior |
196
- | `flush()` | Flush queued events immediately |
197
- | `setPushNotificationsDeviceToken(t)` | Set APNs push token (iOS) |
198
- | `setPushNotificationsRegistrationId(id)` | Set FCM registration ID (Android) |
199
-
200
- ## Predefined Constants
201
-
202
- ### AppEvents
203
-
204
- `AchievedLevel`, `AdClick`, `AdImpression`, `AddedPaymentInfo`, `AddedToCart`, `AddedToWishlist`, `CompletedRegistration`, `CompletedTutorial`, `Contact`, `CustomizeProduct`, `Donate`, `FindLocation`, `InitiatedCheckout`, `Purchased`, `Rated`, `Schedule`, `Searched`, `SpentCredits`, `StartTrial`, `SubmitApplication`, `Subscribe`, `UnlockedAchievement`, `ViewedContent`
56
+ ## Requirements
205
57
 
206
- ### AppEventParams
58
+ | Tool | Version |
59
+ | ---------------------------- | ------- |
60
+ | Expo SDK | 56+ |
61
+ | React Native | 0.85+ |
62
+ | `react-native-nitro-modules` | 0.35.9+ |
63
+ | iOS deployment target | 16.4+ |
64
+ | Android `minSdkVersion` | 24+ |
207
65
 
208
- `AddType`, `Content`, `ContentID`, `ContentType`, `Currency`, `Description`, `Level`, `MaxRatingValue`, `NumItems`, `OrderId`, `PaymentInfoAvailable`, `RegistrationMethod`, `SearchString`, `Success`, `ValueNo`, `ValueYes`
66
+ Native SDKs: Facebook iOS/Android SDK 18. Requires the React Native New Architecture (default in SDK 56).
209
67
 
210
- ## Types
68
+ ## Contributing
211
69
 
212
- ```typescript
213
- type Params = { [key: string]: string | number };
214
-
215
- type UserData = Readonly<{
216
- email?: string;
217
- firstName?: string;
218
- lastName?: string;
219
- phone?: string;
220
- dateOfBirth?: string;
221
- gender?: 'm' | 'f';
222
- city?: string;
223
- state?: string;
224
- zip?: string;
225
- country?: string;
226
- }>;
227
-
228
- type AppEventsFlushBehavior = 'auto' | 'explicit_only';
70
+ ```sh
71
+ bun install # install dependencies
72
+ bun run nitrogen # regenerate native bindings
73
+ bun run prepare # build the library
74
+ bun test # run tests
75
+ bun run check # lint & format
229
76
  ```
230
77
 
231
- ## Requirements
232
-
233
- | Platform | Minimum Version |
234
- | -------- | --------------- |
235
- | iOS | 13.0 |
236
- | Android | SDK 21 |
237
-
238
- Native SDKs: Facebook SDK ~17.0
78
+ To run the example app, see [`example/`](./example).
239
79
 
240
80
  ## License
241
81
 
@@ -0,0 +1,16 @@
1
+ project(NitroFBAnalytics)
2
+ cmake_minimum_required(VERSION 3.9.0)
3
+
4
+ set(CMAKE_VERBOSE_MAKEFILE ON)
5
+ set(CMAKE_CXX_STANDARD 20)
6
+
7
+ # The shared library loaded by NitroFBAnalyticsOnLoad.initializeNative()
8
+ # (System.loadLibrary("NitroFBAnalytics")). Its real sources are added by the
9
+ # generated autolinking cmake below.
10
+ add_library(NitroFBAnalytics SHARED
11
+ src/main/cpp/cpp-adapter.cpp
12
+ )
13
+
14
+ # Adds the Nitrogen-generated C++ sources, headers, and links (fbjni,
15
+ # ReactAndroid, react-native-nitro-modules) to the NitroFBAnalytics target.
16
+ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/NitroFBAnalytics+autolinking.cmake)
@@ -7,44 +7,61 @@ buildscript {
7
7
  mavenCentral()
8
8
  }
9
9
  dependencies {
10
- classpath("com.android.tools.build:gradle:8.2.0")
11
- classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22")
10
+ classpath("com.android.tools.build:gradle:${safeExtGet('androidGradlePluginVersion', '8.9.2')}")
11
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', '2.1.20')}")
12
12
  }
13
13
  }
14
14
 
15
15
  apply plugin: 'com.android.library'
16
16
  apply plugin: 'kotlin-android'
17
17
 
18
- def nitrogenAutolinking = file("nitrogen/generated/android/NitroFBAnalytics-autolinking.gradle")
18
+ def nitrogenAutolinking = file("../nitrogen/generated/android/NitroFBAnalytics+autolinking.gradle")
19
19
  if (nitrogenAutolinking.exists()) {
20
20
  apply from: nitrogenAutolinking
21
21
  }
22
22
 
23
23
  android {
24
24
  namespace 'com.nitrofbanalytics'
25
- compileSdkVersion safeExtGet('compileSdkVersion', 34)
25
+ compileSdkVersion safeExtGet('compileSdkVersion', 36)
26
26
 
27
27
  defaultConfig {
28
- minSdkVersion safeExtGet('minSdkVersion', 21)
29
- targetSdkVersion safeExtGet('targetSdkVersion', 34)
28
+ minSdkVersion safeExtGet('minSdkVersion', 24)
29
+ targetSdkVersion safeExtGet('targetSdkVersion', 36)
30
+
31
+ externalNativeBuild {
32
+ cmake {
33
+ cppFlags "-O2", "-frtti", "-fexceptions", "-Wall", "-std=c++20"
34
+ arguments "-DANDROID_STL=c++_shared"
35
+ }
36
+ }
37
+ }
38
+
39
+ buildFeatures {
40
+ prefab true
41
+ }
42
+
43
+ externalNativeBuild {
44
+ cmake {
45
+ path "CMakeLists.txt"
46
+ }
30
47
  }
31
48
 
32
49
  sourceSets {
33
50
  main {
34
51
  java.srcDirs += [
35
52
  'src/main/java',
36
- 'nitrogen/generated/android/kotlin'
53
+ '../nitrogen/generated/android/kotlin'
37
54
  ]
38
55
  }
39
56
  }
40
57
 
41
58
  compileOptions {
42
- sourceCompatibility JavaVersion.VERSION_1_8
43
- targetCompatibility JavaVersion.VERSION_1_8
59
+ sourceCompatibility JavaVersion.VERSION_17
60
+ targetCompatibility JavaVersion.VERSION_17
44
61
  }
45
62
 
46
63
  kotlinOptions {
47
- jvmTarget = '1.8'
64
+ jvmTarget = '17'
48
65
  }
49
66
  }
50
67
 
@@ -55,6 +72,14 @@ repositories {
55
72
 
56
73
  dependencies {
57
74
  implementation 'com.facebook.react:react-native:+'
58
- implementation 'com.margelo.nitro:nitro-modules:+'
75
+ // react-native-nitro-modules does not publish `com.margelo.nitro:nitro-modules`
76
+ // to a Maven repo and autolinking doesn't substitute it, so depend on the
77
+ // autolinked Gradle project directly. Fall back to the coordinate for
78
+ // standalone builds where the project isn't part of the Gradle build.
79
+ if (findProject(':react-native-nitro-modules') != null) {
80
+ implementation project(':react-native-nitro-modules')
81
+ } else {
82
+ implementation 'com.margelo.nitro:nitro-modules:+'
83
+ }
59
84
  implementation 'com.facebook.android:facebook-android-sdk:18.0.3'
60
85
  }
@@ -0,0 +1,14 @@
1
+ #include <jni.h>
2
+ #include <fbjni/fbjni.h>
3
+
4
+ #include "NitroFBAnalyticsOnLoad.hpp"
5
+
6
+ // Entry point of libNitroFBAnalytics.so. Loaded by
7
+ // NitroFBAnalyticsOnLoad.initializeNative() (System.loadLibrary), this
8
+ // registers the "FacebookAnalytics" HybridObject with the Nitro registry so
9
+ // JS `createHybridObject("FacebookAnalytics")` can resolve it.
10
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
11
+ return facebook::jni::initialize(vm, [] {
12
+ margelo::nitro::fbanalytics::registerAllNatives();
13
+ });
14
+ }
@@ -0,0 +1,30 @@
1
+ package com.nitrofbanalytics
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+ import com.margelo.nitro.com.nitrofbanalytics.NitroFBAnalyticsOnLoad
8
+
9
+ /**
10
+ * React Native autolinking entry point for the Nitro module.
11
+ *
12
+ * Unlike iOS (where Nitro auto-registers via the podspec's autolinking files),
13
+ * Android has no auto-load mechanism for the C++ library. This package exists
14
+ * solely so React Native autolinking instantiates it and triggers
15
+ * [NitroFBAnalyticsOnLoad.initializeNative], which loads the native library and
16
+ * registers the "FacebookAnalytics" HybridObject in the Nitro registry.
17
+ */
18
+ class FacebookAnalyticsPackage : ReactPackage {
19
+ init {
20
+ NitroFBAnalyticsOnLoad.initializeNative()
21
+ }
22
+
23
+ override fun createNativeModules(
24
+ reactContext: ReactApplicationContext,
25
+ ): List<NativeModule> = emptyList()
26
+
27
+ override fun createViewManagers(
28
+ reactContext: ReactApplicationContext,
29
+ ): List<ViewManager<*, *>> = emptyList()
30
+ }
@@ -1,11 +1,14 @@
1
- package com.nitrofbanalytics
1
+ package com.margelo.nitro.com.nitrofbanalytics
2
2
 
3
3
  import android.os.Bundle
4
4
  import com.facebook.FacebookSdk
5
+ import com.facebook.LoggingBehavior
5
6
  import com.facebook.appevents.AppEventsConstants
6
7
  import com.facebook.appevents.AppEventsLogger
7
8
  import com.facebook.internal.AttributionIdentifiers
8
9
  import com.margelo.nitro.core.Promise
10
+ import kotlinx.coroutines.CoroutineScope
11
+ import kotlinx.coroutines.Dispatchers
9
12
  import java.math.BigDecimal
10
13
  import java.util.Currency
11
14
 
@@ -15,6 +18,52 @@ class HybridFacebookAnalytics : HybridFacebookAnalyticsSpec() {
15
18
  AppEventsLogger.newLogger(FacebookSdk.getApplicationContext())
16
19
  }
17
20
 
21
+ // Background scope for blocking SDK calls (Play Services I/O) so they never
22
+ // run on the JS thread.
23
+ private val ioScope = CoroutineScope(Dispatchers.IO)
24
+
25
+ // region Initialization & Runtime Configuration
26
+
27
+ override fun initialize() {
28
+ FacebookSdk.setAutoInitEnabled(true)
29
+ FacebookSdk.fullyInitialize()
30
+ }
31
+
32
+ override fun setAutoLogAppEventsEnabled(enabled: Boolean) {
33
+ FacebookSdk.setAutoLogAppEventsEnabled(enabled)
34
+ }
35
+
36
+ override fun setAdvertiserIDCollectionEnabled(enabled: Boolean) {
37
+ FacebookSdk.setAdvertiserIDCollectionEnabled(enabled)
38
+ }
39
+
40
+ override fun setAppID(appID: String) {
41
+ FacebookSdk.setApplicationId(appID)
42
+ }
43
+
44
+ override fun setClientToken(clientToken: String) {
45
+ FacebookSdk.setClientToken(clientToken)
46
+ }
47
+
48
+ override fun setLoggingEnabled(enabled: Boolean) {
49
+ val behaviors = listOf(
50
+ LoggingBehavior.APP_EVENTS,
51
+ LoggingBehavior.REQUESTS,
52
+ LoggingBehavior.DEVELOPER_ERRORS,
53
+ LoggingBehavior.INCLUDE_ACCESS_TOKENS
54
+ )
55
+ FacebookSdk.setIsDebugEnabled(enabled)
56
+ for (behavior in behaviors) {
57
+ if (enabled) {
58
+ FacebookSdk.addLoggingBehavior(behavior)
59
+ } else {
60
+ FacebookSdk.removeLoggingBehavior(behavior)
61
+ }
62
+ }
63
+ }
64
+
65
+ // endregion
66
+
18
67
  // region Event Logging
19
68
 
20
69
  override fun logEvent(eventName: String, valueToSum: Double, params: Map<String, String>) {
@@ -83,16 +132,22 @@ class HybridFacebookAnalytics : HybridFacebookAnalyticsSpec() {
83
132
  // region Device Identifiers
84
133
 
85
134
  override fun getAnonymousID(): Promise<String?> {
86
- return Promise.resolved(logger.anonymousAppDeviceGUID)
135
+ return Promise.resolved(
136
+ AppEventsLogger.getAnonymousAppDeviceGUID(FacebookSdk.getApplicationContext())
137
+ )
87
138
  }
88
139
 
89
140
  override fun getAdvertiserID(): Promise<String?> {
90
- return try {
91
- val context = FacebookSdk.getApplicationContext()
92
- val identifiers = AttributionIdentifiers.getAttributionIdentifiers(context)
93
- Promise.resolved(identifiers?.androidAdvertiserId)
94
- } catch (e: Exception) {
95
- Promise.resolved(null)
141
+ // AttributionIdentifiers performs blocking Play Services I/O, so run it
142
+ // off the JS thread on the IO dispatcher.
143
+ return Promise.async(ioScope) {
144
+ try {
145
+ val context = FacebookSdk.getApplicationContext()
146
+ val identifiers = AttributionIdentifiers.getAttributionIdentifiers(context)
147
+ identifiers?.androidAdvertiserId
148
+ } catch (e: Exception) {
149
+ null
150
+ }
96
151
  }
97
152
  }
98
153
 
@@ -12,7 +12,7 @@ Pod::Spec.new do |s|
12
12
  s.license = package['license']
13
13
  s.author = 'expo-facebook-analytics contributors'
14
14
  s.source = { :git => '.', :tag => s.version.to_s }
15
- s.platforms = { :ios => '13.0' }
15
+ s.platforms = { :ios => '16.4' }
16
16
  s.module_name = 'NitroFBAnalytics'
17
17
 
18
18
  s.source_files = [
@@ -5,6 +5,43 @@ import AdSupport
5
5
 
6
6
  class HybridFacebookAnalytics: HybridFacebookAnalyticsSpec {
7
7
 
8
+ // MARK: - Initialization & Runtime Configuration
9
+
10
+ func initialize() throws {
11
+ // On iOS, auto-init is controlled by Info.plist (FacebookAutoInitEnabled).
12
+ // When disabled, this performs the deferred initialization.
13
+ ApplicationDelegate.shared.initializeSDK()
14
+ }
15
+
16
+ func setAutoLogAppEventsEnabled(enabled: Bool) throws {
17
+ Settings.shared.isAutoLogAppEventsEnabled = enabled
18
+ }
19
+
20
+ func setAdvertiserIDCollectionEnabled(enabled: Bool) throws {
21
+ Settings.shared.isAdvertiserIDCollectionEnabled = enabled
22
+ }
23
+
24
+ func setAppID(appID: String) throws {
25
+ Settings.shared.appID = appID
26
+ }
27
+
28
+ func setClientToken(clientToken: String) throws {
29
+ Settings.shared.clientToken = clientToken
30
+ }
31
+
32
+ func setLoggingEnabled(enabled: Bool) throws {
33
+ let behaviors: [LoggingBehavior] = [
34
+ .appEvents, .networkRequests, .developerErrors, .informational,
35
+ ]
36
+ for behavior in behaviors {
37
+ if enabled {
38
+ Settings.shared.enableLoggingBehavior(behavior)
39
+ } else {
40
+ Settings.shared.disableLoggingBehavior(behavior)
41
+ }
42
+ }
43
+ }
44
+
8
45
  // MARK: - Event Logging
9
46
 
10
47
  func logEvent(eventName: String, valueToSum: Double, params: [String: String]) throws {
@@ -115,16 +152,24 @@ class HybridFacebookAnalytics: HybridFacebookAnalyticsSpec {
115
152
  // MARK: - Push Notifications
116
153
 
117
154
  func setPushNotificationsDeviceToken(token: String) throws {
118
- // Token comes as a hex string โ€” convert back to raw Data
119
- let hex = token.replacingOccurrences(of: " ", with: "")
120
- var data = Data()
121
- var index = hex.startIndex
122
- while index < hex.endIndex {
123
- let nextIndex = hex.index(index, offsetBy: 2)
124
- if let byte = UInt8(hex[index..<nextIndex], radix: 16) {
125
- data.append(byte)
155
+ // Token comes as a hex string โ€” convert back to raw Data.
156
+ // Iterate over UTF-8 bytes and pack each pair of hex digits into one byte.
157
+ var data = Data(capacity: token.utf8.count / 2)
158
+ var highNibble: UInt8? = nil
159
+ for ascii in token.utf8 {
160
+ let nibble: UInt8
161
+ switch ascii {
162
+ case 0x30...0x39: nibble = ascii - 0x30 // '0'-'9'
163
+ case 0x41...0x46: nibble = ascii - 0x41 + 10 // 'A'-'F'
164
+ case 0x61...0x66: nibble = ascii - 0x61 + 10 // 'a'-'f'
165
+ default: continue // skip spaces / non-hex
166
+ }
167
+ if let high = highNibble {
168
+ data.append((high << 4) | nibble)
169
+ highNibble = nil
170
+ } else {
171
+ highNibble = nibble
126
172
  }
127
- index = nextIndex
128
173
  }
129
174
  AppEvents.shared.setPushNotificationsDeviceToken(data)
130
175
  }
package/lib/index.d.ts CHANGED
@@ -1,6 +1,39 @@
1
1
  import type { AppEventsFlushBehavior, Params, UserData } from "./types";
2
2
  export type { AppEventsFlushBehavior, Params, UserData } from "./types";
3
3
  export { AppEventParams, AppEvents } from "./types";
4
+ /**
5
+ * Manually initialize the Facebook SDK.
6
+ *
7
+ * Only required when `isAutoInitEnabled` is set to `false` in the config plugin.
8
+ * Call this once, early in your app's lifecycle (e.g. in your root layout),
9
+ * after optionally configuring the app ID / client token at runtime.
10
+ */
11
+ export declare function initialize(): void;
12
+ /**
13
+ * Enable or disable automatic logging of app events at runtime.
14
+ */
15
+ export declare function setAutoLogAppEventsEnabled(enabled: boolean): void;
16
+ /**
17
+ * Enable or disable advertiser ID (IDFA / AAID) collection at runtime.
18
+ */
19
+ export declare function setAdvertiserIDCollectionEnabled(enabled: boolean): void;
20
+ /**
21
+ * Set the Facebook App ID at runtime (alternative to the config plugin).
22
+ * Call before {@link initialize} when configuring the SDK manually.
23
+ */
24
+ export declare function setAppID(appID: string): void;
25
+ /**
26
+ * Set the Facebook Client Token at runtime (alternative to the config plugin).
27
+ * Call before {@link initialize} when configuring the SDK manually.
28
+ */
29
+ export declare function setClientToken(clientToken: string): void;
30
+ /**
31
+ * Enable verbose Facebook SDK logging (app events, network requests, developer
32
+ * errors). Output is printed to the native console โ€” view it via the Xcode
33
+ * console / `xcrun simctl spawn booted log stream` (iOS) or `adb logcat` (Android).
34
+ * Intended for development only.
35
+ */
36
+ export declare function setLoggingEnabled(enabled: boolean): void;
4
37
  /**
5
38
  * Log a custom or predefined app event.
6
39
  * @param eventName - Event name (use AppEvents constants for predefined events)