expo-facebook-analytics 1.0.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.
- package/README.md +242 -0
- package/android/build.gradle +60 -0
- package/android/src/main/java/com/nitrofbanalytics/HybridFacebookAnalytics.kt +139 -0
- package/app.plugin.js +1 -0
- package/expo-facebook-analytics.podspec +31 -0
- package/ios/HybridFacebookAnalytics.swift +135 -0
- package/lib/index.d.ts +58 -0
- package/lib/index.js +138 -0
- package/lib/specs/FacebookAnalytics.nitro.d.ts +20 -0
- package/lib/specs/FacebookAnalytics.nitro.js +2 -0
- package/lib/types.d.ts +65 -0
- package/lib/types.js +52 -0
- package/nitro.json +19 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/NitroFBAnalytics+autolinking.cmake +81 -0
- package/nitrogen/generated/android/NitroFBAnalytics+autolinking.gradle +27 -0
- package/nitrogen/generated/android/NitroFBAnalyticsOnLoad.cpp +44 -0
- package/nitrogen/generated/android/NitroFBAnalyticsOnLoad.hpp +25 -0
- package/nitrogen/generated/android/c++/JHybridFacebookAnalyticsSpec.cpp +157 -0
- package/nitrogen/generated/android/c++/JHybridFacebookAnalyticsSpec.hpp +79 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/com/nitrofbanalytics/HybridFacebookAnalyticsSpec.kt +110 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/com/nitrofbanalytics/NitroFBAnalyticsOnLoad.kt +35 -0
- package/nitrogen/generated/ios/NitroFBAnalytics+autolinking.rb +60 -0
- package/nitrogen/generated/ios/NitroFBAnalytics-Swift-Cxx-Bridge.cpp +49 -0
- package/nitrogen/generated/ios/NitroFBAnalytics-Swift-Cxx-Bridge.hpp +171 -0
- package/nitrogen/generated/ios/NitroFBAnalytics-Swift-Cxx-Umbrella.hpp +47 -0
- package/nitrogen/generated/ios/NitroFBAnalyticsAutolinking.mm +33 -0
- package/nitrogen/generated/ios/NitroFBAnalyticsAutolinking.swift +26 -0
- package/nitrogen/generated/ios/c++/HybridFacebookAnalyticsSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridFacebookAnalyticsSpecSwift.hpp +167 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +47 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +54 -0
- package/nitrogen/generated/ios/swift/HybridFacebookAnalyticsSpec.swift +69 -0
- package/nitrogen/generated/ios/swift/HybridFacebookAnalyticsSpec_cxx.swift +410 -0
- package/nitrogen/generated/shared/c++/HybridFacebookAnalyticsSpec.cpp +34 -0
- package/nitrogen/generated/shared/c++/HybridFacebookAnalyticsSpec.hpp +78 -0
- package/package.json +66 -0
- package/plugin/build/index.d.ts +13 -0
- package/plugin/build/index.js +42 -0
- package/plugin/build/withFacebookAnalyticsAndroid.d.ts +14 -0
- package/plugin/build/withFacebookAnalyticsAndroid.js +67 -0
- package/plugin/build/withFacebookAnalyticsIOS.d.ts +16 -0
- package/plugin/build/withFacebookAnalyticsIOS.js +96 -0
- package/src/index.ts +161 -0
- package/src/specs/FacebookAnalytics.nitro.ts +47 -0
- package/src/types.ts +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# expo-facebook-analytics
|
|
2
|
+
|
|
3
|
+
High-performance Facebook Analytics for React Native using [Nitro Modules](https://github.com/mrousavy/nitro).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
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+
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
bun add expo-facebook-analytics react-native-nitro-modules
|
|
17
|
+
```
|
|
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.33.2
|
|
29
|
+
- `expo` >= 55.0.4 _(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`:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"expo": {
|
|
48
|
+
"plugins": [
|
|
49
|
+
[
|
|
50
|
+
"expo-facebook-analytics",
|
|
51
|
+
{
|
|
52
|
+
"appID": "YOUR_FACEBOOK_APP_ID",
|
|
53
|
+
"clientToken": "YOUR_FACEBOOK_CLIENT_TOKEN",
|
|
54
|
+
"displayName": "Your App Name"
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Plugin Options
|
|
63
|
+
|
|
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
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { logEvent, logPurchase, AppEvents, AppEventParams } from 'expo-facebook-analytics';
|
|
85
|
+
|
|
86
|
+
// Simple event
|
|
87
|
+
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
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Device Identifiers
|
|
141
|
+
|
|
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
|
+
```
|
|
148
|
+
|
|
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`
|
|
205
|
+
|
|
206
|
+
### AppEventParams
|
|
207
|
+
|
|
208
|
+
`AddType`, `Content`, `ContentID`, `ContentType`, `Currency`, `Description`, `Level`, `MaxRatingValue`, `NumItems`, `OrderId`, `PaymentInfoAvailable`, `RegistrationMethod`, `SearchString`, `Success`, `ValueNo`, `ValueYes`
|
|
209
|
+
|
|
210
|
+
## Types
|
|
211
|
+
|
|
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';
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Requirements
|
|
232
|
+
|
|
233
|
+
| Platform | Minimum Version |
|
|
234
|
+
| -------- | --------------- |
|
|
235
|
+
| iOS | 13.0 |
|
|
236
|
+
| Android | SDK 21 |
|
|
237
|
+
|
|
238
|
+
Native SDKs: Facebook SDK ~17.0
|
|
239
|
+
|
|
240
|
+
## License
|
|
241
|
+
|
|
242
|
+
MIT
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.safeExtGet = {prop, fallback ->
|
|
3
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
4
|
+
}
|
|
5
|
+
repositories {
|
|
6
|
+
google()
|
|
7
|
+
mavenCentral()
|
|
8
|
+
}
|
|
9
|
+
dependencies {
|
|
10
|
+
classpath("com.android.tools.build:gradle:8.2.0")
|
|
11
|
+
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22")
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
apply plugin: 'com.android.library'
|
|
16
|
+
apply plugin: 'kotlin-android'
|
|
17
|
+
|
|
18
|
+
def nitrogenAutolinking = file("nitrogen/generated/android/NitroFBAnalytics-autolinking.gradle")
|
|
19
|
+
if (nitrogenAutolinking.exists()) {
|
|
20
|
+
apply from: nitrogenAutolinking
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
android {
|
|
24
|
+
namespace 'com.nitrofbanalytics'
|
|
25
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 34)
|
|
26
|
+
|
|
27
|
+
defaultConfig {
|
|
28
|
+
minSdkVersion safeExtGet('minSdkVersion', 21)
|
|
29
|
+
targetSdkVersion safeExtGet('targetSdkVersion', 34)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
sourceSets {
|
|
33
|
+
main {
|
|
34
|
+
java.srcDirs += [
|
|
35
|
+
'src/main/java',
|
|
36
|
+
'nitrogen/generated/android/kotlin'
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
compileOptions {
|
|
42
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
43
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
kotlinOptions {
|
|
47
|
+
jvmTarget = '1.8'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
repositories {
|
|
52
|
+
google()
|
|
53
|
+
mavenCentral()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
dependencies {
|
|
57
|
+
implementation 'com.facebook.react:react-native:+'
|
|
58
|
+
implementation 'com.margelo.nitro:nitro-modules:+'
|
|
59
|
+
implementation 'com.facebook.android:facebook-android-sdk:17.+'
|
|
60
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
package com.nitrofbanalytics
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import com.facebook.FacebookSdk
|
|
5
|
+
import com.facebook.appevents.AppEventsConstants
|
|
6
|
+
import com.facebook.appevents.AppEventsLogger
|
|
7
|
+
import com.facebook.internal.AttributionIdentifiers
|
|
8
|
+
import com.margelo.nitro.core.Promise
|
|
9
|
+
import java.math.BigDecimal
|
|
10
|
+
import java.util.Currency
|
|
11
|
+
|
|
12
|
+
class HybridFacebookAnalytics : HybridFacebookAnalyticsSpec() {
|
|
13
|
+
|
|
14
|
+
private val logger: AppEventsLogger by lazy {
|
|
15
|
+
AppEventsLogger.newLogger(FacebookSdk.getApplicationContext())
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// region Event Logging
|
|
19
|
+
|
|
20
|
+
override fun logEvent(eventName: String, valueToSum: Double, params: Map<String, String>) {
|
|
21
|
+
val bundle = mapToBundle(params)
|
|
22
|
+
logger.logEvent(eventName, valueToSum, bundle)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
override fun logEventWithoutParams(eventName: String, valueToSum: Double) {
|
|
26
|
+
if (valueToSum != 0.0) {
|
|
27
|
+
logger.logEvent(eventName, valueToSum)
|
|
28
|
+
} else {
|
|
29
|
+
logger.logEvent(eventName)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override fun logPurchase(amount: Double, currency: String, params: Map<String, String>) {
|
|
34
|
+
val bundle = mapToBundle(params)
|
|
35
|
+
logger.logPurchase(
|
|
36
|
+
BigDecimal.valueOf(amount),
|
|
37
|
+
Currency.getInstance(currency),
|
|
38
|
+
bundle
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override fun logPushNotificationOpen(payload: Map<String, String>) {
|
|
43
|
+
val bundle = mapToBundle(payload)
|
|
44
|
+
logger.logPushNotificationOpen(bundle)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// endregion
|
|
48
|
+
|
|
49
|
+
// region User Identity
|
|
50
|
+
|
|
51
|
+
override fun setUserID(userID: String) {
|
|
52
|
+
AppEventsLogger.setUserID(userID)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
override fun clearUserID() {
|
|
56
|
+
AppEventsLogger.clearUserID()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
override fun getUserID(): String? {
|
|
60
|
+
return AppEventsLogger.getUserID()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
override fun setUserData(
|
|
64
|
+
email: String?,
|
|
65
|
+
firstName: String?,
|
|
66
|
+
lastName: String?,
|
|
67
|
+
phone: String?,
|
|
68
|
+
dateOfBirth: String?,
|
|
69
|
+
gender: String?,
|
|
70
|
+
city: String?,
|
|
71
|
+
state: String?,
|
|
72
|
+
zip: String?,
|
|
73
|
+
country: String?
|
|
74
|
+
) {
|
|
75
|
+
AppEventsLogger.setUserData(
|
|
76
|
+
email, firstName, lastName, phone,
|
|
77
|
+
dateOfBirth, gender, city, state, zip, country
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// endregion
|
|
82
|
+
|
|
83
|
+
// region Device Identifiers
|
|
84
|
+
|
|
85
|
+
override fun getAnonymousID(): Promise<String?> {
|
|
86
|
+
return Promise.resolved(logger.anonymousAppDeviceGUID)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
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)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// endregion
|
|
100
|
+
|
|
101
|
+
// region Configuration
|
|
102
|
+
|
|
103
|
+
override fun setFlushBehavior(flushBehavior: String) {
|
|
104
|
+
when (flushBehavior) {
|
|
105
|
+
"explicit_only" -> AppEventsLogger.setFlushBehavior(AppEventsLogger.FlushBehavior.EXPLICIT_ONLY)
|
|
106
|
+
else -> AppEventsLogger.setFlushBehavior(AppEventsLogger.FlushBehavior.AUTO)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
override fun flush() {
|
|
111
|
+
logger.flush()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// endregion
|
|
115
|
+
|
|
116
|
+
// region Push Notifications
|
|
117
|
+
|
|
118
|
+
override fun setPushNotificationsDeviceToken(token: String) {
|
|
119
|
+
// No-op on Android — use setPushNotificationsRegistrationId instead
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
override fun setPushNotificationsRegistrationId(registrationId: String) {
|
|
123
|
+
AppEventsLogger.setPushNotificationsRegistrationId(registrationId)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// endregion
|
|
127
|
+
|
|
128
|
+
// region Helpers
|
|
129
|
+
|
|
130
|
+
private fun mapToBundle(map: Map<String, String>): Bundle {
|
|
131
|
+
val bundle = Bundle()
|
|
132
|
+
for ((key, value) in map) {
|
|
133
|
+
bundle.putString(key, value)
|
|
134
|
+
}
|
|
135
|
+
return bundle
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// endregion
|
|
139
|
+
}
|
package/app.plugin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("./plugin/build").default;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
nitrogen_autolinking = File.join(__dir__, 'nitrogen', 'generated', 'ios', 'NitroFBAnalytics+autolinking.rb')
|
|
6
|
+
|
|
7
|
+
Pod::Spec.new do |s|
|
|
8
|
+
s.name = 'expo-facebook-analytics'
|
|
9
|
+
s.version = package['version']
|
|
10
|
+
s.summary = package['description']
|
|
11
|
+
s.homepage = 'https://github.com/user/expo-facebook-analytics'
|
|
12
|
+
s.license = package['license']
|
|
13
|
+
s.author = 'expo-facebook-analytics contributors'
|
|
14
|
+
s.source = { :git => '.', :tag => s.version.to_s }
|
|
15
|
+
s.platforms = { :ios => '13.0' }
|
|
16
|
+
s.module_name = 'NitroFBAnalytics'
|
|
17
|
+
|
|
18
|
+
s.source_files = [
|
|
19
|
+
'ios/**/*.{swift,h,hpp,m,mm,cpp}',
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
s.dependency 'React-Core'
|
|
23
|
+
s.dependency 'FBSDKCoreKit', '~> 17.0'
|
|
24
|
+
|
|
25
|
+
s.frameworks = ['AdSupport']
|
|
26
|
+
|
|
27
|
+
if File.exist?(nitrogen_autolinking)
|
|
28
|
+
load nitrogen_autolinking
|
|
29
|
+
add_nitrogen_files(s)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import NitroModules
|
|
3
|
+
import FBSDKCoreKit
|
|
4
|
+
import AdSupport
|
|
5
|
+
|
|
6
|
+
class HybridFacebookAnalytics: HybridFacebookAnalyticsSpec {
|
|
7
|
+
|
|
8
|
+
// MARK: - Event Logging
|
|
9
|
+
|
|
10
|
+
func logEvent(eventName: String, valueToSum: Double, params: [String: String]) throws {
|
|
11
|
+
let fbParams: [AppEvents.ParameterName: Any] = params.reduce(into: [:]) { result, pair in
|
|
12
|
+
result[AppEvents.ParameterName(pair.key)] = pair.value
|
|
13
|
+
}
|
|
14
|
+
AppEvents.shared.logEvent(
|
|
15
|
+
AppEvents.Name(eventName),
|
|
16
|
+
valueToSum: valueToSum,
|
|
17
|
+
parameters: fbParams
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
func logEventWithoutParams(eventName: String, valueToSum: Double) throws {
|
|
22
|
+
if valueToSum != 0 {
|
|
23
|
+
AppEvents.shared.logEvent(
|
|
24
|
+
AppEvents.Name(eventName),
|
|
25
|
+
valueToSum: valueToSum
|
|
26
|
+
)
|
|
27
|
+
} else {
|
|
28
|
+
AppEvents.shared.logEvent(AppEvents.Name(eventName))
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
func logPurchase(amount: Double, currency: String, params: [String: String]) throws {
|
|
33
|
+
let fbParams: [AppEvents.ParameterName: Any] = params.reduce(into: [:]) { result, pair in
|
|
34
|
+
result[AppEvents.ParameterName(pair.key)] = pair.value
|
|
35
|
+
}
|
|
36
|
+
AppEvents.shared.logPurchase(amount: amount, currency: currency, parameters: fbParams)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func logPushNotificationOpen(payload: [String: String]) throws {
|
|
40
|
+
let nsPayload: [String: Any] = payload.reduce(into: [:]) { result, pair in
|
|
41
|
+
result[pair.key] = pair.value
|
|
42
|
+
}
|
|
43
|
+
AppEvents.shared.logPushNotificationOpen(payload: nsPayload)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// MARK: - User Identity
|
|
47
|
+
|
|
48
|
+
func setUserID(userID: String) throws {
|
|
49
|
+
AppEvents.shared.userID = userID
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func clearUserID() throws {
|
|
53
|
+
AppEvents.shared.userID = nil
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
func getUserID() throws -> String? {
|
|
57
|
+
return AppEvents.shared.userID
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func setUserData(
|
|
61
|
+
email: String?,
|
|
62
|
+
firstName: String?,
|
|
63
|
+
lastName: String?,
|
|
64
|
+
phone: String?,
|
|
65
|
+
dateOfBirth: String?,
|
|
66
|
+
gender: String?,
|
|
67
|
+
city: String?,
|
|
68
|
+
state: String?,
|
|
69
|
+
zip: String?,
|
|
70
|
+
country: String?
|
|
71
|
+
) throws {
|
|
72
|
+
AppEvents.shared.setUser(
|
|
73
|
+
email: email,
|
|
74
|
+
firstName: firstName,
|
|
75
|
+
lastName: lastName,
|
|
76
|
+
phone: phone,
|
|
77
|
+
dateOfBirth: dateOfBirth,
|
|
78
|
+
gender: gender,
|
|
79
|
+
city: city,
|
|
80
|
+
state: state,
|
|
81
|
+
zip: zip,
|
|
82
|
+
country: country
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// MARK: - Device Identifiers
|
|
87
|
+
|
|
88
|
+
func getAnonymousID() throws -> Promise<String?> {
|
|
89
|
+
return Promise.resolved(withResult: AppEvents.shared.anonymousID)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
func getAdvertiserID() throws -> Promise<String?> {
|
|
93
|
+
let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
|
|
94
|
+
if idfa == "00000000-0000-0000-0000-000000000000" {
|
|
95
|
+
return Promise.resolved(withResult: nil)
|
|
96
|
+
}
|
|
97
|
+
return Promise.resolved(withResult: idfa)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// MARK: - Configuration
|
|
101
|
+
|
|
102
|
+
func setFlushBehavior(flushBehavior: String) throws {
|
|
103
|
+
switch flushBehavior {
|
|
104
|
+
case "explicit_only":
|
|
105
|
+
AppEvents.shared.flushBehavior = .explicitOnly
|
|
106
|
+
default:
|
|
107
|
+
AppEvents.shared.flushBehavior = .auto
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
func flush() throws {
|
|
112
|
+
AppEvents.shared.flush()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// MARK: - Push Notifications
|
|
116
|
+
|
|
117
|
+
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)
|
|
126
|
+
}
|
|
127
|
+
index = nextIndex
|
|
128
|
+
}
|
|
129
|
+
AppEvents.shared.setPushNotificationsDeviceToken(data)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
func setPushNotificationsRegistrationId(registrationId: String) throws {
|
|
133
|
+
// No-op on iOS — this is an Android-only method
|
|
134
|
+
}
|
|
135
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { AppEventsFlushBehavior, Params, UserData } from "./types";
|
|
2
|
+
export type { AppEventsFlushBehavior, Params, UserData } from "./types";
|
|
3
|
+
export { AppEventParams, AppEvents } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* Log a custom or predefined app event.
|
|
6
|
+
* @param eventName - Event name (use AppEvents constants for predefined events)
|
|
7
|
+
* @param args - Optional valueToSum (number) and/or params object
|
|
8
|
+
*/
|
|
9
|
+
export declare function logEvent(eventName: string, ...args: Array<number | Params>): void;
|
|
10
|
+
/**
|
|
11
|
+
* Log a purchase event.
|
|
12
|
+
*/
|
|
13
|
+
export declare function logPurchase(purchaseAmount: number, currencyCode: string, parameters?: Params): void;
|
|
14
|
+
/**
|
|
15
|
+
* Log a push notification open event.
|
|
16
|
+
*/
|
|
17
|
+
export declare function logPushNotificationOpen(payload?: Record<string, string | number>): void;
|
|
18
|
+
/**
|
|
19
|
+
* Set the user ID for analytics association.
|
|
20
|
+
*/
|
|
21
|
+
export declare function setUserID(userID: string | null): void;
|
|
22
|
+
/**
|
|
23
|
+
* Clear the current user ID.
|
|
24
|
+
*/
|
|
25
|
+
export declare function clearUserID(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Get the current user ID.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getUserID(): string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Set user data for advanced matching.
|
|
32
|
+
*/
|
|
33
|
+
export declare function setUserData(userData: UserData): void;
|
|
34
|
+
/**
|
|
35
|
+
* Get the anonymous device ID.
|
|
36
|
+
*/
|
|
37
|
+
export declare function getAnonymousID(): Promise<string | undefined>;
|
|
38
|
+
/**
|
|
39
|
+
* Get the advertiser ID (IDFA on iOS, AAID on Android).
|
|
40
|
+
*/
|
|
41
|
+
export declare function getAdvertiserID(): Promise<string | undefined>;
|
|
42
|
+
/**
|
|
43
|
+
* Set the flush behavior for event batching.
|
|
44
|
+
* @param flushBehavior - 'auto' or 'explicit_only'
|
|
45
|
+
*/
|
|
46
|
+
export declare function setFlushBehavior(flushBehavior: AppEventsFlushBehavior): void;
|
|
47
|
+
/**
|
|
48
|
+
* Flush all queued events to Facebook immediately.
|
|
49
|
+
*/
|
|
50
|
+
export declare function flush(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Set the push notification device token (iOS).
|
|
53
|
+
*/
|
|
54
|
+
export declare function setPushNotificationsDeviceToken(deviceToken: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* Set the push notification registration ID (Android/FCM).
|
|
57
|
+
*/
|
|
58
|
+
export declare function setPushNotificationsRegistrationId(registrationId: string): void;
|