Compare commits
1 Commits
mobile-v0.
...
mobile-v0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
411afa70a2 |
105
INTEGRATION.md
105
INTEGRATION.md
@@ -8,57 +8,45 @@ identically — see [`conformance/CONTRACT.md`](conformance/CONTRACT.md).
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Install — 0.1.0 beta (hosted on Gitea)
|
## Install — 0.2.0 beta (public, no auth)
|
||||||
|
|
||||||
Everything is hosted on the org's Gitea — no external registry. The Android
|
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.2.0`) on that repo; the Android artifacts live in the org's **Gitea Maven package registry** (anonymous read).
|
||||||
artifacts live in **Gitea's Maven package registry**; the iOS XCFramework is a
|
|
||||||
**Gitea release asset** (`mobile-v0.1.0`).
|
|
||||||
|
|
||||||
### Android — Gradle (Gitea Maven registry)
|
### Android — Gradle (public Maven registry)
|
||||||
```kotlin
|
```kotlin
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven { url = uri("https://git.3halves-labs.com/api/packages/3HL-SCORE/maven") } // public — no credentials
|
||||||
url = uri("https://git.3halves-labs.com/api/packages/3HL-SCORE/maven")
|
|
||||||
// If the package registry isn't public, add a Gitea token:
|
|
||||||
// credentials(HttpHeaderCredentials::class) { name = "Authorization"; value = "token ${'$'}giteaToken" }
|
|
||||||
// authentication { create<HttpHeaderAuthentication>("header") }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("com.threehalveslabs.scoretracker:shared-android:0.1.0")
|
implementation("com.threehalveslabs.scoretracker:shared-android:0.2.0")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### iOS — CocoaPods (release asset)
|
### iOS — CocoaPods (public release asset)
|
||||||
```ruby
|
```ruby
|
||||||
pod 'ScoreTracker',
|
pod 'ScoreTracker',
|
||||||
:podspec => 'https://git.3halves-labs.com/3HL-SCORE/score-anything-loyalty/raw/branch/main/mobile/ios/ScoreTracker/ScoreTracker.podspec'
|
:podspec => 'https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/raw/branch/main/ScoreTracker.podspec'
|
||||||
```
|
```
|
||||||
|
|
||||||
### iOS — Swift Package Manager (Gitea Swift registry)
|
### iOS — Swift Package Manager (public git URL)
|
||||||
Published to Gitea's **Swift package registry** as `threehalveslabs.ScoreTracker`.
|
The SPM package lives at the **root** of the public `public-sdks-score` repo, so
|
||||||
Configure the registry once (per machine / CI), then add it as a normal
|
add it by **git URL** — no registry config, no login:
|
||||||
dependency by **id** — no git URL needed:
|
|
||||||
```bash
|
|
||||||
swift package-registry set https://git.3halves-labs.com/api/packages/3HL-SCORE/swift
|
|
||||||
# private registry → log in with a Gitea token:
|
|
||||||
swift package-registry login https://git.3halves-labs.com/api/packages/3HL-SCORE/swift --token <gitea-token>
|
|
||||||
```
|
|
||||||
```swift
|
```swift
|
||||||
// your app's Package.swift
|
// your app's Package.swift
|
||||||
dependencies: [ .package(id: "threehalveslabs.ScoreTracker", from: "0.1.0") ]
|
dependencies: [
|
||||||
// then: .product(name: "ScoreTracker", package: "ScoreTracker")
|
.package(url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score.git", from: "0.2.0")
|
||||||
|
],
|
||||||
|
// target: .product(name: "ScoreTracker", package: "public-sdks-score")
|
||||||
```
|
```
|
||||||
The package's binary `ScoreTrackerKit` target pulls the XCFramework from the
|
Or in Xcode: **File → Add Packages…** → paste the URL. The binary `ScoreTrackerKit`
|
||||||
`mobile-v0.1.0` release asset (SPM verifies the checksum). For a private release
|
target pulls the XCFramework from the **public** `mobile-v0.2.0` release asset (SPM
|
||||||
asset, SPM reads credentials from `~/.netrc`.
|
verifies the checksum) — no `~/.netrc` credentials needed. Verified with an
|
||||||
|
anonymous `swift package resolve`.
|
||||||
> Note: SPM-by-git-URL isn't available (the package lives in a monorepo subdir,
|
|
||||||
> which SPM can't resolve) — the Swift registry above is the supported path.
|
|
||||||
|
|
||||||
### iOS — direct XCFramework
|
### iOS — direct XCFramework
|
||||||
Download `ScoreTrackerKit.xcframework.zip` from the **mobile-v0.1.0** release and
|
Download `ScoreTrackerKit.xcframework.zip` from the **mobile-v0.2.0** release on
|
||||||
drag the `.xcframework` into your Xcode project; add `ScoreClient.swift`.
|
[`public-sdks-score`](https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases)
|
||||||
|
and drag the `.xcframework` into your Xcode project; add `ScoreClient.swift`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -71,7 +59,7 @@ let score = ScoreClient(
|
|||||||
publishableKey: "pk_live_…",
|
publishableKey: "pk_live_…",
|
||||||
siteId: "urc-ios",
|
siteId: "urc-ios",
|
||||||
endpoint: "https://<middleware-host>",
|
endpoint: "https://<middleware-host>",
|
||||||
sdkVersion: "0.1.0",
|
sdkVersion: "0.2.0",
|
||||||
appVersion: Bundle.main.shortVersion,
|
appVersion: Bundle.main.shortVersion,
|
||||||
os: "iOS \(UIDevice.current.systemVersion)",
|
os: "iOS \(UIDevice.current.systemVersion)",
|
||||||
device: UIDevice.current.model,
|
device: UIDevice.current.model,
|
||||||
@@ -106,7 +94,7 @@ val score = newScoreTracker(
|
|||||||
publishableKey = "pk_live_…",
|
publishableKey = "pk_live_…",
|
||||||
siteId = "urc-android",
|
siteId = "urc-android",
|
||||||
endpoint = "https://<middleware-host>",
|
endpoint = "https://<middleware-host>",
|
||||||
sdk = SdkInfo("@3halves-labs/score-tracker-android", "0.1.0"),
|
sdk = SdkInfo("@3halves-labs/score-tracker-android", "0.2.0"),
|
||||||
device = DeviceDescriptor(os = "Android ${Build.VERSION.RELEASE}", device = Build.MODEL,
|
device = DeviceDescriptor(os = "Android ${Build.VERSION.RELEASE}", device = Build.MODEL,
|
||||||
appVersion = BuildConfig.VERSION_NAME, locale = Locale.getDefault().toLanguageTag()),
|
appVersion = BuildConfig.VERSION_NAME, locale = Locale.getDefault().toLanguageTag()),
|
||||||
),
|
),
|
||||||
@@ -152,6 +140,53 @@ Events declaring a category (e.g. `trackAdvertising(...)` on iOS, or
|
|||||||
`requires = listOf(ConsentCategory.ADVERTISING)` on Android) are dropped until
|
`requires = listOf(ConsentCategory.ADVERTISING)` on Android) are dropped until
|
||||||
that category is granted.
|
that category is granted.
|
||||||
|
|
||||||
|
## PII scrubbing
|
||||||
|
|
||||||
|
Same options as the web tracker's `pii` (#482). Scrubbing runs **when you call
|
||||||
|
`track()`, before the event is queued**, so a raw value never reaches the
|
||||||
|
on-device queue (NSUserDefaults / SharedPreferences) or the network.
|
||||||
|
|
||||||
|
- **Denylist:** remove matching keys.
|
||||||
|
- **Classify:** a per-key action. The first rule for a key wins.
|
||||||
|
- `DROP`: remove the key.
|
||||||
|
- `REDACT`: replace the value with `"<redacted>"`.
|
||||||
|
- `TOKENIZE`: replace it with `t:1`, `t:2`, …, stable for the tracker's lifetime.
|
||||||
|
- `HASH`: `h:` plus FNV-1a 32-bit hex. It's identical to the web tracker, so
|
||||||
|
the same value hashes the same on both platforms. **Not** cryptographic.
|
||||||
|
|
||||||
|
Keys match exactly (case-sensitive) at any depth, including inside lists.
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
// Android
|
||||||
|
val score = newScoreTracker(
|
||||||
|
context, config,
|
||||||
|
pii = PiiOptions.Classify(listOf(
|
||||||
|
PiiRule("email", PiiAction.HASH), // joinable across web + app
|
||||||
|
PiiRule("phone", PiiAction.REDACT),
|
||||||
|
PiiRule("memberNumber", PiiAction.TOKENIZE),
|
||||||
|
PiiRule("dateOfBirth", PiiAction.DROP),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
score.track("profile_updated", mapOf("email" to "fan@example.com", "favouriteTeam" to "home-club"))
|
||||||
|
// queued and sent as {"email":"h:141e28bb","favouriteTeam":"home-club"}
|
||||||
|
```
|
||||||
|
```swift
|
||||||
|
// iOS
|
||||||
|
let score = ScoreClient(
|
||||||
|
publishableKey: "pk_…", siteId: "app.example.com-1a2b3c",
|
||||||
|
endpoint: "https://api.example.com", sdkVersion: "0.2.0",
|
||||||
|
pii: PiiOptions.Classify(rules: [
|
||||||
|
PiiRule(field: "email", action: .hash),
|
||||||
|
PiiRule(field: "phone", action: .redact),
|
||||||
|
PiiRule(field: "memberNumber", action: .tokenize),
|
||||||
|
PiiRule(field: "dateOfBirth", action: .drop),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
To remove keys without per-field actions, use
|
||||||
|
`PiiOptions.Denylist(listOf("email", "phone"))`.
|
||||||
|
|
||||||
## Auth0 (JWT)
|
## Auth0 (JWT)
|
||||||
|
|
||||||
Mirrors the web tracker (#109): supply a token provider — it's consulted before
|
Mirrors the web tracker (#109): supply a token provider — it's consulted before
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
// swift-tools-version:5.9
|
// swift-tools-version:5.9
|
||||||
import PackageDescription
|
import PackageDescription
|
||||||
|
|
||||||
// Public SPM package for the Score iOS SDK. `ScoreTracker` (Swift facade,
|
// SPM package for the iOS SDK (#178/#188). The `ScoreTracker` Swift facade
|
||||||
// ScoreClient) wraps the binary `ScoreTrackerKit` XCFramework, hosted as a
|
// (ScoreClient) wraps the binary `ScoreTrackerKit` XCFramework, hosted as a
|
||||||
// public release asset on this repo. Consume via git URL:
|
// **public** Gitea release asset on `3HL-SCORE/public-sdks-score` (#284).
|
||||||
// .package(url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score.git", from: "0.1.0")
|
// Build/refresh via `scripts/release.sh` (rebuild the XCFramework, re-zip,
|
||||||
|
// recompute the checksum, re-upload to the public release).
|
||||||
let package = Package(
|
let package = Package(
|
||||||
name: "ScoreTracker",
|
name: "ScoreTracker",
|
||||||
platforms: [.iOS(.v14)],
|
platforms: [.iOS(.v14)],
|
||||||
@@ -14,8 +15,8 @@ let package = Package(
|
|||||||
targets: [
|
targets: [
|
||||||
.binaryTarget(
|
.binaryTarget(
|
||||||
name: "ScoreTrackerKit",
|
name: "ScoreTrackerKit",
|
||||||
url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases/download/mobile-v0.1.0/ScoreTrackerKit.xcframework.zip",
|
url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases/download/mobile-v0.2.0/ScoreTrackerKit.xcframework.zip",
|
||||||
checksum: "ae4b4c9b2a7e386d58c1c1144d15c3b4e5f457099ac2677e7d22894a7e4ab3e5"
|
checksum: "328f8e36fc0c71d5b82bd4cc79d3d12b4520dea2db2358c73922348d83144b47"
|
||||||
),
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "ScoreTracker",
|
name: "ScoreTracker",
|
||||||
|
|||||||
38
README.md
38
README.md
@@ -1,14 +1,24 @@
|
|||||||
|
<!--
|
||||||
|
Seed README for the PUBLIC distribution repo `3HL-SCORE/public-sdks-score` (#284).
|
||||||
|
Copy this to that repo's root as README.md when publishing. Source of truth for
|
||||||
|
the SDK lives in the private score-anything-loyalty repo under `mobile/`.
|
||||||
|
-->
|
||||||
# Score mobile SDKs (public distribution)
|
# Score mobile SDKs (public distribution)
|
||||||
|
|
||||||
Public, auth-free distribution of the **Score mobile tracker** SDKs for iOS and Android — the mobile counterpart of the web `@3halves-labs/score-tracker`.
|
Public, auth-free distribution of the **Score mobile tracker** SDKs for iOS and Android — the mobile counterpart of the web `@3halves-labs/score-tracker`. Lightweight app analytics / fan-engagement tracking with a durable offline queue, consent gating, and Auth0 JWT support.
|
||||||
|
|
||||||
## Install — 0.1.0 (no token / login required)
|
> This repo hosts the **consumable artifacts** (release assets + package manifests). The SDK source lives in 3 Halves Labs' private platform repo.
|
||||||
|
|
||||||
### iOS — Swift Package Manager (git URL)
|
## Install — 0.2.0 (no token / login required)
|
||||||
|
|
||||||
|
### iOS — Swift Package Manager
|
||||||
|
```bash
|
||||||
|
swift package-registry set https://git.3halves-labs.com/api/packages/3HL-SCORE/swift
|
||||||
|
```
|
||||||
```swift
|
```swift
|
||||||
// Package.swift
|
// Package.swift
|
||||||
dependencies: [ .package(url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score.git", from: "0.1.0") ]
|
dependencies: [ .package(id: "threehalveslabs.ScoreTracker", from: "0.2.0") ]
|
||||||
// target: .product(name: "ScoreTracker", package: "public-sdks-score")
|
// target: .product(name: "ScoreTracker", package: "ScoreTracker")
|
||||||
```
|
```
|
||||||
|
|
||||||
### iOS — CocoaPods
|
### iOS — CocoaPods
|
||||||
@@ -18,16 +28,22 @@ pod 'ScoreTracker',
|
|||||||
```
|
```
|
||||||
|
|
||||||
### iOS — direct XCFramework
|
### iOS — direct XCFramework
|
||||||
Download `ScoreTrackerKit.xcframework.zip` from the [`mobile-v0.1.0` release](https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases) and drag it into Xcode.
|
Download `ScoreTrackerKit.xcframework.zip` from the [`mobile-v0.2.0` release](https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases) and drag it into Xcode.
|
||||||
|
|
||||||
### Android — Gradle
|
### Android — Gradle
|
||||||
```kotlin
|
```kotlin
|
||||||
repositories { maven { url = uri("https://git.3halves-labs.com/api/packages/3HL-SCORE/maven") } } // public
|
repositories {
|
||||||
dependencies { implementation("com.threehalveslabs.scoretracker:shared-android:0.1.0") }
|
maven { url = uri("https://git.3halves-labs.com/api/packages/3HL-SCORE/maven") } // public — no credentials
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
implementation("com.threehalveslabs.scoretracker:shared-android:0.2.0")
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Docs
|
## Quickstart & API
|
||||||
|
|
||||||
Full integration guide (init, consent, Auth0, offline/flush, event catalogue): **[`INTEGRATION.md`](INTEGRATION.md)**.
|
See the full integration guide (init, consent, Auth0, offline/flush, event catalogue): **`INTEGRATION.md`** in this repo (published alongside each release).
|
||||||
|
|
||||||
SDK source lives in 3 Halves Labs' platform repo; this repo hosts the consumable artifacts. Versions tagged `0.1.0` (SPM) / `mobile-v0.1.0` (release asset).
|
## Support
|
||||||
|
|
||||||
|
Issues / integration questions: contact 3 Halves Labs. Versions are tagged `mobile-v<version>`.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = 'ScoreTracker'
|
s.name = 'ScoreTracker'
|
||||||
s.version = '0.1.0'
|
s.version = '0.2.0'
|
||||||
s.summary = 'Score mobile tracker (iOS) — KMP shared core + Swift facade.'
|
s.summary = 'Score mobile tracker (iOS) — KMP shared core + Swift facade.'
|
||||||
s.description = <<-DESC
|
s.description = <<-DESC
|
||||||
Lightweight app analytics / fan-engagement tracker. Emits the same event
|
Lightweight app analytics / fan-engagement tracker. Emits the same event
|
||||||
@@ -13,8 +13,8 @@ Pod::Spec.new do |s|
|
|||||||
s.platform = :ios, '14.0'
|
s.platform = :ios, '14.0'
|
||||||
s.swift_version = '5.9'
|
s.swift_version = '5.9'
|
||||||
|
|
||||||
# Release attaches the zipped XCFramework; point :http at that asset.
|
# Release attaches the zipped XCFramework as a PUBLIC asset on public-sdks-score (#284).
|
||||||
s.source = { :http => 'https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases/download/mobile-v0.1.0/ScoreTrackerKit.xcframework.zip' }
|
s.source = { :http => 'https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases/download/mobile-v0.2.0/ScoreTrackerKit.xcframework.zip' }
|
||||||
|
|
||||||
s.vendored_frameworks = 'ScoreTrackerKit.xcframework'
|
s.vendored_frameworks = 'ScoreTrackerKit.xcframework'
|
||||||
s.source_files = 'Sources/ScoreTracker/**/*.swift'
|
s.source_files = 'Sources/ScoreTracker/**/*.swift'
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ public final class ScoreClient {
|
|||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - endpoint: middleware base URL; events POST to `<endpoint>/api/tracking/website`.
|
/// - endpoint: middleware base URL; events POST to `<endpoint>/api/tracking/website`.
|
||||||
/// - initialConsent: defaults to "none" — nothing fires until `setConsent(...)`.
|
/// - initialConsent: defaults to "none" — nothing fires until `setConsent(...)`.
|
||||||
|
/// - pii: field-level PII handling (#482), scrubbed before events are queued on the device.
|
||||||
public init(
|
public init(
|
||||||
publishableKey: String,
|
publishableKey: String,
|
||||||
siteId: String,
|
siteId: String,
|
||||||
@@ -22,7 +23,8 @@ public final class ScoreClient {
|
|||||||
os: String? = nil,
|
os: String? = nil,
|
||||||
device: String? = nil,
|
device: String? = nil,
|
||||||
locale: String? = nil,
|
locale: String? = nil,
|
||||||
initialConsent: ConsentState = ConsentState.companion.NONE
|
initialConsent: ConsentState = ConsentState.companion.NONE,
|
||||||
|
pii: PiiOptions? = nil
|
||||||
) {
|
) {
|
||||||
let config = TrackerConfig(
|
let config = TrackerConfig(
|
||||||
publishableKey: publishableKey,
|
publishableKey: publishableKey,
|
||||||
@@ -31,7 +33,7 @@ public final class ScoreClient {
|
|||||||
sdk: SdkInfo(name: "@3halves-labs/score-tracker-ios", version: sdkVersion),
|
sdk: SdkInfo(name: "@3halves-labs/score-tracker-ios", version: sdkVersion),
|
||||||
device: DeviceDescriptor(os: os, device: device, appVersion: appVersion, locale: locale)
|
device: DeviceDescriptor(os: os, device: device, appVersion: appVersion, locale: locale)
|
||||||
)
|
)
|
||||||
tracker = IosPlatformKt.doNewScoreTracker(config: config, initialConsent: initialConsent)
|
tracker = IosPlatformKt.doNewScoreTracker(config: config, initialConsent: initialConsent, pii: pii)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Consent (wire to your CMP / OneTrust)
|
// MARK: - Consent (wire to your CMP / OneTrust)
|
||||||
|
|||||||
Reference in New Issue
Block a user