@booleanmaths/booleanmaths-rn-sdk 0.2.0 → 0.3.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/BooleanmathsRnSdk.podspec +26 -0
- package/README.md +204 -65
- package/ios/BMBooleanMathsBridge.swift +146 -0
- package/ios/BooleanmathsRnSdk.h +11 -10
- package/ios/BooleanmathsRnSdk.mm +68 -14
- package/lib/module/BooleanMaths.native.js +9 -5
- package/lib/module/BooleanMaths.native.js.map +1 -1
- package/lib/typescript/src/BooleanMaths.native.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +16 -7
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/BooleanMaths.native.tsx +12 -5
- package/src/types.ts +16 -7
|
@@ -10,11 +10,37 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.license = package["license"]
|
|
11
11
|
s.authors = package["author"]
|
|
12
12
|
|
|
13
|
+
# No platform override needed. BooleanMathsSDK 1.0.1 lowered its own floor to
|
|
14
|
+
# 15.1, which is exactly React Native's min_ios_version_supported — pinning a
|
|
15
|
+
# higher floor here would push it onto every consuming app.
|
|
13
16
|
s.platforms = { :ios => min_ios_version_supported }
|
|
14
17
|
s.source = { :git => "https://github.com/medront/react-native-booleanmaths-sdk.git", :tag => "v#{s.version}" }
|
|
15
18
|
|
|
19
|
+
# Globs `swift` so ios/BMBooleanMathsBridge.swift is compiled. That shim is
|
|
20
|
+
# mandatory, not stylistic: BooleanMaths is a pure Swift `@MainActor final
|
|
21
|
+
# class` with no Objective-C surface, so the .mm cannot reach it directly.
|
|
16
22
|
s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
|
|
23
|
+
# Does not match the generated BooleanmathsRnSdk-Swift.h, which the .mm needs.
|
|
17
24
|
s.private_header_files = "ios/**/*.h"
|
|
18
25
|
|
|
26
|
+
s.swift_version = "5.9"
|
|
27
|
+
|
|
28
|
+
# `~> 1.0.1`, deliberately not `~> 1.0`: 1.0.0 is still published on Trunk
|
|
29
|
+
# carrying an iOS 17.0 deployment target, and resolving to it would break the
|
|
30
|
+
# install for any app below iOS 17.
|
|
31
|
+
s.dependency "BooleanMathsSDK", "~> 1.0.1"
|
|
32
|
+
|
|
33
|
+
# Mirrors Android's BuildConfig.WRAPPER_VERSION, which is read from
|
|
34
|
+
# package.json so the reported wrapper_version cannot drift from the published
|
|
35
|
+
# npm version — s.version is that same value. Consumed by the .mm as an
|
|
36
|
+
# Objective-C preprocessor define; it does not reach Swift.
|
|
37
|
+
#
|
|
38
|
+
# $(inherited) is load-bearing: without it this replaces the pod target's
|
|
39
|
+
# inherited defines instead of appending, dropping DEBUG, RCT_NEW_ARCH_ENABLED
|
|
40
|
+
# and the FOLLY_* flags that React Native's own xcconfig sets.
|
|
41
|
+
s.pod_target_xcconfig = {
|
|
42
|
+
"GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) BMRN_WRAPPER_VERSION=\\\"#{s.version}\\\""
|
|
43
|
+
}
|
|
44
|
+
|
|
19
45
|
install_modules_dependencies(s)
|
|
20
46
|
end
|
package/README.md
CHANGED
|
@@ -5,42 +5,90 @@ and attribution.
|
|
|
5
5
|
|
|
6
6
|
This package is a thin TurboModule bridge over the native
|
|
7
7
|
[`com.booleanmaths:bm-sdk`](https://central.sonatype.com/artifact/com.booleanmaths/bm-sdk)
|
|
8
|
-
Android SDK
|
|
8
|
+
Android SDK and the
|
|
9
|
+
[`BooleanMathsSDK`](https://cocoapods.org/pods/BooleanMathsSDK) iOS SDK.
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
**One import, one API, both platforms.** There are no platform-specific entry
|
|
12
|
+
points — `import { BooleanMaths } from '@booleanmaths/booleanmaths-rn-sdk'` and
|
|
13
|
+
call the same methods everywhere.
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
---
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
> **Android only**. On iOS (and on web) this package installs and builds
|
|
16
|
-
> normally, but **every SDK call is a no-op and no events are tracked**.
|
|
17
|
+
## Platform support
|
|
17
18
|
|
|
18
19
|
| Platform | Native SDK | Behaviour |
|
|
19
20
|
| :------- | :--------- | :-------- |
|
|
20
21
|
| Android | ✅ `com.booleanmaths:bm-sdk:1.0.9` | Fully functional |
|
|
21
|
-
| iOS |
|
|
22
|
+
| iOS | ✅ `BooleanMathsSDK 1.0.1` | Event tracking fully functional — see below |
|
|
22
23
|
| Web | ❌ not published | Silent no-op, **never crashes** |
|
|
23
24
|
|
|
25
|
+
### What iOS supports
|
|
26
|
+
|
|
27
|
+
Event tracking is complete and at parity with Android. Attribution features
|
|
28
|
+
are not — they are deferred to a later release, so their absence is scope
|
|
29
|
+
rather than a bug.
|
|
30
|
+
|
|
31
|
+
| Feature | Android | iOS |
|
|
32
|
+
| :------ | :-----: | :-: |
|
|
33
|
+
| `initialize()` | ✅ | ✅ |
|
|
34
|
+
| `trackEvent()` with nested properties | ✅ | ✅ |
|
|
35
|
+
| `wrapper_type` / `wrapper_version` on every event | ✅ | ✅ |
|
|
36
|
+
| Automatic `app_opened` | ✅ | ✅ |
|
|
37
|
+
| Automatic `FirstOpen` (once per install) | ✅ | ✅ — but with no attribution payload, see below |
|
|
38
|
+
| Visitor ID and 30-minute session handling | ✅ | ✅ |
|
|
39
|
+
| Durable on-device queue surviving app restarts | ✅ | ✅ |
|
|
40
|
+
| Automatic flush when the app backgrounds | ✅ | ✅ |
|
|
41
|
+
| `getHelloMessage()` bridge smoke test | ✅ | ✅ |
|
|
42
|
+
| **Deep links / universal links** (`DeepLinkClick`) | ✅ | ❌ |
|
|
43
|
+
| **Push-notification attribution** (`NotificationClick`) | ✅ | ❌ |
|
|
44
|
+
| **`handleIntent()` / `handleNotificationIntent()`** | ✅ | ❌ no-op |
|
|
45
|
+
| **Install attribution** on `FirstOpen` | ✅ Play Install Referrer | ❌ `data` is `{}` |
|
|
46
|
+
|
|
47
|
+
Notes on the iOS gaps:
|
|
48
|
+
|
|
49
|
+
- **`handleIntent()` is safe to call on iOS.** It reaches a native no-op and
|
|
50
|
+
logs one dev-mode notice. Shared code does not need to branch on platform.
|
|
51
|
+
- **`FirstOpen` still fires on iOS**, once per install — it just carries no
|
|
52
|
+
campaign payload. `data` is `{}` (present but empty), so the wire shape will
|
|
53
|
+
not change when Apple Search Ads attribution lands.
|
|
54
|
+
- On iOS there is **no `DeepLinkClick` or `NotificationClick` event at all**,
|
|
55
|
+
and consequently no `data.attribution` block on subsequent events.
|
|
56
|
+
- **`flush()` is not exposed to JavaScript** on either platform. The iOS SDK
|
|
57
|
+
flushes automatically on `willResignActive` / `didBecomeActive`; it will be
|
|
58
|
+
exposed only once Android has an equivalent, so it can ship as a genuinely
|
|
59
|
+
cross-platform API.
|
|
60
|
+
- macOS and tvOS are out of scope. The native SDK compiles for them; this
|
|
61
|
+
wrapper targets iOS only.
|
|
62
|
+
|
|
24
63
|
### Why it does not crash
|
|
25
64
|
|
|
26
|
-
Two independent guards, so
|
|
65
|
+
Two independent guards, so an unsupported platform or an incomplete native
|
|
66
|
+
install can never take your app down:
|
|
27
67
|
|
|
28
68
|
1. **JavaScript gate.** `BooleanMaths` checks `Platform.OS` against an
|
|
29
|
-
allowlist (
|
|
69
|
+
allowlist (`['android', 'ios']`) and returns before touching the native
|
|
30
70
|
bridge. It also verifies the TurboModule actually resolved, which covers a
|
|
31
|
-
broken or incomplete native install
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
71
|
+
broken or incomplete native install — most often a JS install without a
|
|
72
|
+
native rebuild.
|
|
73
|
+
2. **Native backstop.** Every native call is wrapped so failures are logged
|
|
74
|
+
rather than thrown into JavaScript
|
|
75
|
+
([`safely()`](android/src/main/java/com/booleanmathsrnsdk/BooleanmathsRnSdkModule.kt)
|
|
76
|
+
on Android, `BMSafely()` in
|
|
77
|
+
[`ios/BooleanmathsRnSdk.mm`](ios/BooleanmathsRnSdk.mm)). Analytics should
|
|
78
|
+
never crash the host app.
|
|
79
|
+
|
|
80
|
+
On web the JavaScript gate is the whole story: a separate no-op implementation
|
|
81
|
+
([`src/BooleanMaths.tsx`](src/BooleanMaths.tsx)) is resolved by the bundler, so
|
|
82
|
+
shared code can call the SDK unconditionally without platform checks.
|
|
35
83
|
|
|
36
84
|
In development (`__DEV__`) you get **one** console warning per app launch, not
|
|
37
85
|
one per call.
|
|
38
86
|
|
|
39
|
-
###
|
|
87
|
+
### Optionally gate your own analytics code
|
|
40
88
|
|
|
41
89
|
Calling the SDK unconditionally is safe — you do not *need* to branch. But if
|
|
42
|
-
you want to avoid dead work, skip the dev warning, or show different UI,
|
|
43
|
-
on `isSupported`:
|
|
90
|
+
you want to avoid dead work on web, skip the dev warning, or show different UI,
|
|
91
|
+
branch on `isSupported`:
|
|
44
92
|
|
|
45
93
|
```ts
|
|
46
94
|
import { BooleanMaths } from '@booleanmaths/booleanmaths-rn-sdk';
|
|
@@ -48,21 +96,12 @@ import { BooleanMaths } from '@booleanmaths/booleanmaths-rn-sdk';
|
|
|
48
96
|
if (BooleanMaths.isSupported) {
|
|
49
97
|
BooleanMaths.initialize(API_KEY, PIXEL_ID);
|
|
50
98
|
} else {
|
|
51
|
-
//
|
|
99
|
+
// Web, or a native install that needs rebuilding. Fall back or do nothing.
|
|
52
100
|
}
|
|
53
101
|
```
|
|
54
102
|
|
|
55
|
-
`isSupported` is
|
|
56
|
-
often as you like.
|
|
57
|
-
|
|
58
|
-
### When the iOS SDK ships
|
|
59
|
-
|
|
60
|
-
Two changes, no API break for consumers:
|
|
61
|
-
|
|
62
|
-
1. Add the iOS dependency to [`BooleanmathsRnSdk.podspec`](BooleanmathsRnSdk.podspec)
|
|
63
|
-
and implement the method bodies in [`ios/BooleanmathsRnSdk.mm`](ios/BooleanmathsRnSdk.mm).
|
|
64
|
-
2. Add `'ios'` to `SUPPORTED_PLATFORMS` in
|
|
65
|
-
[`src/BooleanMaths.native.tsx`](src/BooleanMaths.native.tsx).
|
|
103
|
+
`isSupported` is `true` on Android and iOS. It is a plain boolean, evaluated at
|
|
104
|
+
module load — cheap to read as often as you like.
|
|
66
105
|
|
|
67
106
|
---
|
|
68
107
|
|
|
@@ -78,14 +117,17 @@ Then rebuild the native app — a Metro reload is **not** enough:
|
|
|
78
117
|
|
|
79
118
|
```sh
|
|
80
119
|
npx react-native run-android
|
|
120
|
+
# and/or
|
|
121
|
+
cd ios && pod install && cd .. && npx react-native run-ios
|
|
81
122
|
```
|
|
82
123
|
|
|
83
124
|
### Requirements
|
|
84
125
|
|
|
85
126
|
- React Native **0.80+** with the **New Architecture** enabled (this is a
|
|
86
127
|
TurboModule)
|
|
87
|
-
- Android
|
|
88
|
-
|
|
128
|
+
- **Android:** `minSdkVersion` 24 or higher (the native SDK requires it),
|
|
129
|
+
`compileSdkVersion 36`, Java 17
|
|
130
|
+
- **iOS:** deployment target **15.1** or higher, and **Xcode 16+**
|
|
89
131
|
|
|
90
132
|
### Android
|
|
91
133
|
|
|
@@ -105,13 +147,31 @@ buildscript {
|
|
|
105
147
|
|
|
106
148
|
### iOS
|
|
107
149
|
|
|
108
|
-
|
|
109
|
-
compiles and links, it just does not track anything.
|
|
150
|
+
Autolinking picks the module up; run `pod install` to pull in the native SDK.
|
|
110
151
|
|
|
111
152
|
```sh
|
|
112
153
|
cd ios && pod install
|
|
113
154
|
```
|
|
114
155
|
|
|
156
|
+
That resolves `BooleanMathsSDK` from CocoaPods Trunk. Points worth knowing:
|
|
157
|
+
|
|
158
|
+
- **Minimum deployment target is iOS 15.1**, matching React Native's own floor,
|
|
159
|
+
so adopting this SDK does not raise your app's minimum iOS version.
|
|
160
|
+
- **The pod is pinned to `~> 1.0.1`,** deliberately not `~> 1.0`. Version 1.0.0
|
|
161
|
+
is still published with an iOS 17.0 floor, and resolving to it would break
|
|
162
|
+
the install for apps below iOS 17. Confirm your `Podfile.lock` shows
|
|
163
|
+
`BooleanMathsSDK (1.0.1)` or newer.
|
|
164
|
+
- **The SDK ships as a closed-source, vendored *dynamic* XCFramework.**
|
|
165
|
+
CocoaPods embeds and re-signs it with your app's identity. If you use
|
|
166
|
+
`use_frameworks!`, both `:linkage => :static` and `:linkage => :dynamic`
|
|
167
|
+
are supported.
|
|
168
|
+
- **No privacy manifest work needed.** The SDK bundles its own
|
|
169
|
+
`PrivacyInfo.xcprivacy` inside the XCFramework, so App Store
|
|
170
|
+
privacy-manifest requirements are covered by the pod.
|
|
171
|
+
- **Xcode 16+ is required.** The SDK's `.swiftinterface` is emitted at Swift 6.
|
|
172
|
+
Library evolution is enabled, so it is not pinned to the exact Xcode that
|
|
173
|
+
built it — but the toolchain must understand Swift 6.
|
|
174
|
+
|
|
115
175
|
---
|
|
116
176
|
|
|
117
177
|
## Usage
|
|
@@ -146,9 +206,16 @@ ignored.
|
|
|
146
206
|
|
|
147
207
|
### `BooleanMaths.initialize(apiKey, pixelId): void`
|
|
148
208
|
|
|
149
|
-
Initializes the native SDK. Also registers this wrapper with the native SDK
|
|
150
|
-
|
|
151
|
-
|
|
209
|
+
Initializes the native SDK. Also registers this wrapper with the native SDK
|
|
210
|
+
**before** initializing, so that even the automatic `FirstOpen` and `app_opened`
|
|
211
|
+
events emitted during initialization already carry
|
|
212
|
+
`wrapper_type: "react-native"` and the wrapper version. That version is read
|
|
213
|
+
from `package.json` on both platforms, so it cannot drift from the published npm
|
|
214
|
+
version.
|
|
215
|
+
|
|
216
|
+
On Android it additionally forwards the launch intent (see
|
|
217
|
+
[Deep links](#deep-links-and-notification-attribution)); there is no iOS
|
|
218
|
+
equivalent.
|
|
152
219
|
|
|
153
220
|
### `BooleanMaths.trackEvent(name, properties?): void`
|
|
154
221
|
|
|
@@ -157,14 +224,19 @@ numbers, booleans, nested objects, and arrays.
|
|
|
157
224
|
|
|
158
225
|
### `BooleanMaths.handleIntent(): void`
|
|
159
226
|
|
|
160
|
-
**Android only
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
227
|
+
**Android only.** Forwards the current Activity's intent to the native SDK so
|
|
228
|
+
ad deep links, app links and push-notification campaign data are attributed.
|
|
229
|
+
Safe to call repeatedly — the native SDK de-duplicates intents it has already
|
|
230
|
+
seen.
|
|
164
231
|
|
|
165
232
|
This is the single entry point for every kind of launch intent; native SDK
|
|
166
233
|
1.0.9 unified them behind one method.
|
|
167
234
|
|
|
235
|
+
**A no-op on iOS**, and safe to call there — it logs one dev-mode notice and
|
|
236
|
+
returns. The reason is scope, not platform support: intents are an Android
|
|
237
|
+
concept, and iOS deep links / universal links are deferred to a later release.
|
|
238
|
+
You do not need to branch on platform before calling it.
|
|
239
|
+
|
|
168
240
|
### `BooleanMaths.handleNotificationIntent(): void`
|
|
169
241
|
|
|
170
242
|
Deprecated alias of `handleIntent()`, kept so existing callers keep working.
|
|
@@ -174,16 +246,26 @@ behavioural difference — prefer `handleIntent()` in new code.
|
|
|
174
246
|
### `BooleanMaths.getHelloMessage(): string | null`
|
|
175
247
|
|
|
176
248
|
Bridge smoke test. Returns the native SDK's hello string, or `null` where there
|
|
177
|
-
is no native SDK.
|
|
249
|
+
is no native SDK. The string comes from the native SDK itself on both platforms
|
|
250
|
+
(not from this wrapper), so a correct value also proves the native artifact
|
|
251
|
+
actually linked — which on iOS is the quickest way to confirm the XCFramework
|
|
252
|
+
was embedded.
|
|
178
253
|
|
|
179
254
|
### `BooleanMaths.isSupported: boolean`
|
|
180
255
|
|
|
181
|
-
`true` only where a real native SDK is linked
|
|
256
|
+
`true` only where a real native SDK is linked — Android and iOS. `false` on
|
|
257
|
+
web, and on any platform where the native module failed to resolve (typically a
|
|
258
|
+
JS install without a native rebuild).
|
|
182
259
|
|
|
183
260
|
---
|
|
184
261
|
|
|
185
262
|
## Deep links and notification attribution
|
|
186
263
|
|
|
264
|
+
> **Android only.** This entire section does not apply to iOS, where
|
|
265
|
+
> `handleIntent()` is a no-op and no `DeepLinkClick` / `NotificationClick`
|
|
266
|
+
> events are produced. The code below is still safe to run unchanged on iOS —
|
|
267
|
+
> the calls simply do nothing.
|
|
268
|
+
|
|
187
269
|
The native SDK registers its `ActivityLifecycleCallbacks` **inside**
|
|
188
270
|
`initialize()`. In a React Native app that runs long after `MainActivity`'s
|
|
189
271
|
`onActivityCreated` has already fired, so **the intent that cold-started your
|
|
@@ -277,17 +359,25 @@ intent without `ACTION_VIEW` takes the `NotificationClick` path instead — see
|
|
|
277
359
|
|
|
278
360
|
The native SDK tracks these without any call from you:
|
|
279
361
|
|
|
280
|
-
| Event | When |
|
|
281
|
-
| :---- | :--- |
|
|
282
|
-
| `app_opened` | First Activity creation / SDK initialization |
|
|
283
|
-
| `FirstOpen` | Once per install
|
|
284
|
-
| `DeepLinkClick` | An `ACTION_VIEW` intent is handled — ad deep links and app links. Campaign fields nest under `data.link` |
|
|
285
|
-
| `NotificationClick` | Any other intent carrying campaign data is handled. Fields nest under `data.notification` |
|
|
362
|
+
| Event | When | Android | iOS |
|
|
363
|
+
| :---- | :--- | :-----: | :-: |
|
|
364
|
+
| `app_opened` | First Activity creation / SDK initialization | ✅ | ✅ |
|
|
365
|
+
| `FirstOpen` | Once per install | ✅ with Google Play Install Referrer attribution | ✅ but `data` is `{}` |
|
|
366
|
+
| `DeepLinkClick` | An `ACTION_VIEW` intent is handled — ad deep links and app links. Campaign fields nest under `data.link` | ✅ | ❌ |
|
|
367
|
+
| `NotificationClick` | Any other intent carrying campaign data is handled. Fields nest under `data.notification` | ✅ | ❌ |
|
|
368
|
+
|
|
369
|
+
On both platforms `FirstOpen` precedes `app_opened`, so a new install's stream
|
|
370
|
+
reads in order. `FirstOpen` is PascalCase on the wire on purpose — the two
|
|
371
|
+
platforms match byte-for-byte and backend install reporting keys off that exact
|
|
372
|
+
string.
|
|
286
373
|
|
|
287
374
|
Visitor ID and session ID (30-minute timeout) are generated and persisted
|
|
288
|
-
natively
|
|
289
|
-
|
|
290
|
-
|
|
375
|
+
natively on both platforms.
|
|
376
|
+
|
|
377
|
+
**Attribution is Android-only.** Campaign data from a handled intent is
|
|
378
|
+
persisted by `AttributionManager` and attached to **every subsequent event** as
|
|
379
|
+
`data.attribution`. iOS produces no `data.attribution` block, since it handles
|
|
380
|
+
no intents; Apple Search Ads attribution is deferred to a later release.
|
|
291
381
|
|
|
292
382
|
### What counts as a campaign intent (native SDK v1.0.9)
|
|
293
383
|
|
|
@@ -320,7 +410,34 @@ de-duplicated in a `WeakHashMap`, so re-forwarding the same intent is a no-op.
|
|
|
320
410
|
|
|
321
411
|
## How properties cross the bridge
|
|
322
412
|
|
|
323
|
-
|
|
413
|
+
Each platform normalizes `properties` at the native boundary before handing it
|
|
414
|
+
to the SDK. The rules differ because the two SDKs serialize differently — the
|
|
415
|
+
observable payload is the same in the cases that matter.
|
|
416
|
+
|
|
417
|
+
| Input | Android | iOS |
|
|
418
|
+
| :---- | :------ | :-- |
|
|
419
|
+
| `null` / `undefined` object value | Key dropped | Key dropped |
|
|
420
|
+
| `null` inside an array | Preserved (indices must not shift) | Preserved |
|
|
421
|
+
| Nested objects and arrays | Recursed | Recursed |
|
|
422
|
+
| Whole numbers (`3`) | Coerced to integer — see the Gson caveat below | No action needed; `JSONSerialization` already emits `3`, not `3.0` |
|
|
423
|
+
| Fractions (`999.5`) | Untouched | Untouched |
|
|
424
|
+
| Booleans | Untouched | Untouched |
|
|
425
|
+
| **`NaN` / `Infinity`** | Passed through as-is | **Key dropped** — see below |
|
|
426
|
+
|
|
427
|
+
### iOS: why `NaN` is dropped rather than passed through
|
|
428
|
+
|
|
429
|
+
This one is load-bearing, not cosmetic. The iOS SDK guards its writes with
|
|
430
|
+
`JSONSerialization.isValidJSONObject(...)` and **silently discards the payload**
|
|
431
|
+
when that returns false. A JS `NaN` or `Infinity` arrives as a non-finite
|
|
432
|
+
`NSNumber` and invalidates the whole object — so a single bad property value
|
|
433
|
+
could discard the event, or the entire outgoing batch. The wrapper strips those
|
|
434
|
+
keys at the boundary so the rest of the event survives.
|
|
435
|
+
|
|
436
|
+
`NSDate` and anything else not JSON-representable is dropped for the same
|
|
437
|
+
reason. Everything is handled recursively, so a `NaN` nested three objects deep
|
|
438
|
+
costs you that one key and nothing else.
|
|
439
|
+
|
|
440
|
+
### Android normalization
|
|
324
441
|
|
|
325
442
|
- **Integral numbers are converted to integers.** React Native passes every JS
|
|
326
443
|
number across the bridge as a `Double`, so `{ count: 3 }` would otherwise be
|
|
@@ -346,28 +463,50 @@ Two normalizations happen on the Android side, both worth knowing:
|
|
|
346
463
|
serializes with Gson, which omits null map values anyway, so the emitted JSON
|
|
347
464
|
is identical. Nulls **inside arrays** are preserved so indices do not shift.
|
|
348
465
|
|
|
349
|
-
Failures in the native bridge are logged
|
|
350
|
-
|
|
466
|
+
Failures in the native bridge are logged rather than thrown into JavaScript —
|
|
467
|
+
analytics should never crash the host app. Android logs to
|
|
468
|
+
`adb logcat -s BooleanmathsRnSdk`; iOS logs through `RCTLogError`, visible in
|
|
469
|
+
Xcode's console and Metro.
|
|
351
470
|
|
|
352
471
|
---
|
|
353
472
|
|
|
354
473
|
## Troubleshooting
|
|
355
474
|
|
|
356
475
|
**No events arriving.** Confirm `BooleanMaths.isSupported` is `true`, then check
|
|
357
|
-
`adb logcat -s BooleanMathsSDK:D BooleanmathsRnSdk:D
|
|
358
|
-
|
|
476
|
+
the native logs — `adb logcat -s BooleanMathsSDK:D BooleanmathsRnSdk:D` on
|
|
477
|
+
Android, or Xcode's console on iOS. The native SDK logs each persisted event and
|
|
478
|
+
the full payload it sends.
|
|
359
479
|
|
|
360
480
|
**Warning: "native module could not be found".** The JS installed but the native
|
|
361
|
-
side did not. Rebuild the app (`npx react-native run-android
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
**
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
481
|
+
side did not. Rebuild the app (`npx react-native run-android`, or `pod install`
|
|
482
|
+
followed by `npx react-native run-ios`) rather than just reloading Metro.
|
|
483
|
+
|
|
484
|
+
**iOS: crash at launch with a dyld "Library not loaded" / "image not found"
|
|
485
|
+
error naming `BooleanMathsSDK`.** The XCFramework is a *dynamic* framework and
|
|
486
|
+
was not embedded. Confirm the `[CP] Embed Pods Frameworks` build phase exists on
|
|
487
|
+
your app target, then `pod deintegrate && pod install`. This is the one iOS
|
|
488
|
+
failure mode that builds cleanly and only shows up at runtime.
|
|
489
|
+
|
|
490
|
+
**iOS: `getHelloMessage()` returns an empty string.** The bridge resolved but the
|
|
491
|
+
native SDK call failed — check the Xcode console for a
|
|
492
|
+
`BooleanMaths getHelloMessage failed` error. An empty string here specifically
|
|
493
|
+
means the XCFramework did not link correctly.
|
|
494
|
+
|
|
495
|
+
**iOS: `pod install` fails to resolve `BooleanMathsSDK`.** Run
|
|
496
|
+
`pod repo update`, and confirm your app's deployment target is 15.1 or higher.
|
|
497
|
+
If the lockfile pinned `1.0.0`, delete that entry and reinstall — 1.0.0 carries
|
|
498
|
+
an iOS 17.0 floor.
|
|
499
|
+
|
|
500
|
+
**Events show a delay.** By design on both platforms. Each `trackEvent`
|
|
501
|
+
enqueues an immediate sync attempt; Android's WorkManager also runs a periodic
|
|
502
|
+
15-minute batch job and requires network connectivity, and iOS flushes when the
|
|
503
|
+
app backgrounds.
|
|
504
|
+
|
|
505
|
+
**Deep link not attributed.** Android only — see
|
|
506
|
+
[Deep links](#deep-links-and-notification-attribution); the launch intent needs
|
|
507
|
+
explicit forwarding, and `singleTask` activities need `setIntent`. On iOS deep
|
|
508
|
+
link attribution is not implemented at all
|
|
509
|
+
([what iOS supports](#what-ios-supports)).
|
|
371
510
|
|
|
372
511
|
---
|
|
373
512
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import BooleanMathsSDK
|
|
3
|
+
|
|
4
|
+
/// Objective-C-visible shim over the pure Swift `BooleanMathsSDK`.
|
|
5
|
+
///
|
|
6
|
+
/// This file is mandatory, not a stylistic layer. `BooleanMaths` is declared
|
|
7
|
+
/// `@MainActor public final class` — it is not `@objc` and not `NSObject`-derived
|
|
8
|
+
/// (and cannot trivially become `@objc`, which requires `NSObject` inheritance).
|
|
9
|
+
/// The SDK's generated `BooleanMathsSDK-Swift.h` therefore contains zero
|
|
10
|
+
/// `@interface` declarations, so `#import <BooleanMathsSDK/...>` from
|
|
11
|
+
/// `BooleanmathsRnSdk.mm` resolves to an empty module and the TurboModule cannot
|
|
12
|
+
/// see the SDK at all.
|
|
13
|
+
///
|
|
14
|
+
/// Everything here takes only Objective-C-representable types and is reached
|
|
15
|
+
/// from the `.mm` through the pod's generated `BooleanmathsRnSdk-Swift.h`.
|
|
16
|
+
///
|
|
17
|
+
/// Behaviour is specified by the Android module
|
|
18
|
+
/// (`android/src/main/java/com/booleanmathsrnsdk/BooleanmathsRnSdkModule.kt`),
|
|
19
|
+
/// which is the reference implementation for this wrapper.
|
|
20
|
+
@objc(BMBooleanMathsBridge)
|
|
21
|
+
public final class BMBooleanMathsBridge: NSObject {
|
|
22
|
+
|
|
23
|
+
/// Matches Android's `BuildConfig.WRAPPER_TYPE`.
|
|
24
|
+
private static let wrapperType = "react-native"
|
|
25
|
+
|
|
26
|
+
// MARK: - Public API
|
|
27
|
+
|
|
28
|
+
/// Initializes the native SDK and stamps this wrapper's identity onto it.
|
|
29
|
+
///
|
|
30
|
+
/// `@MainActor` because `BooleanMaths.initialize` is main-actor isolated. The
|
|
31
|
+
/// caller in `BooleanmathsRnSdk.mm` hops with `dispatch_async` before invoking
|
|
32
|
+
/// this — never `dispatch_sync`, which deadlocks when the JS thread is the
|
|
33
|
+
/// main thread.
|
|
34
|
+
///
|
|
35
|
+
/// Named `initializeSdk` rather than `initialize` for the same reason the
|
|
36
|
+
/// codegen spec is: `+[NSObject initialize]` already exists.
|
|
37
|
+
@MainActor
|
|
38
|
+
@objc(initializeSdkWithApiKey:pixelId:wrapperVersion:)
|
|
39
|
+
public static func initializeSdk(
|
|
40
|
+
apiKey: String,
|
|
41
|
+
pixelId: String,
|
|
42
|
+
wrapperVersion: String
|
|
43
|
+
) {
|
|
44
|
+
// Before `initialize`, not after: `initialize` itself emits `FirstOpen` and
|
|
45
|
+
// `app_opened` internally, and those must already carry wrapper_type /
|
|
46
|
+
// wrapper_version. Same ordering rationale as Android.
|
|
47
|
+
//
|
|
48
|
+
// Do NOT port Android's second, post-initialize call. Android needs it
|
|
49
|
+
// because its native SDK can only persist to SharedPreferences once it holds
|
|
50
|
+
// an application context, which it acquires inside initialize(). iOS has no
|
|
51
|
+
// such gap: `WrapperConfigStore.set` writes to UserDefaults unconditionally,
|
|
52
|
+
// and `initialize` calls `rehydrate()`, which fills each field only where it
|
|
53
|
+
// is still nil — so a value set earlier in the process outranks the
|
|
54
|
+
// persisted one. One call, before initialize, is correct and sufficient.
|
|
55
|
+
BooleanMaths.shared.setWrapperConfig(type: wrapperType, version: wrapperVersion)
|
|
56
|
+
|
|
57
|
+
BooleanMaths.shared.initialize(apiKey: apiKey, pixelId: pixelId)
|
|
58
|
+
|
|
59
|
+
// There is no iOS equivalent of Android's forwardCurrentIntent(): deep links
|
|
60
|
+
// are deferred on iOS, so nothing is forwarded here. See `handleIntent` in
|
|
61
|
+
// BooleanmathsRnSdk.mm.
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// Records a custom event. `properties` is sanitized first — see
|
|
65
|
+
/// `sanitized(value:allowNull:)` for why that is load-bearing.
|
|
66
|
+
///
|
|
67
|
+
/// `@MainActor` because `BooleanMaths.track` is main-actor isolated.
|
|
68
|
+
@MainActor
|
|
69
|
+
@objc(trackEventWithName:properties:)
|
|
70
|
+
public static func trackEvent(name: String, properties: [String: Any]?) {
|
|
71
|
+
BooleanMaths.shared.track(name, properties: sanitized(dictionary: properties ?? [:]))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/// Bridge smoke test. Deliberately not main-actor isolated: the TurboModule
|
|
75
|
+
/// method is synchronous and returns the value directly, so it must not hop
|
|
76
|
+
/// threads. `BooleanMaths.getHelloMessage()` is `nonisolated static` in the SDK
|
|
77
|
+
/// specifically to allow this.
|
|
78
|
+
///
|
|
79
|
+
/// A real SDK call rather than a wrapper-side literal, so it also proves the
|
|
80
|
+
/// XCFramework actually linked.
|
|
81
|
+
@objc(getHelloMessage)
|
|
82
|
+
public static func getHelloMessage() -> String {
|
|
83
|
+
BooleanMaths.getHelloMessage()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// MARK: - Properties sanitization
|
|
87
|
+
|
|
88
|
+
// `EventDispatcher` and `EventStore` both guard on
|
|
89
|
+
// `JSONSerialization.isValidJSONObject(...)` and silently drop the payload when
|
|
90
|
+
// it returns false. A JS `NaN` or `Infinity` arrives here as a non-finite
|
|
91
|
+
// NSNumber and makes the whole object invalid — so one bad property value can
|
|
92
|
+
// discard the event, or the entire outgoing batch. Android guards the same case
|
|
93
|
+
// in `normalizeValue`.
|
|
94
|
+
|
|
95
|
+
private static func sanitized(dictionary: [String: Any]) -> [String: Any] {
|
|
96
|
+
var result = [String: Any](minimumCapacity: dictionary.count)
|
|
97
|
+
|
|
98
|
+
for (key, value) in dictionary {
|
|
99
|
+
guard let clean = sanitized(value: value, allowNull: false) else { continue }
|
|
100
|
+
result[key] = clean
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return result
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/// Nulls are preserved inside arrays — dropping them would shift indices.
|
|
107
|
+
/// Android preserves them deliberately for the same reason.
|
|
108
|
+
private static func sanitized(array: [Any]) -> [Any] {
|
|
109
|
+
array.map { sanitized(value: $0, allowNull: true) ?? NSNull() }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private static func sanitized(value: Any, allowNull: Bool) -> Any? {
|
|
113
|
+
switch value {
|
|
114
|
+
case is NSNull:
|
|
115
|
+
// Dropped as an object value (matching Android, whose Gson omits null map
|
|
116
|
+
// values anyway), kept inside an array.
|
|
117
|
+
return allowNull ? NSNull() : nil
|
|
118
|
+
|
|
119
|
+
case let number as NSNumber:
|
|
120
|
+
// Must be tested before any `as Bool` cast: `NSNumber(1) as? Bool`
|
|
121
|
+
// succeeds under Swift bridging, so checking Bool first would silently
|
|
122
|
+
// turn `{ count: 1 }` into `{ count: true }`. Booleans arrive from React
|
|
123
|
+
// Native as CFBoolean, match here, and serialize as true/false unchanged.
|
|
124
|
+
//
|
|
125
|
+
// No whole-number coercion: Android's `toWholeNumberOrSelf` fixes a
|
|
126
|
+
// Gson-specific artifact, whereas JSONSerialization already emits `3`
|
|
127
|
+
// rather than `3.0`.
|
|
128
|
+
return number.doubleValue.isFinite ? number : nil
|
|
129
|
+
|
|
130
|
+
case let string as String:
|
|
131
|
+
return string
|
|
132
|
+
|
|
133
|
+
case let nested as [String: Any]:
|
|
134
|
+
return sanitized(dictionary: nested)
|
|
135
|
+
|
|
136
|
+
case let nested as [Any]:
|
|
137
|
+
return sanitized(array: nested)
|
|
138
|
+
|
|
139
|
+
default:
|
|
140
|
+
// NSDate and anything else not JSON-representable, plus dictionaries with
|
|
141
|
+
// non-String keys. React Native never produces these from a JS object, but
|
|
142
|
+
// passing one through would invalidate the payload.
|
|
143
|
+
return nil
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
package/ios/BooleanmathsRnSdk.h
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
#import <BooleanmathsRnSdkSpec/BooleanmathsRnSdkSpec.h>
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* iOS
|
|
4
|
+
* iOS implementation of the BooleanMaths TurboModule, backed by the
|
|
5
|
+
* `BooleanMathsSDK` pod (>= 1.0.1, minimum iOS 15.1).
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* The SDK itself is pure Swift and exposes no Objective-C surface, so this class
|
|
8
|
+
* does not talk to it directly — every call goes through
|
|
9
|
+
* `BMBooleanMathsBridge` (`ios/BMBooleanMathsBridge.swift`), which explains why
|
|
10
|
+
* in detail.
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
* `
|
|
13
|
-
*
|
|
12
|
+
* `initializeSdk` and `trackEvent` hop to the main queue because the SDK is
|
|
13
|
+
* `@MainActor`; `getHelloMessage` deliberately does not, being synchronous and
|
|
14
|
+
* value-returning. Failures are logged and swallowed rather than thrown into JS.
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* `handleIntent` and `handleNotificationIntent` remain no-ops: intents are an
|
|
17
|
+
* Android concept and iOS deep links are out of scope for this release.
|
|
17
18
|
*/
|
|
18
19
|
@interface BooleanmathsRnSdk : NSObject <NativeBooleanmathsRnSdkSpec>
|
|
19
20
|
|
package/ios/BooleanmathsRnSdk.mm
CHANGED
|
@@ -2,50 +2,104 @@
|
|
|
2
2
|
|
|
3
3
|
#import <React/RCTLog.h>
|
|
4
4
|
|
|
5
|
+
// The generated header for BMBooleanMathsBridge.swift. Both paths are needed so
|
|
6
|
+
// this builds under static and dynamic pod linkage alike.
|
|
7
|
+
#if __has_include(<BooleanmathsRnSdk/BooleanmathsRnSdk-Swift.h>)
|
|
8
|
+
#import <BooleanmathsRnSdk/BooleanmathsRnSdk-Swift.h>
|
|
9
|
+
#else
|
|
10
|
+
#import "BooleanmathsRnSdk-Swift.h"
|
|
11
|
+
#endif
|
|
12
|
+
|
|
13
|
+
// Injected by BooleanmathsRnSdk.podspec from package.json's version, mirroring
|
|
14
|
+
// Android's BuildConfig.WRAPPER_VERSION. Only reached if that xcconfig failed to
|
|
15
|
+
// apply, in which case a wrong-looking wrapper_version is far better than a
|
|
16
|
+
// build error in a consumer's app.
|
|
17
|
+
#ifndef BMRN_WRAPPER_VERSION
|
|
18
|
+
#define BMRN_WRAPPER_VERSION "unknown"
|
|
19
|
+
#endif
|
|
20
|
+
|
|
5
21
|
@implementation BooleanmathsRnSdk
|
|
6
22
|
|
|
7
23
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
24
|
+
* Analytics must never take the host app down. Mirrors Android's `safely()`
|
|
25
|
+
* helper: log the failure and swallow it rather than surfacing it to JS.
|
|
26
|
+
*/
|
|
27
|
+
static void BMSafely(NSString *operation, void (^block)(void))
|
|
28
|
+
{
|
|
29
|
+
@try {
|
|
30
|
+
block();
|
|
31
|
+
} @catch (NSException *exception) {
|
|
32
|
+
RCTLogError(@"[@booleanmaths/booleanmaths-rn-sdk] BooleanMaths %@ failed: %@", operation, exception);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Logs the "deep links are Android-only" notice at most once per app launch, so
|
|
38
|
+
* it is visible without flooding the console.
|
|
10
39
|
*/
|
|
11
|
-
static void
|
|
40
|
+
static void BMWarnIntentUnsupportedOnce(void)
|
|
12
41
|
{
|
|
13
42
|
static dispatch_once_t onceToken;
|
|
14
43
|
dispatch_once(&onceToken, ^{
|
|
15
|
-
RCTLogWarn(@"[@booleanmaths/booleanmaths-rn-sdk]
|
|
16
|
-
@"
|
|
17
|
-
@"
|
|
44
|
+
RCTLogWarn(@"[@booleanmaths/booleanmaths-rn-sdk] Deep-link and notification intent forwarding is "
|
|
45
|
+
@"Android-only; handleIntent() is a no-op on iOS. Event tracking is fully supported — "
|
|
46
|
+
@"only intent attribution is unavailable.");
|
|
18
47
|
});
|
|
19
48
|
}
|
|
20
49
|
|
|
21
50
|
- (void)initializeSdk:(NSString *)apiKey pixelId:(NSString *)pixelId
|
|
22
51
|
{
|
|
23
|
-
|
|
52
|
+
// Captured outside the block: it is a compile-time constant, not thread state.
|
|
53
|
+
NSString *wrapperVersion = @BMRN_WRAPPER_VERSION;
|
|
54
|
+
|
|
55
|
+
// BooleanMaths is @MainActor. dispatch_async, never dispatch_sync — the latter
|
|
56
|
+
// deadlocks whenever the JS thread is the main thread.
|
|
57
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
58
|
+
BMSafely(@"initialize", ^{
|
|
59
|
+
[BMBooleanMathsBridge initializeSdkWithApiKey:apiKey
|
|
60
|
+
pixelId:pixelId
|
|
61
|
+
wrapperVersion:wrapperVersion];
|
|
62
|
+
});
|
|
63
|
+
});
|
|
24
64
|
}
|
|
25
65
|
|
|
26
66
|
- (void)trackEvent:(NSString *)name properties:(NSDictionary *)properties
|
|
27
67
|
{
|
|
28
|
-
|
|
68
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
69
|
+
BMSafely(@"trackEvent", ^{
|
|
70
|
+
[BMBooleanMathsBridge trackEventWithName:name properties:properties];
|
|
71
|
+
});
|
|
72
|
+
});
|
|
29
73
|
}
|
|
30
74
|
|
|
31
75
|
- (void)handleIntent
|
|
32
76
|
{
|
|
33
|
-
//
|
|
34
|
-
|
|
77
|
+
// Deliberately still a no-op. Intents are an Android concept, and iOS deep
|
|
78
|
+
// links / universal links are deferred — their absence here is scope, not a
|
|
79
|
+
// missing implementation.
|
|
80
|
+
BMWarnIntentUnsupportedOnce();
|
|
35
81
|
}
|
|
36
82
|
|
|
37
83
|
- (void)handleNotificationIntent
|
|
38
84
|
{
|
|
39
85
|
// Alias of handleIntent, mirroring the Android bridge.
|
|
40
|
-
|
|
86
|
+
BMWarnIntentUnsupportedOnce();
|
|
41
87
|
}
|
|
42
88
|
|
|
43
89
|
- (NSString *)getHelloMessage
|
|
44
90
|
{
|
|
45
|
-
|
|
91
|
+
// No dispatch: this is synchronous and returns a value, so it must not hop
|
|
92
|
+
// threads. The SDK's getHelloMessage() is `nonisolated static` to allow it.
|
|
93
|
+
@try {
|
|
94
|
+
return [BMBooleanMathsBridge getHelloMessage];
|
|
95
|
+
} @catch (NSException *exception) {
|
|
96
|
+
RCTLogError(@"[@booleanmaths/booleanmaths-rn-sdk] BooleanMaths getHelloMessage failed: %@", exception);
|
|
46
97
|
|
|
47
|
-
|
|
48
|
-
|
|
98
|
+
// Empty rather than a plausible-looking message: this method exists to prove
|
|
99
|
+
// the native SDK linked, so a failure must read as a failure. The codegen
|
|
100
|
+
// spec declares a non-optional string, so it cannot be nil.
|
|
101
|
+
return @"";
|
|
102
|
+
}
|
|
49
103
|
}
|
|
50
104
|
|
|
51
105
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
import { Platform } from 'react-native';
|
|
4
4
|
import NativeBooleanmathsRnSdk from "./NativeBooleanmathsRnSdk.js";
|
|
5
5
|
/**
|
|
6
|
-
* The BooleanMaths native SDK
|
|
7
|
-
* iOS
|
|
8
|
-
*
|
|
6
|
+
* The BooleanMaths native SDK ships for Android (`com.booleanmaths:bm-sdk`) and
|
|
7
|
+
* iOS (`BooleanMathsSDK`). Any other platform — including out-of-tree React
|
|
8
|
+
* Native targets — has no native artifact, so every call below short-circuits
|
|
9
|
+
* and the SDK behaves as a silent no-op rather than crashing the app.
|
|
10
|
+
*
|
|
11
|
+
* Note that `handleIntent` is a no-op on iOS even though iOS is supported here:
|
|
12
|
+
* intents are an Android concept. See its JSDoc in `./types`.
|
|
9
13
|
*/
|
|
10
|
-
const SUPPORTED_PLATFORMS = ['android'];
|
|
14
|
+
const SUPPORTED_PLATFORMS = ['android', 'ios'];
|
|
11
15
|
const isPlatformSupported = SUPPORTED_PLATFORMS.includes(Platform.OS);
|
|
12
16
|
|
|
13
17
|
/**
|
|
@@ -23,7 +27,7 @@ function warnOnce() {
|
|
|
23
27
|
}
|
|
24
28
|
hasWarned = true;
|
|
25
29
|
if (!isPlatformSupported) {
|
|
26
|
-
console.warn(`[@booleanmaths/booleanmaths-rn-sdk] The BooleanMaths native SDK is not available on ${Platform.OS} ` + '(Android
|
|
30
|
+
console.warn(`[@booleanmaths/booleanmaths-rn-sdk] The BooleanMaths native SDK is not available on ${Platform.OS} ` + '(Android and iOS only). All SDK calls are no-ops on this platform and no ' + 'events will be tracked. Gate your calls on `BooleanMaths.isSupported` to ' + 'silence this warning — see the README\'s "Platform support" section.');
|
|
27
31
|
return;
|
|
28
32
|
}
|
|
29
33
|
console.warn('[@booleanmaths/booleanmaths-rn-sdk] The native module could not be found on ' + `${Platform.OS}. Rebuild the app after installing the package (a Metro ` + 'reload is not enough), and on iOS run `pod install`. All SDK calls are ' + 'no-ops until this is fixed.');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Platform","NativeBooleanmathsRnSdk","SUPPORTED_PLATFORMS","isPlatformSupported","includes","OS","isSupported","hasWarned","warnOnce","__DEV__","console","warn","forwardCurrentIntent","handleIntent","BooleanMaths","initialize","apiKey","pixelId","initializeSdk","trackEvent","name","properties","handleNotificationIntent","getHelloMessage"],"sourceRoot":"../../src","sources":["BooleanMaths.native.tsx"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,cAAc;AACvC,OAAOC,uBAAuB,MAAM,8BAA2B;AAG/D;AACA;AACA;AACA;AACA;AACA,MAAMC,mBAAsD,GAAG,
|
|
1
|
+
{"version":3,"names":["Platform","NativeBooleanmathsRnSdk","SUPPORTED_PLATFORMS","isPlatformSupported","includes","OS","isSupported","hasWarned","warnOnce","__DEV__","console","warn","forwardCurrentIntent","handleIntent","BooleanMaths","initialize","apiKey","pixelId","initializeSdk","trackEvent","name","properties","handleNotificationIntent","getHelloMessage"],"sourceRoot":"../../src","sources":["BooleanMaths.native.tsx"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,cAAc;AACvC,OAAOC,uBAAuB,MAAM,8BAA2B;AAG/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,mBAAsD,GAAG,CAC7D,SAAS,EACT,KAAK,CACN;AAED,MAAMC,mBAAmB,GAAGD,mBAAmB,CAACE,QAAQ,CAACJ,QAAQ,CAACK,EAAE,CAAC;;AAErE;AACA;AACA;AACA;AACA;AACA,MAAMC,WAAW,GAAGH,mBAAmB,IAAIF,uBAAuB,IAAI,IAAI;AAE1E,IAAIM,SAAS,GAAG,KAAK;AAErB,SAASC,QAAQA,CAAA,EAAG;EAClB,IAAID,SAAS,IAAI,CAACE,OAAO,EAAE;IACzB;EACF;EAEAF,SAAS,GAAG,IAAI;EAEhB,IAAI,CAACJ,mBAAmB,EAAE;IACxBO,OAAO,CAACC,IAAI,CACV,uFAAuFX,QAAQ,CAACK,EAAE,GAAG,GACnG,2EAA2E,GAC3E,2EAA2E,GAC3E,sEACJ,CAAC;IACD;EACF;EAEAK,OAAO,CAACC,IAAI,CACV,8EAA8E,GAC5E,GAAGX,QAAQ,CAACK,EAAE,0DAA0D,GACxE,yEAAyE,GACzE,6BACJ,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAASO,oBAAoBA,CAAA,EAAS;EACpC,IAAI,CAACN,WAAW,EAAE;IAChBE,QAAQ,CAAC,CAAC;IACV;EACF;EAEAP,uBAAuB,CAAEY,YAAY,CAAC,CAAC;AACzC;AAEA,OAAO,MAAMC,YAA6B,GAAG;EAC3CR,WAAW;EAEXS,UAAUA,CAACC,MAAc,EAAEC,OAAe,EAAQ;IAChD,IAAI,CAACX,WAAW,EAAE;MAChBE,QAAQ,CAAC,CAAC;MACV;IACF;IAEAP,uBAAuB,CAAEiB,aAAa,CAACF,MAAM,EAAEC,OAAO,CAAC;EACzD,CAAC;EAEDE,UAAUA,CAACC,IAAY,EAAEC,UAAuC,GAAG,CAAC,CAAC,EAAQ;IAC3E,IAAI,CAACf,WAAW,EAAE;MAChBE,QAAQ,CAAC,CAAC;MACV;IACF;IAEAP,uBAAuB,CAAEkB,UAAU,CAACC,IAAI,EAAEC,UAAU,CAAC;EACvD,CAAC;EAEDR,YAAY,EAAED,oBAAoB;EAElCU,wBAAwB,EAAEV,oBAAoB;EAE9CW,eAAeA,CAAA,EAAkB;IAC/B,IAAI,CAACjB,WAAW,EAAE;MAChBE,QAAQ,CAAC,CAAC;MACV,OAAO,IAAI;IACb;IAEA,OAAOP,uBAAuB,CAAEsB,eAAe,CAAC,CAAC;EACnD;AACF,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BooleanMaths.native.d.ts","sourceRoot":"","sources":["../../../src/BooleanMaths.native.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAA+B,MAAM,YAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"BooleanMaths.native.d.ts","sourceRoot":"","sources":["../../../src/BooleanMaths.native.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAA+B,MAAM,YAAS,CAAC;AAmE5E,eAAO,MAAM,YAAY,EAAE,eAiC1B,CAAC"}
|
|
@@ -28,10 +28,14 @@ export interface BooleanMathsApi {
|
|
|
28
28
|
* Forwards the current Activity's intent to the native SDK so ad deep links,
|
|
29
29
|
* app links and push-notification campaign data are attributed.
|
|
30
30
|
*
|
|
31
|
-
* This is the primary entry point for every kind of launch intent.
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
31
|
+
* This is the primary entry point for every kind of launch intent. Call it
|
|
32
|
+
* from your deep-link handler; `initialize` already forwards the launch
|
|
33
|
+
* intent itself (see the README for why that needs special handling).
|
|
34
|
+
*
|
|
35
|
+
* **Android only.** A no-op on iOS — not because iOS is unsupported (event
|
|
36
|
+
* tracking works fully there), but because intents are an Android concept and
|
|
37
|
+
* iOS deep links / universal links are out of scope for now. Safe to call
|
|
38
|
+
* unconditionally from shared code; on iOS it logs one dev-mode notice.
|
|
35
39
|
*
|
|
36
40
|
* Safe to call repeatedly — the native SDK de-duplicates intents it has
|
|
37
41
|
* already processed.
|
|
@@ -47,12 +51,17 @@ export interface BooleanMathsApi {
|
|
|
47
51
|
handleNotificationIntent(): void;
|
|
48
52
|
/**
|
|
49
53
|
* Returns the native SDK's hello message, or `null` when there is no native
|
|
50
|
-
* SDK on this platform.
|
|
54
|
+
* SDK on this platform.
|
|
55
|
+
*
|
|
56
|
+
* Useful as a bridge smoke test: the string comes from the native SDK itself
|
|
57
|
+
* on both Android and iOS, so a correct value also proves the native artifact
|
|
58
|
+
* actually linked.
|
|
51
59
|
*/
|
|
52
60
|
getHelloMessage(): string | null;
|
|
53
61
|
/**
|
|
54
|
-
* `true` only on platforms where a real BooleanMaths native SDK is linked
|
|
55
|
-
*
|
|
62
|
+
* `true` only on platforms where a real BooleanMaths native SDK is linked —
|
|
63
|
+
* Android and iOS. `false` on web, and on any platform where the native
|
|
64
|
+
* module failed to resolve (typically a JS install without a native rebuild).
|
|
56
65
|
*/
|
|
57
66
|
readonly isSupported: boolean;
|
|
58
67
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GACjC,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,yBAAyB,EAAE,GAC3B;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,yBAAyB,CAAA;CAAE,CAAC;AAEjD,MAAM,MAAM,2BAA2B,GAAG,MAAM,CAC9C,MAAM,EACN,yBAAyB,CAC1B,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAElD;;;;;OAKG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,2BAA2B,GAAG,IAAI,CAAC;IAEzE
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GACjC,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,yBAAyB,EAAE,GAC3B;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,yBAAyB,CAAA;CAAE,CAAC;AAEjD,MAAM,MAAM,2BAA2B,GAAG,MAAM,CAC9C,MAAM,EACN,yBAAyB,CAC1B,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAElD;;;;;OAKG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,2BAA2B,GAAG,IAAI,CAAC;IAEzE;;;;;;;;;;;;;;;OAeG;IACH,YAAY,IAAI,IAAI,CAAC;IAErB;;;;;;OAMG;IACH,wBAAwB,IAAI,IAAI,CAAC;IAEjC;;;;;;;OAOG;IACH,eAAe,IAAI,MAAM,GAAG,IAAI,CAAC;IAEjC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@booleanmaths/booleanmaths-rn-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "React Native SDK for BooleanMaths — track user events and attribution in mobile apps.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -3,11 +3,18 @@ import NativeBooleanmathsRnSdk from './NativeBooleanmathsRnSdk';
|
|
|
3
3
|
import type { BooleanMathsApi, BooleanMathsEventProperties } from './types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* The BooleanMaths native SDK
|
|
7
|
-
* iOS
|
|
8
|
-
*
|
|
6
|
+
* The BooleanMaths native SDK ships for Android (`com.booleanmaths:bm-sdk`) and
|
|
7
|
+
* iOS (`BooleanMathsSDK`). Any other platform — including out-of-tree React
|
|
8
|
+
* Native targets — has no native artifact, so every call below short-circuits
|
|
9
|
+
* and the SDK behaves as a silent no-op rather than crashing the app.
|
|
10
|
+
*
|
|
11
|
+
* Note that `handleIntent` is a no-op on iOS even though iOS is supported here:
|
|
12
|
+
* intents are an Android concept. See its JSDoc in `./types`.
|
|
9
13
|
*/
|
|
10
|
-
const SUPPORTED_PLATFORMS: ReadonlyArray<typeof Platform.OS> = [
|
|
14
|
+
const SUPPORTED_PLATFORMS: ReadonlyArray<typeof Platform.OS> = [
|
|
15
|
+
'android',
|
|
16
|
+
'ios',
|
|
17
|
+
];
|
|
11
18
|
|
|
12
19
|
const isPlatformSupported = SUPPORTED_PLATFORMS.includes(Platform.OS);
|
|
13
20
|
|
|
@@ -30,7 +37,7 @@ function warnOnce() {
|
|
|
30
37
|
if (!isPlatformSupported) {
|
|
31
38
|
console.warn(
|
|
32
39
|
`[@booleanmaths/booleanmaths-rn-sdk] The BooleanMaths native SDK is not available on ${Platform.OS} ` +
|
|
33
|
-
'(Android
|
|
40
|
+
'(Android and iOS only). All SDK calls are no-ops on this platform and no ' +
|
|
34
41
|
'events will be tracked. Gate your calls on `BooleanMaths.isSupported` to ' +
|
|
35
42
|
'silence this warning — see the README\'s "Platform support" section.'
|
|
36
43
|
);
|
package/src/types.ts
CHANGED
|
@@ -40,10 +40,14 @@ export interface BooleanMathsApi {
|
|
|
40
40
|
* Forwards the current Activity's intent to the native SDK so ad deep links,
|
|
41
41
|
* app links and push-notification campaign data are attributed.
|
|
42
42
|
*
|
|
43
|
-
* This is the primary entry point for every kind of launch intent.
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
43
|
+
* This is the primary entry point for every kind of launch intent. Call it
|
|
44
|
+
* from your deep-link handler; `initialize` already forwards the launch
|
|
45
|
+
* intent itself (see the README for why that needs special handling).
|
|
46
|
+
*
|
|
47
|
+
* **Android only.** A no-op on iOS — not because iOS is unsupported (event
|
|
48
|
+
* tracking works fully there), but because intents are an Android concept and
|
|
49
|
+
* iOS deep links / universal links are out of scope for now. Safe to call
|
|
50
|
+
* unconditionally from shared code; on iOS it logs one dev-mode notice.
|
|
47
51
|
*
|
|
48
52
|
* Safe to call repeatedly — the native SDK de-duplicates intents it has
|
|
49
53
|
* already processed.
|
|
@@ -61,13 +65,18 @@ export interface BooleanMathsApi {
|
|
|
61
65
|
|
|
62
66
|
/**
|
|
63
67
|
* Returns the native SDK's hello message, or `null` when there is no native
|
|
64
|
-
* SDK on this platform.
|
|
68
|
+
* SDK on this platform.
|
|
69
|
+
*
|
|
70
|
+
* Useful as a bridge smoke test: the string comes from the native SDK itself
|
|
71
|
+
* on both Android and iOS, so a correct value also proves the native artifact
|
|
72
|
+
* actually linked.
|
|
65
73
|
*/
|
|
66
74
|
getHelloMessage(): string | null;
|
|
67
75
|
|
|
68
76
|
/**
|
|
69
|
-
* `true` only on platforms where a real BooleanMaths native SDK is linked
|
|
70
|
-
*
|
|
77
|
+
* `true` only on platforms where a real BooleanMaths native SDK is linked —
|
|
78
|
+
* Android and iOS. `false` on web, and on any platform where the native
|
|
79
|
+
* module failed to resolve (typically a JS install without a native rebuild).
|
|
71
80
|
*/
|
|
72
81
|
readonly isSupported: boolean;
|
|
73
82
|
}
|