diff --git a/INTEGRATION.md b/INTEGRATION.md index fae0427..42898fd 100644 --- a/INTEGRATION.md +++ b/INTEGRATION.md @@ -8,9 +8,9 @@ identically — see [`conformance/CONTRACT.md`](conformance/CONTRACT.md). --- -## Install — 0.5.0 beta (public, no auth) +## Install — 0.6.0 beta (public, no auth) -Distributed publicly from **[`3HL-SCORE/public-sdks-score`](https://git.3halves-labs.com/3HL-SCORE/public-sdks-score)** (#284) — **no Gitea token / login required**. The iOS XCFramework is a public **release asset** (`mobile-v0.5.0`) on that repo; the Android artifacts live in the org's **Gitea Maven package registry** (anonymous read). +Distributed publicly from **[`3HL-SCORE/public-sdks-score`](https://git.3halves-labs.com/3HL-SCORE/public-sdks-score)** (#284) — **no Gitea token / login required**. The iOS XCFramework is a public **release asset** (`mobile-v0.6.0`) on that repo; the Android artifacts live in the org's **Gitea Maven package registry** (anonymous read). ### Android — Gradle (public Maven registry) ```kotlin @@ -18,7 +18,7 @@ repositories { maven { url = uri("https://git.3halves-labs.com/api/packages/3HL-SCORE/maven") } // public — no credentials } dependencies { - implementation("com.threehalveslabs.scoretracker:shared-android:0.5.0") + implementation("com.threehalveslabs.scoretracker:shared-android:0.6.0") } ``` @@ -34,17 +34,17 @@ add it by **git URL** — no registry config, no login: ```swift // your app's Package.swift dependencies: [ - .package(url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score.git", from: "0.5.0") + .package(url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score.git", from: "0.6.0") ], // target: .product(name: "ScoreTracker", package: "public-sdks-score") ``` Or in Xcode: **File → Add Packages…** → paste the URL. The binary `ScoreTrackerKit` -target pulls the XCFramework from the **public** `mobile-v0.5.0` release asset (SPM +target pulls the XCFramework from the **public** `mobile-v0.6.0` release asset (SPM verifies the checksum) — no `~/.netrc` credentials needed. Verified with an anonymous `swift package resolve`. ### iOS — direct XCFramework -Download `ScoreTracker-pod.zip` from the **mobile-v0.5.0** release on +Download `ScoreTracker-pod.zip` from the **mobile-v0.6.0** release on [`public-sdks-score`](https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases). It holds `ScoreTrackerKit.xcframework` and the Swift facade sources (`Sources/ScoreTracker/`: `ScoreClient.swift`, `Exports.swift`, `AppLifecycle.swift`). @@ -155,6 +155,39 @@ event, pass it yourself: `requires: [.advertising]` on iOS (or the `trackAdvertising(...)` shorthand), `requires = listOf(ConsentCategory.ADVERTISING)` on Android. +## Regional privacy policy (GDPR, Quebec, LGPD, CPRA) + +One `privacy` option sets the tracker's posture for the fan's region (#489), +with the same policies and values as the web tracker's `privacy` option. For URC, +which is UK/EU-facing, use **GDPR**: + +```swift +// iOS +let score = ScoreClient(publishableKey: pk, siteId: "urc-ios", endpoint: endpoint, + privacy: PrivacyOptions(mode: .gdpr, region: nil, regionProvider: nil, overrides: nil)) +``` +```kotlin +// Android +val score = newScoreTracker(context, TrackerConfig(pk, "urc-android", endpoint, + privacy = PrivacyOptions(PrivacyMode.GDPR))) +``` + +| Policy | Starting consent | Queue kept at most | Drops `locale` / `device` | +|---|---|---|---| +| `GDPR` (EU, EEA, UK, CH) | nothing granted (opt-in) | 24 h | yes | +| `QUEBEC` (Law 25) | nothing granted | 24 h | yes | +| `LGPD` (Brazil) | nothing granted | 48 h | yes | +| `CPRA` (US) | analytics + personalization; not advertising | 168 h (the tracker's 72 h still applies) | no | +| `OFF` | no policy: as without the option | 72 h | no | + +What the policy changes: +- **Starting consent:** applies only when you pass no `initialConsent`, and only until your first `setConsent`. A value you pass from your CMP always wins. Under GDPR nothing is sent until `setConsent`, as before. +- **Retention:** queued events older than the cap are dropped instead of sent, including events saved before a cold start. +- **Fingerprint-adjacent signals:** `locale` and the device model leave the envelope. `os` and `appVersion` stay. +- **Declared only:** "no session replay" and "no geo enrichment" are reported by `inspect()`, but the SDK does neither anyway. + +`AUTO` picks the policy from `region` (ISO country, optionally with a subdivision: `GB`, `US-CA`, `CA-QC`) or a `regionProvider`; with neither, it uses GDPR, the strictest. The device locale is never used: it's a language setting, not a location. Resolve the region before creating the tracker; the policy is fixed for its lifetime. To tune a setting without forking the table, pass `overrides`, e.g. `PrivacyOverrides(retentionMaxHours = 12)`. `inspectJson()` shows the active policy under `privacy`. + ## PII scrubbing Same options as the web tracker's `pii` (#482). Scrubbing runs **when you call diff --git a/Package.swift b/Package.swift index 5aedf88..7266ae2 100644 --- a/Package.swift +++ b/Package.swift @@ -15,8 +15,8 @@ let package = Package( targets: [ .binaryTarget( name: "ScoreTrackerKit", - url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases/download/mobile-v0.5.0/ScoreTrackerKit.xcframework.zip", - checksum: "6943d712e2dcb5066f114e2fd14749fffebe79bab27a6ece3d1757b508f04d25" + url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases/download/mobile-v0.6.0/ScoreTrackerKit.xcframework.zip", + checksum: "dbf9bd9eec9e0c01cb28d7527e19e15909ddda95cf5fb48e50a1639e18ef1988" ), .target( name: "ScoreTracker", diff --git a/README.md b/README.md index b4d6340..1f0a9bf 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,13 @@ Public, auth-free distribution of the **Score mobile tracker** SDKs for iOS and > This repo hosts the **consumable artifacts** (release assets + package manifests). The SDK source lives in 3 Halves Labs' private platform repo. -## Install — 0.5.0 (no token / login required) +## Install — 0.6.0 (no token / login required) ### iOS — Swift Package Manager Add this repo by git URL. There's no registry to configure and no login. ```swift // Package.swift -dependencies: [ .package(url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score.git", from: "0.5.0") ] +dependencies: [ .package(url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score.git", from: "0.6.0") ] // target: .product(name: "ScoreTracker", package: "public-sdks-score") ``` Or in Xcode: **File → Add Packages…** and paste the URL. (The old Swift package @@ -29,7 +29,7 @@ pod 'ScoreTracker', ``` ### iOS — direct XCFramework -Download `ScoreTracker-pod.zip` from the [`mobile-v0.5.0` release](https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases). It contains `ScoreTrackerKit.xcframework` plus the Swift facade sources (`Sources/ScoreTracker/`). Drag the framework into Xcode and add the Swift files to your app target. +Download `ScoreTracker-pod.zip` from the [`mobile-v0.6.0` release](https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases). It contains `ScoreTrackerKit.xcframework` plus the Swift facade sources (`Sources/ScoreTracker/`). Drag the framework into Xcode and add the Swift files to your app target. ### Android — Gradle ```kotlin @@ -37,7 +37,7 @@ repositories { maven { url = uri("https://git.3halves-labs.com/api/packages/3HL-SCORE/maven") } // public — no credentials } dependencies { - implementation("com.threehalveslabs.scoretracker:shared-android:0.5.0") + implementation("com.threehalveslabs.scoretracker:shared-android:0.6.0") } ``` diff --git a/ScoreTracker.podspec b/ScoreTracker.podspec index 468b388..3385cef 100644 --- a/ScoreTracker.podspec +++ b/ScoreTracker.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'ScoreTracker' - s.version = '0.5.0' + s.version = '0.6.0' s.summary = 'Score mobile tracker (iOS) — KMP shared core + Swift facade.' s.description = <<-DESC Lightweight app analytics / fan-engagement tracker. Emits the same event diff --git a/Sources/ScoreTracker/Exports.swift b/Sources/ScoreTracker/Exports.swift index d626938..1558390 100644 --- a/Sources/ScoreTracker/Exports.swift +++ b/Sources/ScoreTracker/Exports.swift @@ -20,3 +20,8 @@ public typealias PiiAction = ScoreTrackerKit.PiiAction /// The support snapshot returned by `ScoreClient.inspect()` (#490); its nested /// types are reached through it (`snapshot.identity.hasToken`). public typealias InspectSnapshot = ScoreTrackerKit.InspectSnapshot +/// Regional privacy policy (#489): pass `PrivacyOptions(mode: .gdpr, …)` as +/// `ScoreClient(privacy:)`. +public typealias PrivacyOptions = ScoreTrackerKit.PrivacyOptions +public typealias PrivacyMode = ScoreTrackerKit.PrivacyMode +public typealias PrivacyOverrides = ScoreTrackerKit.PrivacyOverrides diff --git a/Sources/ScoreTracker/ScoreClient.swift b/Sources/ScoreTracker/ScoreClient.swift index 46e017d..ba769a2 100644 --- a/Sources/ScoreTracker/ScoreClient.swift +++ b/Sources/ScoreTracker/ScoreClient.swift @@ -28,7 +28,8 @@ public final class ScoreClient { os: String? = nil, device: String? = nil, locale: String? = nil, - initialConsent: ConsentState = ConsentState.companion.NONE, + initialConsent: ConsentState? = nil, + privacy: PrivacyOptions? = nil, pii: PiiOptions? = nil, tokenRefreshTimeoutSeconds: Double = 5, identifyReplayBufferSize: Int = 100 @@ -37,7 +38,8 @@ public final class ScoreClient { publishableKey: publishableKey, siteId: siteId, endpoint: endpoint, - device: DeviceDescriptor(os: os, device: device, appVersion: appVersion, locale: locale) + device: DeviceDescriptor(os: os, device: device, appVersion: appVersion, locale: locale), + privacy: privacy ) tracker = IosPlatformKt.doNewScoreTracker( config: config,