Skip to content

Commit 5adc200

Browse files
committed
Initial commit: Flutter attribution SDK
0 parents  commit 5adc200

79 files changed

Lines changed: 26630 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
verify:
11+
runs-on: ubuntu-latest
12+
env:
13+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Set up Node.js
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: 20
22+
cache: npm
23+
24+
- name: Install dependencies
25+
run: npm ci
26+
27+
- name: Typecheck
28+
run: npm run typecheck
29+
30+
- name: Run tests
31+
run: npm test
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: Discord Notification
2+
on: [push]
3+
4+
jobs:
5+
notify:
6+
runs-on: ubuntu-latest
7+
steps:
8+
- name: Notify Discord
9+
env:
10+
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_URL }}
11+
COMMIT_MSG_RAW: ${{ github.event.head_commit.message }}
12+
run: |
13+
COMMIT_MSG=$(printf '%s' "$COMMIT_MSG_RAW" | head -1 | sed 's/"/\\"/g')
14+
curl -s -H "Content-Type: application/json" \
15+
-d "{\"embeds\":[{\"title\":\"⚛️ Push to React Native SDK\",\"color\":16043919,\"fields\":[{\"name\":\"Branch\",\"value\":\"${{ github.ref_name }}\",\"inline\":true},{\"name\":\"Author\",\"value\":\"${{ github.actor }}\",\"inline\":true},{\"name\":\"Commit\",\"value\":\"${COMMIT_MSG}\",\"inline\":false}],\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}]}" \
16+
"$DISCORD_WEBHOOK"

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules/
2+
npm-debug.log*
3+
android/build/
4+
android/.gradle/

