add sdk distribution specs (#1881)

This commit is contained in:
Seshanth.S
2026-03-30 12:48:23 +05:30
committed by GitHub
parent b433fe1b85
commit a1e07d2a60
8 changed files with 680 additions and 7 deletions

View File

@@ -18,6 +18,7 @@ Status: Active (WebView-first, current pass is mock-first UI migration)
| SDK Core | [SDK Core Spec](./workstreams/sdk-core/SPEC.md) | Browser-portable engine |
| Native Shells (Lite) | [Native Shells Lite Spec](./workstreams/native-shells-lite/SPEC.md) | Future Kotlin + Swift shell follow-up |
| Build Pipeline | [Build Pipeline Spec](./workstreams/build-pipeline/SPEC.md) | Bundle webview-app into native shells |
| SDK Distribution | [SDK Distribution Spec](./workstreams/sdk-distribution/SPEC.md) | Hosted URL loading + native shell publishing |
## Paused Workstreams

View File

@@ -49,15 +49,16 @@ Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done`
### BP-02 Context (Deferred)
When the SDK moves to CDN-hosted bundles in production, runtime integrity verification becomes a security boundary. Scope:
The SDK Distribution workstream ([SDK Distribution Spec](../sdk-distribution/SPEC.md)) supersedes the CDN bundle approach with hosted URL loading. Native shells will load `https://verify.self.xyz/v1/` directly instead of downloading and verifying CDN bundles.
- Build step: generate a signed manifest (SHA-256 checksums of all bundle files) during `build-webview-bundle.sh`
- Android: Kotlin runtime check — verify downloaded bundle against manifest before loading into WebView
- iOS: Swift runtime check — same verification before `WKWebView.loadFileURL`
- Fail closed: refuse to load on any mismatch (missing file, checksum diff, missing manifest)
- The existing Gradle `validateWebViewBundle` task remains a dev-time guard; this is the prod-time counterpart
With hosted URL loading:
- Runtime bundle integrity verification is no longer needed — the browser handles HTTPS/TLS verification
- The `validateWebViewBundle` Gradle task will be removed as part of SD-01
- The build script (`build-webview-bundle.sh`) remains useful for **local development only** — developers can bundle locally and use `devServerUrl` for offline work
Trigger: when remote/CDN bundle loading is implemented.
If a future requirement emerges for offline/bundled mode alongside hosted mode, BP-02 would be revisited. Until then, this item remains deferred.
Trigger: only if offline/bundled mode is required alongside hosted mode.
## Active Plans

View File

@@ -0,0 +1,110 @@
# SDK Distribution — Implementation Spec
> Last updated: 2026-03-30
> Owner: SDK / Platform
> Parent: `../../OVERVIEW.md`
> Status: Active
## Purpose
- You own the transition from embedded WebView bundles (~34MB) to hosted URL loading.
- Native shells will load `https://verify.self.xyz/v1/` instead of bundled assets, eliminating bundle size from the SDK.
- Done when both native shells load the hosted URL, the WebView app is deployed at the hosted URL, and native shells are published without bundled assets.
## Scope
- Config model changes: add `webAppUrl` to `SelfSdkConfig` on both platforms
- URL loading changes: replace asset loaders with hosted URL loading in both native shells
- Build cleanup: remove bundle validation tasks, asset copy resources, and `androidx.webkit` dependency
- Hosting: deploy webview-app at `https://verify.self.xyz/v1/`
- Publishing: Maven (Android) and SPM (iOS) distribution without bundled assets
## Out of Scope
- Bridge protocol changes (v1 unchanged)
- Bridge handler logic (owned by native-shells-lite workstream)
- React Native wrapper (separate follow-up)
- Debug mode changes (devServerUrl remains unchanged)
- CI/CD pipeline configuration
- WebView app source code changes (owned by WebView workstream)
## Invariants
- HTTPS-only in production. The hosted URL must be served over HTTPS with HSTS.
- Bridge protocol v1 is unchanged. Hosted loading does not change the message contract.
- Debug mode is unchanged. `devServerUrl` override continues to work for local development.
- `webAppUrl` has a default. If not set, defaults to `https://verify.self.xyz/v1/`.
- Auto-update model. The hosted page updates independently of SDK releases. `/v1/` path changes only for breaking changes.
## Dependencies
| Depends On | Type | Status | Notes |
| -------------------------------- | ---------- | ------ | ------------------------------------------------------- |
| Native Shells (Lite) — NSL-01 | Upstream | Active | Android shell must exist before switching URL loading |
| Native Shells (Lite) — NSL-02 | Upstream | Active | iOS shell must exist before switching URL loading |
| `packages/webview-app/` | Upstream | Active | Source of the hosted web app |
| Build Pipeline | Sibling | Active | Bundle script remains for local dev only after SD-03 |
## Ownership Boundaries
| Area | Owner | Notes |
| -------------------------------- | ---------------- | --------------------------------------------- |
| `packages/native-shell-android/` | SDK Distribution | Config + URL loading changes only |
| `packages/native-shell-ios/` | SDK Distribution | Config + URL loading changes only |
| `packages/webview-app/` | SDK Distribution | Hosting setup only (no source changes) |
| Bridge handlers | Native Shells | Not modified by this workstream |
## Backlog
| ID | Title | Status | Priority | Depends On | Plan | PR |
| ----- | ------------------------------ | ------ | -------- | ---------- | ---------------------------------------------------------------------------- | --- |
| SD-01 | Android hosted URL loading | Ready | High | NSL-01 | [plans/SD-01-android-hosted-url.md](./plans/SD-01-android-hosted-url.md) | — |
| SD-02 | iOS hosted URL loading | Ready | High | NSL-02 | [plans/SD-02-ios-hosted-url.md](./plans/SD-02-ios-hosted-url.md) | — |
| SD-03 | WebView app hosting setup | Ready | High | — | [plans/SD-03-hosting-setup.md](./plans/SD-03-hosting-setup.md) | — |
| SD-04 | Android Maven publishing | Ready | Medium | SD-01 | [plans/SD-04-android-maven-publishing.md](./plans/SD-04-android-maven-publishing.md) | — |
| SD-05 | iOS publishing (SPM + CocoaPods) | Ready | Medium | SD-02 | [plans/SD-05-ios-spm-publishing.md](./plans/SD-05-ios-spm-publishing.md) | — |
Allowed statuses: `Ready`, `In Progress`, `Blocked`, `Deferred`, `Done`
### Execution Order
1. **SD-03** first — hosting must be live before native shells can load it
2. **SD-01 + SD-02** in parallel — Android and iOS URL loading changes
3. **SD-04 + SD-05** in parallel — publishing cleanup after URL loading works
## Active Plans
| Plan | IDs | Status |
| ---------------------------------------------------------------------------- | ----- | ------ |
| [plans/SD-01-android-hosted-url.md](./plans/SD-01-android-hosted-url.md) | SD-01 | Ready |
| [plans/SD-02-ios-hosted-url.md](./plans/SD-02-ios-hosted-url.md) | SD-02 | Ready |
| [plans/SD-03-hosting-setup.md](./plans/SD-03-hosting-setup.md) | SD-03 | Ready |
| [plans/SD-04-android-maven-publishing.md](./plans/SD-04-android-maven-publishing.md) | SD-04 | Ready |
| [plans/SD-05-ios-spm-publishing.md](./plans/SD-05-ios-spm-publishing.md) | SD-05 | Ready |
## Completion Checklist
- [ ] Backlog reflects reality
- [ ] Active plan links are current
- [ ] Done items are marked done
- [ ] Cross-workstream dependencies updated
## Key Design Decisions
| Decision | Choice | Rationale |
| -------------------- | --------------------------------------- | --------------------------------------------------------------- |
| Hosting domain | `https://verify.self.xyz/v1/` | User-facing, version-namespaced, HTTPS-only |
| Versioning model | Auto-update (hosted page updates independently) | `/v1/` path changes only for breaking changes to bridge protocol |
| Config delivery | `webAppUrl` field with default | Simple, overridable, does not leak config into query params |
| Hosting | Internal infrastructure | SD-03 describes requirements only |
| Bundle script fate | Retained for local dev | Developers need `devServerUrl` alternative for offline work |
## Related Specs
| Spec | Relationship |
| ---------------------------------------------------------- | --------------------------------------------------------- |
| [SDK Overview](../../OVERVIEW.md) | Parent architecture |
| [Native Shells Lite](../native-shells-lite/SPEC.md) | Upstream — shells must exist before distribution changes |
| [Build Pipeline](../build-pipeline/SPEC.md) | Sibling — bundle script retained for local dev only |
| [WebView Spec](../webview/SPEC.md) | Upstream — produces the web app being hosted |
| [SDK Core Spec](../sdk-core/SPEC.md) | Sibling — engine consumed by hosted web app |

View File

@@ -0,0 +1,111 @@
## Android Hosted URL Loading
> Last updated: 2026-03-30
> Status: Ready
- Workstream: sdk-distribution
- Backlog IDs: SD-01
- Owner: TBD
- Branch: TBD
- PR: TBD
### Why
- The Android native shell currently loads the WebView bundle from local assets via `WebViewAssetLoader`, embedding ~34MB into the AAR.
- Switching to a hosted URL (`https://verify.self.xyz/v1/`) eliminates the bundle from the SDK artifact, dropping AAR size to <200KB.
- The SDK opens a hosted webpage instead of a bundled one — UI updates ship without requiring SDK version bumps.
### Scope
- Remove `WebViewAssetLoader` and load the hosted URL directly via `webView.loadUrl()`
- Add `webAppUrl` field to `SelfSdkConfig` with default `https://verify.self.xyz/v1/`
- Remove `validateWebViewBundle` Gradle task
- Remove `androidx.webkit` dependency (only needed for `WebViewAssetLoader`)
- Update `shouldOverrideUrlLoading` to allow the hosted domain (`verify.self.xyz`)
### Out of Scope
- Bridge handler changes (protocol is identical regardless of URL source)
- Debug mode / `devServerUrl` (already works independently of asset loading)
- Maven publishing (SD-04)
- iOS changes (SD-02)
- Hosting setup (SD-03)
- CI/CD configuration
### Files to Modify
- `packages/native-shell-android/src/main/kotlin/.../AndroidWebViewHost.kt` — Replace `WebViewAssetLoader` with `webView.loadUrl(config.webAppUrl)`. Remove asset loader setup. Update `shouldOverrideUrlLoading` to whitelist `verify.self.xyz`.
- `packages/native-shell-android/src/main/kotlin/.../SelfSdkConfig.kt` — Add `val webAppUrl: String = "https://verify.self.xyz/v1/"`.
- `packages/native-shell-android/src/main/kotlin/.../SelfSdk.kt` — Pass `webAppUrl` through to the Activity intent extras.
- `packages/native-shell-android/src/main/kotlin/.../SelfVerificationActivity.kt` — Read `webAppUrl` from intent extras. Pass to `AndroidWebViewHost`.
- `packages/native-shell-android/build.gradle.kts` — Remove `validateWebViewBundle` task. Remove `androidx.webkit:webkit` dependency.
### Files NOT to Modify
- `packages/native-shell-android/src/main/kotlin/.../MessageRouter.kt` — Bridge routing is unchanged
- `packages/native-shell-android/src/main/kotlin/.../SecureStorageHandler.kt` — Handler logic unchanged
- `packages/native-shell-android/src/main/kotlin/.../CryptoHandler.kt` — Handler logic unchanged
- `packages/native-shell-android/src/main/kotlin/.../LifecycleHandler.kt` — Handler logic unchanged
- `packages/webview-bridge/` — Upstream, do not change
- `packages/webview-app/` — Upstream, do not change
### Preconditions
- NSL-01 is complete (Android native shell exists)
- SD-03 is complete (hosted URL is live at `https://verify.self.xyz/v1/`)
### Implementation Details
1. **Remove `WebViewAssetLoader`** in `AndroidWebViewHost.kt`:
- Delete the `WebViewAssetLoader.Builder()` setup and the `PathHandler`
- Delete `shouldInterceptRequest` override that delegates to the asset loader
- Replace with `webView.loadUrl(webAppUrl)` where `webAppUrl` comes from config
2. **Update `shouldOverrideUrlLoading`**:
- Allow navigation to `verify.self.xyz` domain
- Continue blocking other external navigations
- Keep the existing `devServerUrl` allowlisting for debug mode
3. **Add `webAppUrl` to config**:
- In `SelfSdkConfig.kt`: `val webAppUrl: String = "https://verify.self.xyz/v1/"`
- The default means existing integrators get hosted loading without config changes
- Config params (`teeUrl`, `verificationId`, `userId`) continue to be appended as URL query params
4. **Remove Gradle bundle validation**:
- Delete the `validateWebViewBundle` task from `build.gradle.kts`
- Delete the `src/main/assets/self-wallet/` directory reference (no longer needed)
- Remove `androidx.webkit:webkit` from dependencies
5. **Thread config through**:
- `SelfSdk.launch()` → Intent extras → `SelfVerificationActivity``AndroidWebViewHost`
- `webAppUrl` follows the same path as existing config fields
### Validation
```bash
# Build must succeed without assets/self-wallet/ directory
cd packages/native-shell-android && ./gradlew assembleDebug
# Verify no reference to WebViewAssetLoader
grep -r "WebViewAssetLoader" packages/native-shell-android/src/ && echo "FAIL: WebViewAssetLoader still referenced" || echo "PASS"
# Verify no androidx.webkit dependency
grep "androidx.webkit" packages/native-shell-android/build.gradle.kts && echo "FAIL: webkit dependency still present" || echo "PASS"
```
### Definition of Done
- [ ] `./gradlew assembleDebug` passes without `assets/self-wallet/` directory
- [ ] `WebViewAssetLoader` fully removed from source
- [ ] `androidx.webkit:webkit` removed from dependencies
- [ ] `validateWebViewBundle` Gradle task removed
- [ ] `SelfSdkConfig.webAppUrl` defaults to `https://verify.self.xyz/v1/`
- [ ] `shouldOverrideUrlLoading` allows `verify.self.xyz` domain
- [ ] Debug mode (`devServerUrl`) still works unchanged
- [ ] Bridge communication works identically (handlers unchanged)
- [ ] Backlog row updated
- [ ] Plan status updated
### Status Log
- 2026-03-30: Plan created.

View File

@@ -0,0 +1,108 @@
## iOS Hosted URL Loading
> Last updated: 2026-03-30
> Status: Ready
- Workstream: sdk-distribution
- Backlog IDs: SD-02
- Owner: TBD
- Branch: TBD
- PR: TBD
### Why
- The iOS native shell currently loads the WebView bundle from local files via `WKWebView.loadFileURL`, embedding ~34MB into the Swift Package.
- Switching to a hosted URL (`https://verify.self.xyz/v1/`) eliminates the bundle from the package, making SPM resolution fast and the package lightweight.
- The SDK opens a hosted webpage instead of a bundled one — UI updates ship without requiring SDK version bumps.
### Scope
- Replace `loadFileURL` with `load(URLRequest(url:))` for the hosted URL
- Add `webAppUrl` field to `SelfSdkConfig` with default `https://verify.self.xyz/v1/`
- Remove `.copy("Resources/self-sdk-web")` resource processing from `Package.swift`
- Update navigation policy to allow the hosted domain
### Out of Scope
- Bridge handler changes (protocol is identical regardless of URL source)
- Debug mode / `devServerUrl` (already works independently of file loading)
- SPM publishing cleanup (SD-05)
- Android changes (SD-01)
- Hosting setup (SD-03)
- CI/CD configuration
### Files to Modify
- `packages/native-shell-ios/Sources/.../SelfWebViewHost.swift` — Replace `loadFileURL(_:allowingReadAccessTo:)` with `load(URLRequest(url: URL(string: config.webAppUrl)!))`. Update `decidePolicyFor navigationAction` to allow `verify.self.xyz` domain.
- `packages/native-shell-ios/Sources/.../SelfSdkConfig.swift` — Add `public var webAppUrl: String = "https://verify.self.xyz/v1/"`.
- `packages/native-shell-ios/Sources/.../SelfSdk.swift` — Thread `webAppUrl` from config to the WebView host.
- `packages/native-shell-ios/Package.swift` — Remove `.copy("Resources/self-sdk-web")` from the resource processing rules. Remove the `Resources/` directory reference if it becomes empty.
### Files NOT to Modify
- `packages/native-shell-ios/Sources/.../MessageRouter.swift` — Bridge routing is unchanged
- `packages/native-shell-ios/Sources/.../SecureStorageHandler.swift` — Handler logic unchanged
- `packages/native-shell-ios/Sources/.../CryptoHandler.swift` — Handler logic unchanged
- `packages/native-shell-ios/Sources/.../LifecycleHandler.swift` — Handler logic unchanged
- `packages/webview-bridge/` — Upstream, do not change
- `packages/webview-app/` — Upstream, do not change
### Preconditions
- NSL-02 is complete (iOS native shell exists)
- SD-03 is complete (hosted URL is live at `https://verify.self.xyz/v1/`)
### Implementation Details
1. **Replace `loadFileURL`** in `SelfWebViewHost.swift`:
- Remove the bundle path resolution that finds `Resources/self-sdk-web/index.html`
- Remove `loadFileURL(_:allowingReadAccessTo:)` call
- Replace with `webView.load(URLRequest(url: URL(string: webAppUrl)!))` where `webAppUrl` comes from config
- Config params (`teeUrl`, `verificationId`, `userId`) continue to be appended as URL query params
2. **Update navigation policy**:
- In `decidePolicyFor navigationAction`, allow navigation to `verify.self.xyz` domain
- Continue blocking other external navigations
- Keep the existing `devServerUrl` allowlisting for debug mode
3. **Add `webAppUrl` to config**:
- In `SelfSdkConfig.swift`: `public var webAppUrl: String = "https://verify.self.xyz/v1/"`
- The default means existing integrators get hosted loading without config changes
4. **Clean up `Package.swift`**:
- Remove `.copy("Resources/self-sdk-web")` from the SPM resource rules
- If `resources:` array becomes empty, remove the parameter entirely
- Delete the `Resources/self-sdk-web/` directory (or its `.gitkeep` placeholder)
5. **Thread config through**:
- `SelfSdk.start(config:)``SelfWebViewHost` init → `loadURL`
- `webAppUrl` follows the same path as existing config fields
### Validation
```bash
# Build must succeed without Resources/self-sdk-web/ directory
cd packages/native-shell-ios && swift build
# Verify no loadFileURL reference
grep -r "loadFileURL" packages/native-shell-ios/Sources/ && echo "FAIL: loadFileURL still referenced" || echo "PASS"
# Verify no resource copy in Package.swift
grep "self-sdk-web" packages/native-shell-ios/Package.swift && echo "FAIL: resource copy still present" || echo "PASS"
```
### Definition of Done
- [ ] `swift build` passes without `Resources/self-sdk-web/` directory
- [ ] `loadFileURL` fully removed from source
- [ ] `.copy("Resources/self-sdk-web")` removed from `Package.swift`
- [ ] `SelfSdkConfig.webAppUrl` defaults to `https://verify.self.xyz/v1/`
- [ ] Navigation policy allows `verify.self.xyz` domain
- [ ] Debug mode (`devServerUrl`) still works unchanged
- [ ] Bridge communication works identically (handlers unchanged)
- [ ] Backlog row updated
- [ ] Plan status updated
### Status Log
- 2026-03-30: Plan created.

View File

@@ -0,0 +1,103 @@
## WebView App Hosting Setup
> Last updated: 2026-03-30
> Status: Ready
- Workstream: sdk-distribution
- Backlog IDs: SD-03
- Owner: TBD
- Branch: TBD
- PR: TBD
### Why
- The native shells are switching from embedded bundles to loading `https://verify.self.xyz/v1/`.
- The WebView app must be deployed and reachable at that URL before SD-01 and SD-02 can be tested or shipped.
- This is the critical-path prerequisite for the entire SDK distribution workstream.
### Scope
- Deploy `packages/webview-app/` build output at `https://verify.self.xyz/v1/`
- Handle `/v1/` base path (either via `base` in Vite config or hosting-layer URL rewrite)
- SPA rewrite rules (all paths under `/v1/` serve `index.html`)
- Security headers: HSTS (`Strict-Transport-Security`), appropriate `Content-Security-Policy`
- Cache headers: hashed assets get long-lived `Cache-Control`, `index.html` gets short TTL or `no-cache`
### Out of Scope
- WebView app source code changes (owned by WebView workstream)
- CI/CD pipeline for automated deployments (separate follow-up)
- CDN bundle integrity / signed manifests (BP-02, deferred)
- Multiple environment deployments (staging, preview) — follow-up
### Files to Modify
- `packages/webview-app/vite.config.ts` — Add `base: '/v1/'` so asset paths resolve correctly under the versioned path. This is the only source code change.
### Files NOT to Modify
- `packages/webview-app/src/` — No application code changes
- `packages/webview-bridge/` — Upstream, do not change
- `packages/native-shell-android/` — Downstream, SD-01
- `packages/native-shell-ios/` — Downstream, SD-02
### Preconditions
- `packages/webview-app/` builds successfully (`yarn workspace @selfxyz/webview-app build`)
- DNS for `verify.self.xyz` is configured (or can be configured)
### Implementation Details
1. **Vite base path**:
- Set `base: '/v1/'` in `vite.config.ts`
- This makes all asset references (`/v1/assets/index-abc123.js`) resolve correctly
- Alternatively, the hosting layer can rewrite `/v1/*``/*` and leave `base` as `/` — decide based on hosting provider capabilities
2. **Hosting requirements** (provider-agnostic):
- **SPA rewrite**: Any request to `/v1/*` that doesn't match a static file must serve `/v1/index.html`
- **HTTPS**: TLS required. No HTTP access in production.
- **HSTS**: `Strict-Transport-Security: max-age=31536000; includeSubDomains`
- **Cache policy**:
- `/v1/index.html`: `Cache-Control: no-cache` (always revalidate — enables auto-update)
- `/v1/assets/*` (hashed filenames): `Cache-Control: public, max-age=31536000, immutable`
- **Content-Security-Policy**: Restrict `script-src` to `'self'`, allow `connect-src` for API endpoints the WebView needs
3. **Deployment process** (manual for SD-03, automated later):
- `yarn workspace @selfxyz/webview-app build`
- Deploy `packages/webview-app/dist/` under `/v1/` path
- Verify with curl
### Validation
```bash
# Build the WebView app
yarn workspace @selfxyz/webview-app build
# After deployment, verify the hosted URL
curl -sI https://verify.self.xyz/v1/ | head -20
# Expected: HTTP/2 200, Strict-Transport-Security header present
# Verify SPA rewrite works
curl -sI https://verify.self.xyz/v1/some/deep/route | head -5
# Expected: HTTP/2 200 (serves index.html)
# Verify hashed assets have correct cache headers
curl -sI https://verify.self.xyz/v1/assets/index-abc123.js | grep -i cache-control
# Expected: public, max-age=31536000, immutable
```
### Definition of Done
- [ ] `https://verify.self.xyz/v1/` returns 200 with the WebView app
- [ ] HSTS header present in response
- [ ] SPA rewrite works (deep paths serve `index.html`)
- [ ] Hashed assets have immutable cache headers
- [ ] `index.html` has `no-cache` (enables auto-update)
- [ ] Vite `base` configured for `/v1/` path
- [ ] WebView app loads and bridge initializes when opened in a browser
- [ ] Backlog row updated
- [ ] Plan status updated
### Status Log
- 2026-03-30: Plan created.

View File

@@ -0,0 +1,113 @@
## Android Maven Publishing
> Last updated: 2026-03-30
> Status: Ready
- Workstream: sdk-distribution
- Backlog IDs: SD-04
- Owner: TBD
- Branch: TBD
- PR: TBD
### Why
- After SD-01 removes the embedded bundle, the Android AAR contains only compiled Kotlin — no bundled web assets.
- Publishing to Maven Central (or a private Maven repo) lets integrators add the SDK as a Gradle dependency instead of copying the AAR manually.
- This is the standard Android library distribution mechanism.
### Scope
- Add `maven-publish` Gradle plugin to `packages/native-shell-android/build.gradle.kts`
- Configure publication with `groupId: xyz.self.sdk`, `artifactId: native-shell-android`
- Generate POM with correct dependencies
- Verify `publishToMavenLocal` produces a working AAR
### Out of Scope
- Maven Central account setup / GPG signing (ops task, not code)
- CI/CD automated publishing (separate follow-up)
- iOS publishing (SD-05)
- AAR ProGuard/R8 rules (follow-up if needed)
- Version management strategy (follow-up)
### Files to Modify
- `packages/native-shell-android/build.gradle.kts` — Add `maven-publish` plugin. Add `publishing` block with `MavenPublication` configuration. Set `groupId`, `artifactId`, `version`. Configure POM metadata (name, description, URL, license).
### Files NOT to Modify
- `packages/native-shell-android/src/` — No source code changes
- `packages/webview-app/` — Upstream, do not change
- `packages/native-shell-ios/` — Separate workstream item
### Preconditions
- SD-01 is complete (embedded bundle removed, AAR is lightweight)
### Implementation Details
1. **Add `maven-publish` plugin**:
```kotlin
plugins {
// existing plugins...
id("maven-publish")
}
```
2. **Configure publication**:
```kotlin
afterEvaluate {
publishing {
publications {
create<MavenPublication>("release") {
from(components["release"])
groupId = "xyz.self.sdk"
artifactId = "native-shell-android"
version = "0.1.0"
pom {
name.set("Self SDK Android")
description.set("Self identity verification SDK for Android")
url.set("https://self.xyz")
licenses {
license {
name.set("MIT")
url.set("https://opensource.org/licenses/MIT")
}
}
}
}
}
}
}
```
3. **Verify transitive dependencies**:
- POM must declare `androidx.security:security-crypto` and `kotlinx-serialization-json` as dependencies
### Validation
```bash
cd packages/native-shell-android
# Publish to local Maven repo
./gradlew publishToMavenLocal
# Verify AAR does not contain bundled web assets
unzip -l $(find ~/.m2/repository/xyz/self/sdk/native-shell-android -name "*.aar") | grep -E "self-wallet|self-sdk-web" && echo "FAIL: bundled assets found" || echo "PASS"
```
### Definition of Done
- [ ] `./gradlew publishToMavenLocal` succeeds
- [ ] AAR does not contain bundled web assets (`self-wallet/`, `self-sdk-web/`)
- [ ] POM includes correct `groupId` and `artifactId`
- [ ] POM declares runtime dependencies (security-crypto, kotlinx-serialization)
- [ ] A fresh Android project can add the Maven local dependency and resolve it
- [ ] Backlog row updated
- [ ] Plan status updated
### Status Log
- 2026-03-30: Plan created.

View File

@@ -0,0 +1,126 @@
## iOS Publishing (SPM + CocoaPods)
> Last updated: 2026-03-30
> Status: Ready
- Workstream: sdk-distribution
- Backlog IDs: SD-05
- Owner: TBD
- Branch: TBD
- PR: TBD
### Why
- After SD-02 removes the embedded bundle and resource copy rules, the Swift Package is lightweight and ready for distribution.
- Supporting both SPM and CocoaPods gives integrators flexibility — SPM is the modern default, but many projects still use CocoaPods.
- Both mechanisms point to the same source files. A `.podspec` file is the only addition for CocoaPods support — no code changes, no separate maintenance burden.
### Scope
- Verify `Package.swift` is clean after SD-02 (no resource copy, no stale paths)
- Verify `swift build` succeeds from a clean checkout
- Add a `.podspec` file for CocoaPods distribution
- Tag a release and verify consumption via both SPM and CocoaPods
- Ensure `.gitignore` excludes any build artifacts from the package directory
### Out of Scope
- CI/CD automated tagging/publishing (separate follow-up)
- Android publishing (SD-04)
- Binary framework (XCFramework) distribution (follow-up if needed)
- Version management strategy (follow-up)
### Files to Modify
- `packages/native-shell-ios/Package.swift` — Verify clean state after SD-02. If any stale references remain, remove them. Ensure `platforms: [.iOS(.v15)]` or appropriate minimum is set.
- `packages/native-shell-ios/.gitignore` — Ensure `.build/` and any generated artifacts are excluded.
### Files to Create
- `packages/native-shell-ios/SelfSDK.podspec` — CocoaPods spec pointing to the same Swift source files as `Package.swift`.
### Files NOT to Modify
- `packages/native-shell-ios/Sources/` — No source code changes (SD-02 handled URL loading)
- `packages/webview-app/` — Upstream, do not change
- `packages/native-shell-android/` — Separate workstream item
### Preconditions
- SD-02 is complete (resource copy removed, `loadFileURL` replaced)
### Implementation Details
1. **Verify `Package.swift` cleanliness**:
- No `resources:` parameter on the target (or empty if Swift requires it)
- No references to `self-sdk-web`, `Resources/`, or bundle paths
- `products:` declares a single library target
- `dependencies:` lists only runtime dependencies (if any)
2. **Verify `.gitignore`**:
- `.build/` excluded
- No committed build artifacts in the package directory
3. **Add `SelfSDK.podspec`**:
```ruby
Pod::Spec.new do |s|
s.name = 'SelfSDK'
s.version = '0.1.0'
s.summary = 'Self identity verification SDK for iOS'
s.homepage = 'https://self.xyz'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = 'Self'
s.source = { :git => 'https://github.com/selfxyz/self.git', :tag => s.version.to_s }
s.platform = :ios, '15.0'
s.swift_version = '5.9'
s.source_files = 'packages/native-shell-ios/Sources/**/*.swift'
end
```
Adjust `source`, `source_files`, and module name to match the actual repo structure and naming.
4. **Tag and test SPM consumption**:
- Create a Git tag (e.g., `native-shell-ios/0.1.0`)
- In a fresh Xcode project, add the package via SPM using the repo URL and tag
- Verify the package resolves, builds, and `import SelfSDK` (or the module name) works
- Verify the resolved package does NOT download bundled web assets
5. **Test CocoaPods consumption**:
- Run `pod lib lint SelfSDK.podspec` to validate the podspec
- In a fresh Xcode project with a `Podfile`, add `pod 'SelfSDK'` pointing to the local path
- Verify `pod install` succeeds and the project builds
### Validation
```bash
cd packages/native-shell-ios
# Clean build from scratch
rm -rf .build && swift build
# Verify no resource references
grep -r "self-sdk-web" Package.swift && echo "FAIL" || echo "PASS"
grep -r "Resources" Package.swift && echo "FAIL" || echo "PASS"
# Validate podspec
pod lib lint SelfSDK.podspec --allow-warnings
# Verify package source size (should be small — no bundled web assets)
du -sh Sources/
```
### Definition of Done
- [ ] `swift build` passes from clean checkout
- [ ] `Package.swift` has no resource copy rules or stale references
- [ ] `.gitignore` excludes `.build/` and artifacts
- [ ] `SelfSDK.podspec` exists and passes `pod lib lint`
- [ ] Git tag created for release
- [ ] Fresh Xcode project can add package via SPM and build
- [ ] Fresh Xcode project can add pod via CocoaPods and build
- [ ] Package resolution does not download bundled web assets
- [ ] Backlog row updated
- [ ] Plan status updated
### Status Log
- 2026-03-30: Plan created.