Publish Score iOS SDK 0.2.0

This commit is contained in:
bdot
2026-10-02 14:28:42 -04:00
parent ca717e4656
commit 411afa70a2
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