README.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# appsprint-react-native
2+
3+
AppSprint mobile attribution SDK for React Native. It tracks installs, attribution, lifecycle events, custom events, and revenue events, with local event queueing for transient failures.
4+
5+
## Installation
6+
7+
```bash
8+
npm install appsprint-react-native
9+
```
10+
11+
### iOS
12+
13+
```bash
14+
cd ios && pod install
15+
```
16+
17+
## Expo config plugin
18+
19+
If you use Expo prebuild, add the plugin to your app config:
20+
21+
```json
22+
{
23+
"plugins": [
24+
[
25+
"appsprint-react-native",
26+
{
27+
"trackingDescription": "This identifier will be used to deliver personalized ads to you."
28+
}
29+
]
30+
]
31+
}
32+
```
33+
34+
Plugin options:
35+
36+
| Option | Type | Description | Default |
37+
|---|---|---|---|
38+
| `trackingDescription` | `string` | ATT permission dialog text for `NSUserTrackingUsageDescription` | `"This identifier will be used to deliver personalized ads to you."` |
39+
| `advertisingAttributionEndpoint` | `string` | Sets `NSAdvertisingAttributionReportEndpoint` ||
40+
41+
## Quick start
42+
43+
Initialize the SDK as early as possible in app startup:
44+
45+
```tsx
46+
import { AppSprint } from "appsprint-react-native";
47+
48+
await AppSprint.configure({
49+
apiKey: "YOUR_API_KEY",
50+
});
51+
```
52+
53+
### Configuration
54+
55+
| Option | Type | Required | Default |
56+
|---|---|---|---|
57+
| `apiKey` | `string` | Yes ||
58+
| `apiUrl` | `string` | No | `https://api.appsprint.app` |
59+
| `enableAppleAdsAttribution` | `boolean` | No | `true` |
60+
| `isDebug` | `boolean` | No | `false` |
61+
| `logLevel` | `0 \| 1 \| 2 \| 3` | No | `2` |
62+
| `customerUserId` | `string \| null` | No | `null` |
63+
64+
Log levels:
65+
66+
`0 = debug`, `1 = info`, `2 = warn`, `3 = error`
67+
68+
## Sending events
69+
70+
```tsx
71+
import { AppSprint } from "appsprint-react-native";
72+
73+
await AppSprint.sendEvent("login");
74+
await AppSprint.sendEvent("sign_up");
75+
await AppSprint.sendEvent("purchase", null, {
76+
revenue: 9.99,
77+
currency: "USD",
78+
});
79+
80+
await AppSprint.sendEvent("custom", "onboarding_step", {
81+
screen: "welcome",
82+
step: 1,
83+
});
84+
```
85+
86+
Supported `eventType` values:
87+
88+
`login` | `sign_up` | `register` | `purchase` | `subscribe` | `start_trial` | `add_to_cart` | `add_to_wishlist` | `initiate_checkout` | `view_content` | `view_item` | `search` | `share` | `tutorial_complete` | `level_start` | `level_complete` | `custom`
89+
90+
Notes:
91+
92+
- Use `eventType: "custom"` together with the optional `name` argument for custom event names.
93+
- Revenue fields are accepted through `params.revenue` and `params.currency`.
94+
- If an event cannot be delivered, it is queued locally and retried on the next initialization or explicit flush.
95+
96+
## Public API
97+
98+
### `AppSprint`
99+
100+
```tsx
101+
import { AppSprint } from "appsprint-react-native";
102+
```
103+
104+
Available methods:
105+
106+
- `configure(config)` initializes the SDK and performs install tracking when needed.
107+
- `sendEvent(eventType, name?, params?)` sends or queues an event.
108+
- `sendTestEvent()` sends a diagnostic event and returns `{ success, message }`.
109+
- `flush()` retries queued events immediately.
110+
- `clearData()` clears cached SDK state and the local event queue.
111+
- `isSdkDisabled()` returns whether the SDK has been disabled because the API key was rejected.
112+
- `setCustomerUserId(userId)` updates the customer user id locally and remotely when possible.
113+
- `getAppSprintId()` returns the cached AppSprint install identifier, if available.
114+
- `getAttribution()` returns the last cached attribution result, if available.
115+
- `enableAppleAdsAttribution()` re-enables Apple Ads attribution in the current runtime config.
116+
- `isInitialized()` reports whether `configure()` completed.
117+
- `destroy()` removes SDK listeners.
118+
119+
### `NativeAppSprint`
120+
121+
```tsx
122+
import { NativeAppSprint } from "appsprint-react-native";
123+
```
124+
125+
Available methods:
126+
127+
- `getDeviceInfo()`
128+
- `getAdServicesToken()`
129+
- `requestTrackingAuthorization()`
130+
131+
Example ATT request on iOS:
132+
133+
```tsx
134+
import { NativeAppSprint } from "appsprint-react-native";
135+
136+
const authorized = await NativeAppSprint.requestTrackingAuthorization();
137+
```
138+
139+
## Attribution
140+
141+
The SDK tracks install attribution once an install is registered. You can read the cached values at any time:
142+
143+
```tsx
144+
const attribution = await AppSprint.getAttribution();
145+
const appsprintId = await AppSprint.getAppSprintId();
146+
```
147+
148+
`AttributionResult.source` can be:
149+
150+
`apple_ads` | `fingerprint` | `organic`
151+
152+
## Offline and retry behavior
153+
154+
- The SDK keeps up to `100` queued events in local storage.
155+
- Queued events are flushed after `configure()` and when the app moves to the background.
156+
- Failed flushes keep the unsent events queued for a later retry.
157+
- A rejected API key (`401` or `403`) disables the SDK and drops future events until cached data is cleared.
158+
159+
## Local development
160+
161+
Point the SDK at a non-production backend during development:
162+
163+
```tsx
164+
await AppSprint.configure({
165+
apiKey: "YOUR_API_KEY",
166+
apiUrl: "http://localhost:3000",
167+
isDebug: true,
168+
});
169+
```
170+
171+
## License
172+
173+
MIT

android/build.gradle

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
buildscript {
2+
ext.safeExtGet = {prop, fallback ->
3+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
4+
}
5+
}
6+
7+
apply plugin: 'com.android.library'
8+
apply plugin: 'kotlin-android'
9+
10+
android {
11+
namespace "com.appsprint"
12+
compileSdkVersion safeExtGet('compileSdkVersion', 35)
13+
14+
defaultConfig {
15+
minSdkVersion safeExtGet('minSdkVersion', 24)
16+
targetSdkVersion safeExtGet('targetSdkVersion', 35)
17+
}
18+
19+
compileOptions {
20+
sourceCompatibility JavaVersion.VERSION_17
21+
targetCompatibility JavaVersion.VERSION_17
22+
}
23+
24+
kotlinOptions {
25+
jvmTarget = '17'
26+
}
27+
28+
sourceSets {
29+
main {
30+
java.srcDirs += 'src/main/kotlin'
31+
}
32+
}
33+
}
34+
35+
dependencies {
36+
implementation "com.facebook.react:react-android:+"
37+
implementation files('libs/appsprint-sdk.aar')
38+
implementation "androidx.lifecycle:lifecycle-process:2.8.7"
39+
}

android/libs/appsprint-sdk.aar

20.2 KB
Binary file not shown.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="com.appsprint">
3+
</manifest>

0 commit comments

Comments
 (0)