Files
OSGKeyboard/docs/STOREKIT_TESTING.md
T
rockyandClaude Opus 5 5d51c5bf77 chore: snapshot uncommitted local work before rebasing onto cloud-agent
Safety commit so the 94 uncommitted files in the working tree (in-flight
Account/Mac/Tip work plus the feature-preview recording tooling) survive the
move onto cursor/cloud-agent-1787824905651-vxuwc.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 11:28:07 -07:00

141 lines
6.0 KiB
Markdown

# StoreKit — managed credit packs
OSGKeyboard ships **three Consumable** in-app purchases and no subscriptions.
All three add credits to the optional OSG managed account. The authoritative
local catalog is [`OSGKeyboard.storekit`](../OSGKeyboard.storekit); App Store
Connect must match it exactly.
| Product ID | Type | Reference name | Display name (en) | Price (CN) | Grants |
|---|---|---|---|---|---|
| `500tks` | Consumable | 500 OSG 积分 | 500 OSG Credits | ¥8 | 500 account credits |
| `1500tks` | Consumable | 1,500 OSG 积分 | 1,500 OSG Credits | ¥18 | 1,500 account credits |
| `3000tks` | Consumable | 3,000 OSG 积分 | 3,000 OSG Credits | ¥28 | 3,000 account credits |
Rules that apply to all three:
- Consumables **cannot be restored** (Apple policy). The UI states this.
- Nothing here gates a feature. Local dictation, BYOK providers, typing,
clipboard skills, and iCloud sync stay free with or without a purchase.
- Credits only add balance to the optional OSG account. They are useless
without Sign in with Apple, and the app never requires an account.
- Credit packs are **iOS / iPadOS only**. The macOS build ships via Developer
ID outside the Mac App Store, so it loads no StoreKit products at all.
## Where the packs appear
iOS Home → credit card → Account Center, and Settings → Account Center. Both
require Sign in with Apple.
## Purchase flow (server-verified)
Credit packs are not client-trusted. `AccountCreditPurchaseManager`:
1. Buys with StoreKit 2, binding `appAccountToken` to the signed-in account ID.
2. Rejects any transaction whose `appAccountToken` or product ID does not match
the configured set.
3. Submits the signed transaction to the account service
(`submitCreditTransaction`) and checks the returned transaction and product
IDs against the local ones.
4. Calls `transaction.finish()` **only after** the server confirms and the
ledger is updated.
A purchase that fails server verification stays unfinished and is retried from
the transaction-updates stream, so a crashed or backgrounded app does not lose
credits.
---
## App Store Connect setup
1. Open **App Store Connect → OSGKeyboard → In-App Purchases**.
2. Create each of the three products as **Consumable** with the exact Product
IDs above. Do not rename an existing ID — Apple treats it as a new product.
3. Add en + zh-Hans localizations. Copy comes from
[`OSGKeyboard.storekit`](../OSGKeyboard.storekit) (`localizations`) and
[`docs/APPSTORE_METADATA.md`](APPSTORE_METADATA.md).
4. Set pricing to the nearest App Store tier for China (¥8 / ¥18 / ¥28) and let
Apple map the equivalent tiers elsewhere.
5. Submit the IAPs for review **together with** the app version that exposes
them. A first IAP submitted without a build is rejected as incomplete.
### Review screenshot (required — otherwise「元数据丢失」)
Each product needs a screenshot under **审核信息 → 截屏**: run the app signed
in, open **Home → credit card → Account Center**, and capture the pack list
showing localized prices.
Optional **审核备注**:
```
Consumable credits for the optional OSG managed speech/AI service.
Requires Sign in with Apple. Local dictation and user-supplied API keys
remain free and never require credits. Consumable — cannot restore.
```
Save — status should become **准备提交**.
---
## Local testing (StoreKit Test — no Connect, no sandbox account)
The **OSGKeyboard** scheme already references `OSGKeyboard.storekit` in
`project.yml` (`storeKitConfiguration`).
1. `./Scripts/generate-xcodeproj.sh && open OSGKeyboard.xcodeproj`
2. **Product → Scheme → Edit Scheme → Run → Options** — confirm
**StoreKit Configuration** = `OSGKeyboard.storekit`
3. Run **OSGKeyboard** on a simulator (e.g. iPhone 17) or a device.
4. Sign in with Apple, then open **Home → credit card → Account Center**.
5. Buy `500tks` → balance increases by 500 after the account service confirms;
the purchase-history row appears.
6. Cancel a purchase → returns to idle with no error spam.
7. Repeat a purchase → allowed (Consumable).
**Debug menu:** Xcode → **Debug → StoreKit → Manage Transactions** to inspect
or delete test purchases.
Automated coverage: `AccountCreditPurchaseManagerTests` (in the hermetic
manifest — see [TESTING.md](TESTING.md)) and `AccountCenterUITests`, which runs
separately via `xcodebuild -scheme OSGKeyboardUITests` against the `IAPReview`
stub harness — see
[ACCOUNT_MANAGED_GATEWAY_TESTING.md](ACCOUNT_MANAGED_GATEWAY_TESTING.md).
---
## Sandbox testing (after Connect IAPs reach 准备提交)
1. App Store Connect → **用户和访问 → 沙盒** → create a **Sandbox Tester**.
2. On device: **设置 → App Store → 沙盒账户** → sign in (not your real Apple ID).
3. Install via **TestFlight**, or Debug-run with **StoreKit Configuration =
None** so the app hits Connect products.
4. Buy each pack once and confirm the server-side ledger, not just the UI.
5. Sandbox charges are free; the receipt path is the real one.
The full server-side matrix (replayed transactions, interrupted network,
wrong-account rejection) lives in
[ACCOUNT_MANAGED_GATEWAY_TESTING.md](ACCOUNT_MANAGED_GATEWAY_TESTING.md).
---
## Release checklist
- [ ] All three products load and show localized prices
- [ ] Each pack adds the correct balance after server verification
- [ ] Purchase history lists the new transaction without duplicates
- [ ] A failed/interrupted verification is retried and not lost
- [ ] User cancel returns to idle (no error spam)
- [ ] Repeat purchase works (Consumable allows multiple)
- [ ] No Restore button for any of these products
- [ ] Local dictation, BYOK, typing, and clipboard skills unchanged after purchase
---
## Files
| File | Role |
|---|---|
| `OSGKeyboard/Views/Account/AccountCreditPurchaseManager.swift` | Purchase + server verification |
| `OSGKeyboard/Views/Account/AccountCreditStore.swift` | StoreKit 2 product/purchase abstraction |
| `OSGKeyboard/Views/Account/AccountCenterView.swift` | Credit pack UI, purchase history |
| `OSGKeyboard.storekit` | Local StoreKit Test catalog |