1 Commits

Author SHA1 Message Date
bdot
411afa70a2 Publish Score iOS SDK 0.2.0 2026-10-02 14:28:42 -04:00
5 changed files with 111 additions and 57 deletions

View File

@@ -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
artifacts live in **Gitea's Maven package registry**; the iOS XCFramework is a
**Gitea release asset** (`mobile-v0.1.0`).
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).
### Android — Gradle (Gitea Maven registry)
### Android — Gradle (public Maven registry)
```kotlin
repositories {
maven {
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") }
}
maven { url = uri("https://git.3halves-labs.com/api/packages/3HL-SCORE/maven") } // public — no credentials
}
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
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)
Published to Gitea's **Swift package registry** as `threehalveslabs.ScoreTracker`.
Configure the registry once (per machine / CI), then add it as a normal
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>
```
### iOS — Swift Package Manager (public git URL)
The SPM package lives at the **root** of the public `public-sdks-score` repo, so
add it by **git URL** — no registry config, no login:
```swift
// your app's Package.swift
dependencies: [ .package(id: "threehalveslabs.ScoreTracker", from: "0.1.0") ]
// then: .product(name: "ScoreTracker", package: "ScoreTracker")
dependencies: [
.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
`mobile-v0.1.0` release asset (SPM verifies the checksum). For a private release
asset, SPM reads credentials from `~/.netrc`.
> 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.
Or in Xcode: **File → Add Packages…** → paste the URL. The binary `ScoreTrackerKit`
target pulls the XCFramework from the **public** `mobile-v0.2.0` release asset (SPM
verifies the checksum) — no `~/.netrc` credentials needed. Verified with an
anonymous `swift package resolve`.
### iOS — direct XCFramework
Download `ScoreTrackerKit.xcframework.zip` from the **mobile-v0.1.0** release and
drag the `.xcframework` into your Xcode project; add `ScoreClient.swift`.
Download `ScoreTrackerKit.xcframework.zip` from the **mobile-v0.2.0** release on
[`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_…",
siteId: "urc-ios",
endpoint: "https://<middleware-host>",
sdkVersion: "0.1.0",
sdkVersion: "0.2.0",
appVersion: Bundle.main.shortVersion,
os: "iOS \(UIDevice.current.systemVersion)",
device: UIDevice.current.model,
@@ -106,7 +94,7 @@ val score = newScoreTracker(
publishableKey = "pk_live_…",
siteId = "urc-android",
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,
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
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)
Mirrors the web tracker (#109): supply a token provider — it's consulted before

View File

@@ -1,10 +1,11 @@
// swift-tools-version:5.9
import PackageDescription
// Public SPM package for the Score iOS SDK. `ScoreTracker` (Swift facade,
// ScoreClient) wraps the binary `ScoreTrackerKit` XCFramework, hosted as a
// public release asset on this repo. Consume via git URL:
// .package(url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score.git", from: "0.1.0")
// SPM package for the iOS SDK (#178/#188). The `ScoreTracker` Swift facade
// (ScoreClient) wraps the binary `ScoreTrackerKit` XCFramework, hosted as a
// **public** Gitea release asset on `3HL-SCORE/public-sdks-score` (#284).
// Build/refresh via `scripts/release.sh` (rebuild the XCFramework, re-zip,
// recompute the checksum, re-upload to the public release).
let package = Package(
name: "ScoreTracker",
platforms: [.iOS(.v14)],
@@ -14,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.1.0/ScoreTrackerKit.xcframework.zip",
checksum: "ae4b4c9b2a7e386d58c1c1144d15c3b4e5f457099ac2677e7d22894a7e4ab3e5"
url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases/download/mobile-v0.2.0/ScoreTrackerKit.xcframework.zip",
checksum: "328f8e36fc0c71d5b82bd4cc79d3d12b4520dea2db2358c73922348d83144b47"
),
.target(
name: "ScoreTracker",

View File

@@ -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)
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
// Package.swift
dependencies: [ .package(url: "https://git.3halves-labs.com/3HL-SCORE/public-sdks-score.git", from: "0.1.0") ]
// target: .product(name: "ScoreTracker", package: "public-sdks-score")
dependencies: [ .package(id: "threehalveslabs.ScoreTracker", from: "0.2.0") ]
// target: .product(name: "ScoreTracker", package: "ScoreTracker")
```
### iOS — CocoaPods
@@ -18,16 +28,22 @@ pod 'ScoreTracker',
```
### 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
```kotlin
repositories { maven { url = uri("https://git.3halves-labs.com/api/packages/3HL-SCORE/maven") } } // public
dependencies { implementation("com.threehalveslabs.scoretracker:shared-android:0.1.0") }
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.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>`.

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
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.description = <<-DESC
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.swift_version = '5.9'
# Release attaches the zipped XCFramework; point :http at that asset.
s.source = { :http => 'https://git.3halves-labs.com/3HL-SCORE/public-sdks-score/releases/download/mobile-v0.1.0/ScoreTrackerKit.xcframework.zip' }
# 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.2.0/ScoreTrackerKit.xcframework.zip' }
s.vendored_frameworks = 'ScoreTrackerKit.xcframework'
s.source_files = 'Sources/ScoreTracker/**/*.swift'

View File

@@ -13,6 +13,7 @@ public final class ScoreClient {
/// - Parameters:
/// - endpoint: middleware base URL; events POST to `<endpoint>/api/tracking/website`.
/// - initialConsent: defaults to "none" — nothing fires until `setConsent(...)`.
/// - pii: field-level PII handling (#482), scrubbed before events are queued on the device.
public init(
publishableKey: String,
siteId: String,
@@ -22,7 +23,8 @@ public final class ScoreClient {
os: String? = nil,
device: String? = nil,
locale: String? = nil,
initialConsent: ConsentState = ConsentState.companion.NONE
initialConsent: ConsentState = ConsentState.companion.NONE,
pii: PiiOptions? = nil
) {
let config = TrackerConfig(
publishableKey: publishableKey,
@@ -31,7 +33,7 @@ public final class ScoreClient {
sdk: SdkInfo(name: "@3halves-labs/score-tracker-ios", version: sdkVersion),
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)