@amplytools/react-native-amply-sdk 0.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.
- package/LICENSE +178 -0
- package/README.md +714 -0
- package/android/build.gradle +90 -0
- package/android/consumer-rules.pro +1 -0
- package/android/gradle.properties +3 -0
- package/android/settings.gradle +9 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/AmplyModule.kt +384 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/AmplyPackage.kt +39 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/core/AmplyClient.kt +30 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/core/DefaultAmplyClient.kt +296 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/model/AmplyInitializationOptions.kt +10 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/model/DataSetType.kt +42 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/model/DataSetTypeMapper.kt +38 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/model/DeepLinkPayload.kt +8 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/model/EventEnvelope.kt +9 -0
- package/android/src/main/jni/AmplyTurboModule.cpp +29 -0
- package/android/src/main/jni/CMakeLists.txt +76 -0
- package/android/src/newarch/java/tools/amply/sdk/reactnative/NativeAmplyModuleSpec.java +75 -0
- package/android/src/newarch/jni/AmplyReactNative-generated.cpp +77 -0
- package/android/src/newarch/jni/AmplyReactNative.h +31 -0
- package/android/src/newarch/jni/CMakeLists.txt +40 -0
- package/app.plugin.js +1 -0
- package/dist/index.js +272 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +234 -0
- package/dist/index.mjs.map +1 -0
- package/dist/plugin/index.d.ts +6 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +186 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/index.mjs +169 -0
- package/dist/plugin/index.mjs.map +1 -0
- package/dist/plugin/src/index.d.ts +6 -0
- package/dist/plugin/src/index.d.ts.map +1 -0
- package/dist/plugin/src/index.js +3 -0
- package/dist/plugin/src/withAmply.d.ts +30 -0
- package/dist/plugin/src/withAmply.d.ts.map +1 -0
- package/dist/plugin/src/withAmply.js +51 -0
- package/dist/plugin/withAmply.d.ts +12 -0
- package/dist/plugin/withAmply.d.ts.map +1 -0
- package/dist/src/__tests__/index.test.d.ts +2 -0
- package/dist/src/__tests__/index.test.d.ts.map +1 -0
- package/dist/src/__tests__/index.test.js +70 -0
- package/dist/src/hooks/useAmplySystemEvents.d.ts +12 -0
- package/dist/src/hooks/useAmplySystemEvents.d.ts.map +1 -0
- package/dist/src/hooks/useAmplySystemEvents.js +56 -0
- package/dist/src/index.d.ts +32 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +80 -0
- package/dist/src/nativeModule.d.ts +5 -0
- package/dist/src/nativeModule.d.ts.map +1 -0
- package/dist/src/nativeModule.js +48 -0
- package/dist/src/nativeSpecs/NativeAmplyModule.d.ts +75 -0
- package/dist/src/nativeSpecs/NativeAmplyModule.d.ts.map +1 -0
- package/dist/src/nativeSpecs/NativeAmplyModule.js +2 -0
- package/dist/src/systemEventUtils.d.ts +3 -0
- package/dist/src/systemEventUtils.d.ts.map +1 -0
- package/dist/src/systemEventUtils.js +30 -0
- package/dist/src/systemEvents.d.ts +6 -0
- package/dist/src/systemEvents.d.ts.map +1 -0
- package/dist/src/systemEvents.js +8 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/ARCHITECTURE.md +1115 -0
- package/expo-module.config.json +11 -0
- package/ios/AmplyReactNative.podspec +32 -0
- package/ios/README.md +11 -0
- package/ios/Sources/AmplyReactNative/AmplyModule.mm +332 -0
- package/ios/Sources/AmplyReactNative/AmplyReactNative/AmplyReactNative-generated.mm +111 -0
- package/ios/Sources/AmplyReactNative/AmplyReactNative/AmplyReactNative.h +152 -0
- package/package.json +71 -0
- package/plugin/build/index.d.ts +5 -0
- package/plugin/build/index.js +8 -0
- package/plugin/build/withAmply.d.ts +29 -0
- package/plugin/build/withAmply.js +53 -0
- package/plugin/src/index.ts +7 -0
- package/plugin/src/withAmply.ts +68 -0
- package/plugin/tsconfig.json +8 -0
- package/plugin/tsconfig.tsbuildinfo +1 -0
- package/react-native.config.js +34 -0
- package/scripts/codegen.js +212 -0
- package/src/__tests__/index.test.ts +92 -0
- package/src/hooks/useAmplySystemEvents.ts +75 -0
- package/src/index.ts +115 -0
- package/src/nativeModule.ts +65 -0
- package/src/nativeSpecs/NativeAmplyModule.ts +80 -0
- package/src/systemEventUtils.ts +35 -0
- package/src/systemEvents.ts +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
# Amply React Native SDK
|
|
2
|
+
|
|
3
|
+
A React Native TurboModule bridge for the Amply Kotlin Multiplatform SDK with full New Architecture support. Enables event tracking, deeplink campaign handling, and real-time data collection in React Native apps.
|
|
4
|
+
|
|
5
|
+
## What is Amply?
|
|
6
|
+
|
|
7
|
+
Amply is a customer data collection and analytics platform. This SDK provides a React Native bridge to the Amply native SDKs, allowing you to:
|
|
8
|
+
|
|
9
|
+
- **Track events** from your React Native app to Amply
|
|
10
|
+
- **Handle deeplink campaigns** with automatic route resolution
|
|
11
|
+
- **Access system events** for monitoring and debugging
|
|
12
|
+
- **Manage user data** through native APIs
|
|
13
|
+
- **Inspect collected data** in real-time
|
|
14
|
+
|
|
15
|
+
## Current Status
|
|
16
|
+
|
|
17
|
+
| Feature | Status | Platform |
|
|
18
|
+
|---------|--------|----------|
|
|
19
|
+
| Event tracking | ✅ Complete | Android, iOS |
|
|
20
|
+
| Deeplink campaigns | ✅ Complete | Android, iOS |
|
|
21
|
+
| System events API | ✅ Complete | Android, iOS |
|
|
22
|
+
| Data inspection | ✅ Complete | Android, iOS |
|
|
23
|
+
| Advanced API (identify, setUserProperty, flush) | ⏳ Pending | Android, iOS |
|
|
24
|
+
|
|
25
|
+
**Requirements:**
|
|
26
|
+
- React Native >= 0.79 (New Architecture enabled)
|
|
27
|
+
- Expo SDK >= 53 (for Expo apps)
|
|
28
|
+
- Android API 24+
|
|
29
|
+
- iOS 13.0+
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Installation Guide
|
|
34
|
+
|
|
35
|
+
### Step 1: Install the Package
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
yarn add @amply/amply-react-native
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Step 2: Configure Your App
|
|
42
|
+
|
|
43
|
+
Choose one of the approaches below based on your app type.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Expo Integration Guide
|
|
48
|
+
|
|
49
|
+
### How It Works
|
|
50
|
+
|
|
51
|
+
The Amply SDK uses **React Native's standard autolinking** mechanism for both Bare RN and Expo:
|
|
52
|
+
|
|
53
|
+
1. **Native discovery**: `react-native.config.js` tells React Native where to find native code
|
|
54
|
+
2. **Gradle integration**: Expo's autolinking system includes the Amply module as a gradle subproject
|
|
55
|
+
3. **Package registration**: Expo config plugin registers `AmplyPackage` in the generated `MainApplication.kt` during prebuild
|
|
56
|
+
4. **Runtime loading**: React Native automatically loads the TurboModule
|
|
57
|
+
|
|
58
|
+
No manual configuration needed - it's fully automatic!
|
|
59
|
+
|
|
60
|
+
### Prerequisites
|
|
61
|
+
- Expo SDK 53+
|
|
62
|
+
- Node.js 18+
|
|
63
|
+
- Android SDK/emulator or physical device
|
|
64
|
+
- iOS 13.0+ / Xcode 14+ (for iOS development)
|
|
65
|
+
|
|
66
|
+
### Quick Setup (3 Steps)
|
|
67
|
+
|
|
68
|
+
**Step 1: Install the package**
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
yarn add @amply/amply-react-native
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Step 2: Add plugin to app.json**
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"expo": {
|
|
79
|
+
"plugins": [
|
|
80
|
+
"@amply/amply-react-native"
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The plugin declaration is required by Expo for security (prevents arbitrary code execution). Even though the plugin is lightweight, explicitly declaring it in your config is a best practice that prevents unexpected behavior during prebuild.
|
|
87
|
+
|
|
88
|
+
**Step 3: Prebuild and run**
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
expo prebuild --clean # (~2-3 minutes, one-time only)
|
|
92
|
+
expo start # Terminal 1: Start dev server
|
|
93
|
+
expo run:android # Terminal 2: Build and run (Android)
|
|
94
|
+
expo run:ios # Terminal 2: Build and run (iOS)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
That's it! The Amply SDK is automatically configured via React Native's autolinking mechanism. Setup is one-time only (~3 minutes total).
|
|
98
|
+
|
|
99
|
+
## Bare React Native Integration Guide
|
|
100
|
+
|
|
101
|
+
### Prerequisites
|
|
102
|
+
- React Native 0.79+ with **New Architecture enabled**
|
|
103
|
+
- Android API level 24+
|
|
104
|
+
- Android Gradle Plugin 7.0+
|
|
105
|
+
- Gradle 7.0+
|
|
106
|
+
- iOS 13.0+ / Xcode 14+
|
|
107
|
+
|
|
108
|
+
**Enable New Architecture:**
|
|
109
|
+
|
|
110
|
+
Set `newArchEnabled=true` in `android/gradle.properties`:
|
|
111
|
+
|
|
112
|
+
```properties
|
|
113
|
+
newArchEnabled=true
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Setup Steps
|
|
117
|
+
|
|
118
|
+
**1. Install the package:**
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
yarn add @amply/amply-react-native
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**2. Verify or create `react-native.config.js` at project root:**
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
module.exports = {
|
|
128
|
+
project: {
|
|
129
|
+
ios: {},
|
|
130
|
+
android: {},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
This enables React Native's autolinking mechanism to discover the Amply module.
|
|
136
|
+
|
|
137
|
+
**3. Rebuild:**
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
yarn react-native run-android # Android
|
|
141
|
+
yarn react-native run-ios # iOS
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**4. Verify successful integration:**
|
|
145
|
+
|
|
146
|
+
Check the build logs for:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
✅ Successfully compiled AmplyReactNative TurboModule
|
|
150
|
+
✅ Building APK
|
|
151
|
+
✅ Installing APK
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Or check logs after app starts:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
adb logcat | grep -i "amply\|turbomodule"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
You should see: `TurboModule 'Amply' loaded successfully`
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
## Sample Apps
|
|
164
|
+
|
|
165
|
+
The SDK includes two fully-functional example apps for reference and contribution.
|
|
166
|
+
|
|
167
|
+
### Bare React Native Sample (`example/bare`)
|
|
168
|
+
|
|
169
|
+
A traditional React Native CLI app demonstrating all SDK features.
|
|
170
|
+
|
|
171
|
+
**What it shows:**
|
|
172
|
+
- Event tracking with UI feedback
|
|
173
|
+
- Deeplink campaign handling
|
|
174
|
+
- System event logging
|
|
175
|
+
- Device dataset inspection
|
|
176
|
+
- Auto-initialization toggle
|
|
177
|
+
|
|
178
|
+
**How to run:**
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
cd example/bare
|
|
182
|
+
|
|
183
|
+
# Install dependencies
|
|
184
|
+
yarn install
|
|
185
|
+
|
|
186
|
+
# Build and run on device/emulator
|
|
187
|
+
yarn react-native run-android # Android
|
|
188
|
+
yarn react-native run-ios # iOS
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
**Key files:**
|
|
192
|
+
- `android/app/src/main/AndroidManifest.xml` - Intent filter for deeplinks
|
|
193
|
+
- `src/hooks/useAmplyDemo.ts` - Demo hook for tracking and deeplink testing
|
|
194
|
+
- `src/utils/amplyDeepLinkRouter.ts` - Deeplink routing logic
|
|
195
|
+
|
|
196
|
+
### Expo Sample (`example/expo`)
|
|
197
|
+
|
|
198
|
+
A complete Expo app with file-based routing (`expo-router`) demonstrating all SDK features with Expo's New Architecture support.
|
|
199
|
+
|
|
200
|
+
**What it shows:**
|
|
201
|
+
- Event tracking with real-time UI feedback
|
|
202
|
+
- Deeplink campaign handling with automatic routing
|
|
203
|
+
- System event monitoring
|
|
204
|
+
- Device dataset inspection
|
|
205
|
+
- AsyncStorage persistence for user preferences
|
|
206
|
+
- File-based routing with expo-router
|
|
207
|
+
- Hot reload for development
|
|
208
|
+
|
|
209
|
+
**Key features:**
|
|
210
|
+
- New Architecture enabled by default
|
|
211
|
+
- Automatic deeplink-to-route resolution
|
|
212
|
+
- AsyncStorage persistence for settings
|
|
213
|
+
- Real-time logs of all SDK events
|
|
214
|
+
|
|
215
|
+
**Key files:**
|
|
216
|
+
- `app/` - expo-router file-based routing
|
|
217
|
+
- `app/_layout.tsx` - Root layout with Stack navigation
|
|
218
|
+
- `app/promo/[id].tsx` - Dynamic promo screen route from deeplinks
|
|
219
|
+
- `src/hooks/useAmplyDemo.ts` - Main hook handling initialization, tracking, and listeners
|
|
220
|
+
- `src/utils/amplyDeepLinkRouter.ts` - Deeplink routing logic
|
|
221
|
+
|
|
222
|
+
**Running the Expo Sample:**
|
|
223
|
+
|
|
224
|
+
The example app already has the plugin configured in `expo.config.js`:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
cd example/expo
|
|
228
|
+
yarn install
|
|
229
|
+
expo prebuild --clean # Plugin runs automatically
|
|
230
|
+
expo start # Terminal 1
|
|
231
|
+
expo run:android # Terminal 2 (Android)
|
|
232
|
+
expo run:ios # Terminal 2 (iOS)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**Note for SDK Developers:**
|
|
236
|
+
|
|
237
|
+
When modifying the SDK and testing:
|
|
238
|
+
|
|
239
|
+
1. Build the SDK: `yarn build` (from root)
|
|
240
|
+
2. Test with example:
|
|
241
|
+
```bash
|
|
242
|
+
cd example/expo
|
|
243
|
+
rm -rf android ios # Clean native code
|
|
244
|
+
expo prebuild --clean # Plugin runs automatically via config
|
|
245
|
+
expo start # Terminal 1
|
|
246
|
+
expo run:android # Terminal 2 (Android)
|
|
247
|
+
expo run:ios # Terminal 2 (iOS)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The config plugin in `expo.config.js` automatically runs during `expo prebuild`.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## SDK API Reference
|
|
255
|
+
|
|
256
|
+
### Initialization
|
|
257
|
+
|
|
258
|
+
Initialize the SDK before using any other features.
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import Amply from '@amply/amply-react-native';
|
|
262
|
+
|
|
263
|
+
async function initAmply() {
|
|
264
|
+
try {
|
|
265
|
+
await Amply.initialize({
|
|
266
|
+
appId: 'YOUR_APP_ID',
|
|
267
|
+
apiKeyPublic: 'YOUR_PUBLIC_API_KEY',
|
|
268
|
+
apiKeySecret: 'YOUR_SECRET_API_KEY', // optional
|
|
269
|
+
});
|
|
270
|
+
console.log('Amply initialized');
|
|
271
|
+
} catch (error) {
|
|
272
|
+
console.error('Initialization failed:', error);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Call on app startup
|
|
277
|
+
initAmply();
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Event Tracking
|
|
281
|
+
|
|
282
|
+
Track user actions and custom events.
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
// Simple event
|
|
286
|
+
await Amply.track({
|
|
287
|
+
name: 'Button Tapped',
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Event with properties
|
|
291
|
+
await Amply.track({
|
|
292
|
+
name: 'Purchase Completed',
|
|
293
|
+
properties: {
|
|
294
|
+
amount: 99.99,
|
|
295
|
+
currency: 'USD',
|
|
296
|
+
itemCount: 3,
|
|
297
|
+
},
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// Common events
|
|
301
|
+
await Amply.track({
|
|
302
|
+
name: 'App Opened',
|
|
303
|
+
properties: {
|
|
304
|
+
version: '1.0.0',
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
await Amply.track({
|
|
309
|
+
name: 'User Signed In',
|
|
310
|
+
properties: {
|
|
311
|
+
method: 'email',
|
|
312
|
+
provider: 'google',
|
|
313
|
+
},
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Deeplink Campaigns
|
|
318
|
+
|
|
319
|
+
The Amply SDK automatically triggers deeplinks from marketing campaigns. Your app's router already handles navigation to the correct screen based on the deeplink URL.
|
|
320
|
+
|
|
321
|
+
You need a listener to implement **custom business logic** when a campaign deeplink is received:
|
|
322
|
+
|
|
323
|
+
**Valid use cases:**
|
|
324
|
+
|
|
325
|
+
- **Authentication check**: Redirect to login if the deeplink points to gated content
|
|
326
|
+
- **Analytics tracking**: Log which campaign brought the user in
|
|
327
|
+
- **Custom logic**: Apply discount codes, update user state, sync data, etc.
|
|
328
|
+
|
|
329
|
+
**Understanding `event.consumed`:**
|
|
330
|
+
|
|
331
|
+
The `consumed` flag indicates whether Amply SDK has already processed the deeplink internally. Currently, it's always `false`, meaning your listener will always receive and process the deeplink.
|
|
332
|
+
|
|
333
|
+
This flag is included for **future improvements** where Amply SDK could control whether the app listener should handle the deeplink:
|
|
334
|
+
- `consumed = true`: Amply handled this deeplink internally → skip your custom logic
|
|
335
|
+
- `consumed = false`: Deeplink available for your app to process
|
|
336
|
+
|
|
337
|
+
**Always check the flag** to future-proof your implementation:
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
if (!event.consumed) {
|
|
341
|
+
// Your custom logic: analytics, authentication, state updates, etc.
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
**Implementation:**
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
import Amply from '@amply/amply-react-native';
|
|
349
|
+
|
|
350
|
+
let unsubscribe: (() => void) | null = null;
|
|
351
|
+
|
|
352
|
+
async function setupDeeplinkListener() {
|
|
353
|
+
unsubscribe = await Amply.addDeepLinkListener((event) => {
|
|
354
|
+
console.log('Campaign deeplink received:', event.url);
|
|
355
|
+
// Example: amplybare://campaign/promo/black-friday
|
|
356
|
+
|
|
357
|
+
if (!event.consumed) {
|
|
358
|
+
// Handle custom business logic
|
|
359
|
+
handleCampaignDeeplink(event.url);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function handleCampaignDeeplink(deeplink: string) {
|
|
365
|
+
// Example 1: Check authentication for gated content
|
|
366
|
+
if (deeplink.includes('/premium/') && !user?.isLoggedIn) {
|
|
367
|
+
navigation.navigate('Login');
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Example 2: Track campaign analytics
|
|
372
|
+
const campaignId = deeplink.split('/').pop();
|
|
373
|
+
await Amply.track({
|
|
374
|
+
name: 'Campaign Deeplink Opened',
|
|
375
|
+
properties: {
|
|
376
|
+
campaignId,
|
|
377
|
+
deeplink,
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// Example 3: Custom logic - unlock achievement
|
|
382
|
+
if (deeplink.includes('/achievement/unlock/')) {
|
|
383
|
+
const achievementId = deeplink.split('/').pop();
|
|
384
|
+
store.achievements.unlock(achievementId);
|
|
385
|
+
showAchievementNotification(achievementId);
|
|
386
|
+
|
|
387
|
+
// Track the unlock event
|
|
388
|
+
await Amply.track({
|
|
389
|
+
name: 'Achievement Unlocked',
|
|
390
|
+
properties: {
|
|
391
|
+
achievementId,
|
|
392
|
+
source: 'campaign_deeplink',
|
|
393
|
+
},
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Call on app startup (after initialization)
|
|
399
|
+
setupDeeplinkListener();
|
|
400
|
+
|
|
401
|
+
// Clean up
|
|
402
|
+
function cleanup() {
|
|
403
|
+
if (unsubscribe) {
|
|
404
|
+
unsubscribe();
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**Testing deeplinks with ADB:**
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
# Test campaign promo
|
|
413
|
+
adb shell am start \
|
|
414
|
+
-a android.intent.action.VIEW \
|
|
415
|
+
-d "amplybare://campaign/promo/black-friday" \
|
|
416
|
+
com.yourapp
|
|
417
|
+
|
|
418
|
+
# Test achievement unlock
|
|
419
|
+
adb shell am start \
|
|
420
|
+
-a android.intent.action.VIEW \
|
|
421
|
+
-d "amplybare://campaign/achievement/unlock/first-login" \
|
|
422
|
+
com.yourapp
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### System Events
|
|
426
|
+
|
|
427
|
+
Monitor low-level events from the native SDK.
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
import Amply, { useAmplySystemEvents, formatSystemEventLabel } from '@amply/amply-react-native';
|
|
431
|
+
|
|
432
|
+
// Method 1: Direct listener
|
|
433
|
+
const unsubscribe = await Amply.systemEvents.addListener((event) => {
|
|
434
|
+
console.log('System event:', event.name, event.properties);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// Method 2: React hook (preferred for UI)
|
|
438
|
+
function EventLog() {
|
|
439
|
+
const { events, clear } = useAmplySystemEvents({
|
|
440
|
+
maxEntries: 200,
|
|
441
|
+
onEvent: (event) => {
|
|
442
|
+
console.log(formatSystemEventLabel(event));
|
|
443
|
+
},
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
return (
|
|
447
|
+
<View>
|
|
448
|
+
{events.map((event) => (
|
|
449
|
+
<Text key={event.id}>
|
|
450
|
+
{formatSystemEventLabel(event)}
|
|
451
|
+
</Text>
|
|
452
|
+
))}
|
|
453
|
+
<Button title="Clear" onPress={clear} />
|
|
454
|
+
</View>
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Data Inspection
|
|
460
|
+
|
|
461
|
+
Inspect collected data in real-time.
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
// Get recent events (last 100)
|
|
465
|
+
const events = await Amply.getRecentEvents();
|
|
466
|
+
console.log('Recent events:', events);
|
|
467
|
+
|
|
468
|
+
// Get data snapshot
|
|
469
|
+
const snapshot = await Amply.getDataSetSnapshot();
|
|
470
|
+
console.log('Dataset snapshot:', snapshot);
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### Check Initialization Status
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
const isInitialized = await Amply.isInitialized();
|
|
477
|
+
console.log('SDK initialized:', isInitialized);
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
## Development
|
|
483
|
+
|
|
484
|
+
### Project Structure
|
|
485
|
+
|
|
486
|
+
```
|
|
487
|
+
src/ # TypeScript source (JS side)
|
|
488
|
+
├── nativeSpecs/
|
|
489
|
+
│ └── NativeAmplyModule.ts # TurboModule spec (codegen source)
|
|
490
|
+
├── index.ts # Public API exports
|
|
491
|
+
├── nativeModule.ts # Native module loader with fallbacks
|
|
492
|
+
└── systemEvents.ts # Event emitter helpers
|
|
493
|
+
|
|
494
|
+
android/ # Android native code
|
|
495
|
+
├── src/main/
|
|
496
|
+
│ ├── java/com/amply/reactnative/
|
|
497
|
+
│ │ ├── AmplyModule.kt # TurboModule implementation
|
|
498
|
+
│ │ ├── AmplyPackage.kt # Package for React Native
|
|
499
|
+
│ │ └── core/ # Amply SDK wrapper
|
|
500
|
+
│ └── jni/
|
|
501
|
+
│ └── CMakeLists.txt # C++ build config
|
|
502
|
+
└── src/newarch/ # Auto-generated codegen artifacts
|
|
503
|
+
├── java/
|
|
504
|
+
│ └── NativeAmplyModuleSpec.java
|
|
505
|
+
└── jni/
|
|
506
|
+
├── CMakeLists.txt
|
|
507
|
+
├── AmplyReactNative.h
|
|
508
|
+
└── AmplyReactNative-generated.cpp
|
|
509
|
+
|
|
510
|
+
ios/ # iOS native code
|
|
511
|
+
├── AmplyReactNative.podspec # CocoaPods spec
|
|
512
|
+
└── Sources/AmplyReactNative/
|
|
513
|
+
├── AmplyModule.mm # TurboModule implementation
|
|
514
|
+
├── Amply/ # Codegen artifacts
|
|
515
|
+
│ ├── Amply.h
|
|
516
|
+
│ └── Amply-generated.mm
|
|
517
|
+
└── AmplyReactNative/ # Module header and codegen
|
|
518
|
+
├── AmplyReactNative.h
|
|
519
|
+
└── AmplyReactNative-generated.mm
|
|
520
|
+
|
|
521
|
+
example/bare/ # Bare RN example app
|
|
522
|
+
└── android/ # Native setup for bare RN
|
|
523
|
+
|
|
524
|
+
example/expo/ # Expo example app
|
|
525
|
+
├── scripts/
|
|
526
|
+
│ └── setup-amply.js # Post-prebuild setup script
|
|
527
|
+
├── babel.config.js # Babel configuration
|
|
528
|
+
├── metro.config.js # Metro bundler config
|
|
529
|
+
└── expo.config.js # Expo configuration with plugin
|
|
530
|
+
|
|
531
|
+
plugin/ # Expo config plugin source
|
|
532
|
+
├── src/
|
|
533
|
+
│ ├── withAmply.ts # Main plugin logic (registers AmplyPackage via withMainApplication hook)
|
|
534
|
+
│ └── index.ts # Plugin export
|
|
535
|
+
├── build/ # Compiled plugin (generated)
|
|
536
|
+
├── tsconfig.json # TypeScript config for plugin
|
|
537
|
+
└── tsconfig.tsbuildinfo # Build metadata
|
|
538
|
+
|
|
539
|
+
scripts/
|
|
540
|
+
├── codegen.js # Code generation wrapper
|
|
541
|
+
└── setup-expo.js # CLI command: npx amply-setup-expo
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
### Build Commands
|
|
545
|
+
|
|
546
|
+
```bash
|
|
547
|
+
# Generate TypeScript → Java/C++ bindings
|
|
548
|
+
yarn codegen
|
|
549
|
+
|
|
550
|
+
# Build TypeScript distribution
|
|
551
|
+
yarn build
|
|
552
|
+
|
|
553
|
+
# Run tests
|
|
554
|
+
yarn test
|
|
555
|
+
|
|
556
|
+
# Lint and type check
|
|
557
|
+
yarn lint && yarn typecheck
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### Using Sample Apps for SDK Development
|
|
561
|
+
|
|
562
|
+
The sample apps (`example/bare` and `example/expo`) are the primary testing environments for SDK development. They use the `link:` protocol in `package.json` to reference the local SDK source for rapid iteration:
|
|
563
|
+
|
|
564
|
+
```json
|
|
565
|
+
{
|
|
566
|
+
"dependencies": {
|
|
567
|
+
"@amply/amply-react-native": "link:../.."
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**This allows SDK developers to:**
|
|
573
|
+
- Make changes to SDK source and see them immediately in sample apps
|
|
574
|
+
- Test spec changes with `yarn codegen`
|
|
575
|
+
- Test native code changes without rebuilding the library
|
|
576
|
+
- Verify both Expo and bare RN integrations work correctly
|
|
577
|
+
|
|
578
|
+
**When to use each sample:**
|
|
579
|
+
- **Expo:** Fast iteration, hot reload, local SDK development
|
|
580
|
+
- **Bare:** Production-like testing, intent filter testing, real-world scenario
|
|
581
|
+
|
|
582
|
+
> **Important:** Do not use `link:` protocol in regular apps. Regular developers should install from npm: `yarn add @amply/amply-react-native`
|
|
583
|
+
|
|
584
|
+
### Contributing Workflow
|
|
585
|
+
|
|
586
|
+
**1. Setup workspace:**
|
|
587
|
+
|
|
588
|
+
```bash
|
|
589
|
+
yarn install
|
|
590
|
+
yarn codegen
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
**2. Make changes to SDK:**
|
|
594
|
+
|
|
595
|
+
```bash
|
|
596
|
+
# For native interface changes
|
|
597
|
+
nano src/nativeSpecs/NativeAmplyModule.ts
|
|
598
|
+
yarn codegen
|
|
599
|
+
|
|
600
|
+
# For implementation changes
|
|
601
|
+
nano android/src/main/java/com/amply/reactnative/AmplyModule.kt
|
|
602
|
+
|
|
603
|
+
# For JS changes
|
|
604
|
+
nano src/index.ts
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
**3. Test with sample apps:**
|
|
608
|
+
|
|
609
|
+
The sample apps are pre-configured with `link:` protocol for local SDK development.
|
|
610
|
+
|
|
611
|
+
```bash
|
|
612
|
+
# Expo app (recommended for iteration)
|
|
613
|
+
cd example/expo
|
|
614
|
+
yarn install
|
|
615
|
+
expo prebuild --clean # Plugin runs via expo.config.js
|
|
616
|
+
expo start # Terminal 1
|
|
617
|
+
expo run:android # Terminal 2 (Android)
|
|
618
|
+
expo run:ios # Terminal 2 (iOS)
|
|
619
|
+
|
|
620
|
+
# Bare RN app (for production validation)
|
|
621
|
+
cd example/bare
|
|
622
|
+
yarn install
|
|
623
|
+
yarn react-native run-android # Android
|
|
624
|
+
yarn react-native run-ios # iOS
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
**Recommended development workflow:**
|
|
628
|
+
|
|
629
|
+
```bash
|
|
630
|
+
# 1. Make changes to SDK
|
|
631
|
+
nano src/nativeSpecs/NativeAmplyModule.ts
|
|
632
|
+
|
|
633
|
+
# 2. If spec changed, regenerate artifacts
|
|
634
|
+
yarn codegen
|
|
635
|
+
|
|
636
|
+
# 3. Test with Expo (faster feedback)
|
|
637
|
+
cd example/expo
|
|
638
|
+
rm -rf android ios # Clean native code
|
|
639
|
+
expo prebuild --clean # Plugin runs automatically via config
|
|
640
|
+
expo start # Terminal 1
|
|
641
|
+
expo run:android # Terminal 2 (Android)
|
|
642
|
+
expo run:ios # Terminal 2 (iOS)
|
|
643
|
+
|
|
644
|
+
# 4. Once working, test with bare RN
|
|
645
|
+
cd ../bare
|
|
646
|
+
yarn install
|
|
647
|
+
yarn react-native run-android # Android
|
|
648
|
+
yarn react-native run-ios # iOS
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
**4. PR checklist:**
|
|
652
|
+
|
|
653
|
+
- [ ] Changes tested in both example apps
|
|
654
|
+
- [ ] `yarn lint && yarn typecheck && yarn test` passes
|
|
655
|
+
- [ ] Codegen artifacts committed (if spec changed)
|
|
656
|
+
- [ ] Commit messages are clear
|
|
657
|
+
- [ ] No breaking changes (or documented)
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
## Deeplink Configuration (Bare RN Only)
|
|
662
|
+
|
|
663
|
+
For bare React Native apps, add intent filters to handle deeplinks.
|
|
664
|
+
|
|
665
|
+
**Update `android/app/src/main/AndroidManifest.xml`:**
|
|
666
|
+
|
|
667
|
+
```xml
|
|
668
|
+
<activity
|
|
669
|
+
android:name=".MainActivity"
|
|
670
|
+
android:exported="true"
|
|
671
|
+
android:launchMode="singleTask">
|
|
672
|
+
|
|
673
|
+
<intent-filter android:autoVerify="true">
|
|
674
|
+
<action android:name="android.intent.action.VIEW" />
|
|
675
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
676
|
+
<category android:name="android.intent.category.BROWSABLE" />
|
|
677
|
+
<!-- Define your schemas below -->
|
|
678
|
+
<data
|
|
679
|
+
android:scheme="amply"
|
|
680
|
+
android:host="campaign"
|
|
681
|
+
android:pathPrefix="/" />
|
|
682
|
+
</intent-filter>
|
|
683
|
+
</activity>
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
**For Expo apps:** Deeplinks are handled automatically via `app.json` configuration.
|
|
687
|
+
|
|
688
|
+
---
|
|
689
|
+
|
|
690
|
+
## Contributing
|
|
691
|
+
|
|
692
|
+
Contributions are welcome! Please follow the development workflow above.
|
|
693
|
+
|
|
694
|
+
**Setup:**
|
|
695
|
+
```bash
|
|
696
|
+
yarn install
|
|
697
|
+
yarn codegen
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
**Before submitting a PR:**
|
|
701
|
+
- Test with both example apps
|
|
702
|
+
- Run `yarn lint && yarn typecheck`
|
|
703
|
+
- Verify no breaking changes
|
|
704
|
+
- Update README if API changes
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
## License
|
|
709
|
+
This SDK is licensed under the Apache License 2.0.
|
|
710
|
+
|
|
711
|
+
You may use, modify, and distribute this software in compliance with the terms of the license.
|
|
712
|
+
See the [LICENSE](LICENSE) file for full details.
|
|
713
|
+
|
|
714
|
+
© Amply. 2025
|