expo-facebook-analytics 1.0.6 โ 1.1.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 +37 -196
- package/android/CMakeLists.txt +16 -0
- package/android/build.gradle +36 -11
- package/android/src/main/cpp/cpp-adapter.cpp +14 -0
- package/android/src/main/java/com/nitrofbanalytics/FacebookAnalyticsPackage.kt +30 -0
- package/android/src/main/java/com/nitrofbanalytics/HybridFacebookAnalytics.kt +77 -8
- package/expo-facebook-analytics.podspec +1 -1
- package/ios/HybridFacebookAnalytics.swift +67 -9
- package/lib/index.d.ts +52 -0
- package/lib/index.js +101 -19
- package/lib/specs/FacebookAnalytics.nitro.d.ts +22 -0
- package/nitro.json +8 -2
- package/nitrogen/generated/android/NitroFBAnalyticsOnLoad.cpp +2 -2
- package/nitrogen/generated/android/c++/JHybridFacebookAnalyticsSpec.cpp +32 -0
- package/nitrogen/generated/android/c++/JHybridFacebookAnalyticsSpec.hpp +10 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/com/nitrofbanalytics/HybridFacebookAnalyticsSpec.kt +32 -0
- package/nitrogen/generated/ios/NitroFBAnalytics+autolinking.rb +2 -0
- package/nitrogen/generated/ios/c++/HybridFacebookAnalyticsSpecSwift.hpp +48 -0
- package/nitrogen/generated/ios/swift/HybridFacebookAnalyticsSpec.swift +8 -0
- package/nitrogen/generated/ios/swift/HybridFacebookAnalyticsSpec_cxx.swift +88 -0
- package/nitrogen/generated/shared/c++/HybridFacebookAnalyticsSpec.cpp +8 -0
- package/nitrogen/generated/shared/c++/HybridFacebookAnalyticsSpec.hpp +8 -0
- package/package.json +9 -7
- package/plugin/build/withFacebookAnalyticsIOS.d.ts +9 -0
- package/plugin/build/withFacebookAnalyticsIOS.js +56 -15
- package/react-native.config.js +9 -1
- package/src/index.ts +109 -19
- package/src/specs/FacebookAnalytics.nitro.ts +24 -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
|
-
|
|
5
|
+
๐ **[Documentation](https://jasperaelvoet.github.io/expo-facebook-analytics/)** ยท ๐งช **[Example app](./example)**
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
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
|
-
|
|
16
|
+
npx expo install expo-facebook-analytics react-native-nitro-modules
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
|
|
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,49 @@ Add the plugin to your `app.json` / `app.config.js`:
|
|
|
59
34
|
}
|
|
60
35
|
```
|
|
61
36
|
|
|
62
|
-
|
|
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
|
-
|
|
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
|
|
42
|
+
import { logEvent, logPurchase, AppEvents } from 'expo-facebook-analytics';
|
|
85
43
|
|
|
86
|
-
// Simple event
|
|
87
44
|
logEvent(AppEvents.ViewedContent);
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
49
|
+
For deferred (consent-gated) initialization, set `isAutoInitEnabled: false` in the
|
|
50
|
+
plugin and call `initialize()` yourself; with `autoLogAppEventsEnabled: false`, also
|
|
51
|
+
call `activateApp()` so Meta still receives the install event. Enable the Facebook
|
|
52
|
+
SDK's native logging with `setLoggingEnabled(true)`. See the [documentation](https://jasperaelvoet.github.io/expo-facebook-analytics/) for the full API.
|
|
141
53
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const anonId = await getAnonymousID();
|
|
146
|
-
const advertiserId = await getAdvertiserID(); // IDFA on iOS, AAID on Android
|
|
147
|
-
```
|
|
54
|
+
See the **[documentation](https://jasperaelvoet.github.io/expo-facebook-analytics/)** for the full API,
|
|
55
|
+
config-plugin options, manual initialization, and predefined constants.
|
|
148
56
|
|
|
149
|
-
|
|
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`
|
|
57
|
+
## Requirements
|
|
205
58
|
|
|
206
|
-
|
|
59
|
+
| Tool | Version |
|
|
60
|
+
| ---------------------------- | ------- |
|
|
61
|
+
| Expo SDK | 56+ |
|
|
62
|
+
| React Native | 0.85+ |
|
|
63
|
+
| `react-native-nitro-modules` | 0.35.9+ |
|
|
64
|
+
| iOS deployment target | 16.4+ |
|
|
65
|
+
| Android `minSdkVersion` | 24+ |
|
|
207
66
|
|
|
208
|
-
|
|
67
|
+
Native SDKs: Facebook iOS/Android SDK 18. Requires the React Native New Architecture (default in SDK 56).
|
|
209
68
|
|
|
210
|
-
##
|
|
69
|
+
## Contributing
|
|
211
70
|
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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';
|
|
71
|
+
```sh
|
|
72
|
+
bun install # install dependencies
|
|
73
|
+
bun run nitrogen # regenerate native bindings
|
|
74
|
+
bun run prepare # build the library
|
|
75
|
+
bun test # run tests
|
|
76
|
+
bun run check # lint & format
|
|
229
77
|
```
|
|
230
78
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
| Platform | Minimum Version |
|
|
234
|
-
| -------- | --------------- |
|
|
235
|
-
| iOS | 13.0 |
|
|
236
|
-
| Android | SDK 21 |
|
|
237
|
-
|
|
238
|
-
Native SDKs: Facebook SDK ~17.0
|
|
79
|
+
To run the example app, see [`example/`](./example).
|
|
239
80
|
|
|
240
81
|
## License
|
|
241
82
|
|
|
@@ -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)
|
package/android/build.gradle
CHANGED
|
@@ -7,44 +7,61 @@ buildscript {
|
|
|
7
7
|
mavenCentral()
|
|
8
8
|
}
|
|
9
9
|
dependencies {
|
|
10
|
-
classpath("com.android.tools.build:gradle
|
|
11
|
-
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin
|
|
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
|
|
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',
|
|
25
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 36)
|
|
26
26
|
|
|
27
27
|
defaultConfig {
|
|
28
|
-
minSdkVersion safeExtGet('minSdkVersion',
|
|
29
|
-
targetSdkVersion safeExtGet('targetSdkVersion',
|
|
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.
|
|
43
|
-
targetCompatibility JavaVersion.
|
|
59
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
60
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
44
61
|
}
|
|
45
62
|
|
|
46
63
|
kotlinOptions {
|
|
47
|
-
jvmTarget = '
|
|
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
|
-
|
|
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,15 @@
|
|
|
1
|
-
package com.nitrofbanalytics
|
|
1
|
+
package com.margelo.nitro.com.nitrofbanalytics
|
|
2
2
|
|
|
3
|
+
import android.app.Application
|
|
3
4
|
import android.os.Bundle
|
|
4
5
|
import com.facebook.FacebookSdk
|
|
6
|
+
import com.facebook.LoggingBehavior
|
|
5
7
|
import com.facebook.appevents.AppEventsConstants
|
|
6
8
|
import com.facebook.appevents.AppEventsLogger
|
|
7
9
|
import com.facebook.internal.AttributionIdentifiers
|
|
8
10
|
import com.margelo.nitro.core.Promise
|
|
11
|
+
import kotlinx.coroutines.CoroutineScope
|
|
12
|
+
import kotlinx.coroutines.Dispatchers
|
|
9
13
|
import java.math.BigDecimal
|
|
10
14
|
import java.util.Currency
|
|
11
15
|
|
|
@@ -15,8 +19,67 @@ class HybridFacebookAnalytics : HybridFacebookAnalyticsSpec() {
|
|
|
15
19
|
AppEventsLogger.newLogger(FacebookSdk.getApplicationContext())
|
|
16
20
|
}
|
|
17
21
|
|
|
22
|
+
// Background scope for blocking SDK calls (Play Services I/O) so they never
|
|
23
|
+
// run on the JS thread.
|
|
24
|
+
private val ioScope = CoroutineScope(Dispatchers.IO)
|
|
25
|
+
|
|
26
|
+
// region Initialization & Runtime Configuration
|
|
27
|
+
|
|
28
|
+
override fun initialize() {
|
|
29
|
+
FacebookSdk.setAutoInitEnabled(true)
|
|
30
|
+
FacebookSdk.fullyInitialize()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override fun setAutoInitEnabled(enabled: Boolean) {
|
|
34
|
+
FacebookSdk.setAutoInitEnabled(enabled)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
override fun setAutoLogAppEventsEnabled(enabled: Boolean) {
|
|
38
|
+
FacebookSdk.setAutoLogAppEventsEnabled(enabled)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
override fun setAdvertiserIDCollectionEnabled(enabled: Boolean) {
|
|
42
|
+
FacebookSdk.setAdvertiserIDCollectionEnabled(enabled)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override fun setAppID(appID: String) {
|
|
46
|
+
FacebookSdk.setApplicationId(appID)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
override fun setClientToken(clientToken: String) {
|
|
50
|
+
FacebookSdk.setClientToken(clientToken)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override fun setLoggingEnabled(enabled: Boolean) {
|
|
54
|
+
val behaviors = listOf(
|
|
55
|
+
LoggingBehavior.APP_EVENTS,
|
|
56
|
+
LoggingBehavior.REQUESTS,
|
|
57
|
+
LoggingBehavior.DEVELOPER_ERRORS,
|
|
58
|
+
LoggingBehavior.INCLUDE_ACCESS_TOKENS
|
|
59
|
+
)
|
|
60
|
+
FacebookSdk.setIsDebugEnabled(enabled)
|
|
61
|
+
for (behavior in behaviors) {
|
|
62
|
+
if (enabled) {
|
|
63
|
+
FacebookSdk.addLoggingBehavior(behavior)
|
|
64
|
+
} else {
|
|
65
|
+
FacebookSdk.removeLoggingBehavior(behavior)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// endregion
|
|
71
|
+
|
|
18
72
|
// region Event Logging
|
|
19
73
|
|
|
74
|
+
override fun activateApp() {
|
|
75
|
+
// Publishes the install (with the Play install referrer) once per device,
|
|
76
|
+
// then the launch event โ the only path that does so when automatic
|
|
77
|
+
// event logging is off.
|
|
78
|
+
val application = FacebookSdk.getApplicationContext() as? Application
|
|
79
|
+
?: throw IllegalStateException("The Facebook SDK has no Application context; call initialize() first")
|
|
80
|
+
AppEventsLogger.activateApp(application)
|
|
81
|
+
}
|
|
82
|
+
|
|
20
83
|
override fun logEvent(eventName: String, valueToSum: Double, params: Map<String, String>) {
|
|
21
84
|
val bundle = mapToBundle(params)
|
|
22
85
|
logger.logEvent(eventName, valueToSum, bundle)
|
|
@@ -83,16 +146,22 @@ class HybridFacebookAnalytics : HybridFacebookAnalyticsSpec() {
|
|
|
83
146
|
// region Device Identifiers
|
|
84
147
|
|
|
85
148
|
override fun getAnonymousID(): Promise<String?> {
|
|
86
|
-
return Promise.resolved(
|
|
149
|
+
return Promise.resolved(
|
|
150
|
+
AppEventsLogger.getAnonymousAppDeviceGUID(FacebookSdk.getApplicationContext())
|
|
151
|
+
)
|
|
87
152
|
}
|
|
88
153
|
|
|
89
154
|
override fun getAdvertiserID(): Promise<String?> {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
155
|
+
// AttributionIdentifiers performs blocking Play Services I/O, so run it
|
|
156
|
+
// off the JS thread on the IO dispatcher.
|
|
157
|
+
return Promise.async(ioScope) {
|
|
158
|
+
try {
|
|
159
|
+
val context = FacebookSdk.getApplicationContext()
|
|
160
|
+
val identifiers = AttributionIdentifiers.getAttributionIdentifiers(context)
|
|
161
|
+
identifiers?.androidAdvertiserId
|
|
162
|
+
} catch (e: Exception) {
|
|
163
|
+
null
|
|
164
|
+
}
|
|
96
165
|
}
|
|
97
166
|
}
|
|
98
167
|
|
|
@@ -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 => '
|
|
15
|
+
s.platforms = { :ios => '16.4' }
|
|
16
16
|
s.module_name = 'NitroFBAnalytics'
|
|
17
17
|
|
|
18
18
|
s.source_files = [
|
|
@@ -5,8 +5,58 @@ 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 setAutoInitEnabled(enabled: Bool) throws {
|
|
17
|
+
// The iOS SDK dropped auto-initialization in v9; `initialize()` is the
|
|
18
|
+
// only way it starts, so there is nothing to persist or undo here.
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
func setAutoLogAppEventsEnabled(enabled: Bool) throws {
|
|
22
|
+
Settings.shared.isAutoLogAppEventsEnabled = enabled
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func setAdvertiserIDCollectionEnabled(enabled: Bool) throws {
|
|
26
|
+
Settings.shared.isAdvertiserIDCollectionEnabled = enabled
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
func setAppID(appID: String) throws {
|
|
30
|
+
Settings.shared.appID = appID
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
func setClientToken(clientToken: String) throws {
|
|
34
|
+
Settings.shared.clientToken = clientToken
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func setLoggingEnabled(enabled: Bool) throws {
|
|
38
|
+
let behaviors: [LoggingBehavior] = [
|
|
39
|
+
.appEvents, .networkRequests, .developerErrors, .informational,
|
|
40
|
+
]
|
|
41
|
+
for behavior in behaviors {
|
|
42
|
+
if enabled {
|
|
43
|
+
Settings.shared.enableLoggingBehavior(behavior)
|
|
44
|
+
} else {
|
|
45
|
+
Settings.shared.disableLoggingBehavior(behavior)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
8
50
|
// MARK: - Event Logging
|
|
9
51
|
|
|
52
|
+
func activateApp() throws {
|
|
53
|
+
// Publishes the install and launch events. The SDK insists on the main
|
|
54
|
+
// thread for this call; Nitro calls arrive on the JS thread.
|
|
55
|
+
DispatchQueue.main.async {
|
|
56
|
+
AppEvents.shared.activateApp()
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
10
60
|
func logEvent(eventName: String, valueToSum: Double, params: [String: String]) throws {
|
|
11
61
|
let fbParams: [AppEvents.ParameterName: Any] = params.reduce(into: [:]) { result, pair in
|
|
12
62
|
result[AppEvents.ParameterName(pair.key)] = pair.value
|
|
@@ -115,16 +165,24 @@ class HybridFacebookAnalytics: HybridFacebookAnalyticsSpec {
|
|
|
115
165
|
// MARK: - Push Notifications
|
|
116
166
|
|
|
117
167
|
func setPushNotificationsDeviceToken(token: String) throws {
|
|
118
|
-
// Token comes as a hex string โ convert back to raw Data
|
|
119
|
-
|
|
120
|
-
var data = Data()
|
|
121
|
-
var
|
|
122
|
-
|
|
123
|
-
let
|
|
124
|
-
|
|
125
|
-
|
|
168
|
+
// Token comes as a hex string โ convert back to raw Data.
|
|
169
|
+
// Iterate over UTF-8 bytes and pack each pair of hex digits into one byte.
|
|
170
|
+
var data = Data(capacity: token.utf8.count / 2)
|
|
171
|
+
var highNibble: UInt8? = nil
|
|
172
|
+
for ascii in token.utf8 {
|
|
173
|
+
let nibble: UInt8
|
|
174
|
+
switch ascii {
|
|
175
|
+
case 0x30...0x39: nibble = ascii - 0x30 // '0'-'9'
|
|
176
|
+
case 0x41...0x46: nibble = ascii - 0x41 + 10 // 'A'-'F'
|
|
177
|
+
case 0x61...0x66: nibble = ascii - 0x61 + 10 // 'a'-'f'
|
|
178
|
+
default: continue // skip spaces / non-hex
|
|
179
|
+
}
|
|
180
|
+
if let high = highNibble {
|
|
181
|
+
data.append((high << 4) | nibble)
|
|
182
|
+
highNibble = nil
|
|
183
|
+
} else {
|
|
184
|
+
highNibble = nibble
|
|
126
185
|
}
|
|
127
|
-
index = nextIndex
|
|
128
186
|
}
|
|
129
187
|
AppEvents.shared.setPushNotificationsDeviceToken(data)
|
|
130
188
|
}
|