feat: tip IAP, commercial GitHub Pages, and App Store screenshots

Add optional StoreKit support tip (features stay free), redesign the
landing page with zh/en + light/dark and product shots, and ship
iPhone/iPad/Mac App Store screenshot sets.
This commit is contained in:
Rocky
2026-07-12 11:00:57 +08:00
parent 951e9514d7
commit 166019b384
51 changed files with 1938 additions and 518 deletions
+12
View File
@@ -38,6 +38,7 @@
| Field | Value |
|---|---|
| **Price** | Free (0 USD) |
| **In-App Purchases** | Optional voluntary tip — Consumable `ByRockyACoffee` (¥28 China tier; no feature unlock) |
| **Availability** | All App Store territories (default) |
| **Pre-order** | No |
| **Volume purchase** | No |
@@ -83,6 +84,12 @@ WHY OSGKEYBOARD
touches (voice audio + transcripts, on-device by default, never
linked or tracked); we don't run a server.
OPTIONAL SUPPORT
OSGKeyboard is completely free — every feature is available without
payment. If you'd like to support development, Settings includes an
optional in-app tip (Consumable). It does not unlock anything extra.
BUILT FOR
• iOS 26 and later, iPhone and iPad.
@@ -271,6 +278,11 @@ to end, please:
5. The privacy policy is at
https://hkgood.github.io/OSGKeyboard/privacy/
6. Optional tip (Consumable IAP ByRockyACoffee): open
Settings → "Support the Developer". All features remain free before
and after purchase; the tip does not unlock anything. Consumable
tips cannot be restored (stated in UI).
Source code: https://github.com/hkgood/OSGKeyboard
```
+122
View File
@@ -0,0 +1,122 @@
# StoreKit — Voluntary Support Tip
OSGKeyboard offers a single **Consumable** in-app purchase:
| Field | Value |
|---|---|
| **Type** | Consumable |
| **Product ID** | `ByRockyACoffee` |
| **Reference name (Connect)** | 给老刘买杯咖啡 |
| **Display name (en)** | Buy me a cup of coffee |
| **Display name (zh-Hans)** | 给老刘买杯冰美式 |
| **Price (China)** | ¥28 (nearest available App Store tier) |
| **Price (US, suggested)** | $3.99 equivalent tier |
**Important:** this tip does **not** unlock translation, dictionary limits,
long Flow sessions, or any other capability. The app remains fully free.
Consumable purchases **cannot be restored** (Apple policy). Settings copy
explains this to users.
---
## App Store Connect setup
1. Open **App Store Connect → OSGKeyboard → In-App Purchases**.
2. Create **Consumable** with Product ID `ByRockyACoffee`.
3. Add localizations (en + zh-Hans) using the strings in
`OSGKeyboardShared/*/Shared.strings` (`tip.*` keys) and
`docs/APPSTORE_METADATA.md`.
4. Set pricing: **China ¥28** (App Store only offers fixed tiers — ¥28 is
the nearest to ¥30); pick equivalent tiers for other territories.
5. Submit the IAP for review **with** the app version that includes the
Settings → Support the Developer entry.
### Review screenshot (required — fixes「元数据丢失」)
App Store Connect → IAP **ByRockyACoffee****审核信息****截屏**:
1. Run the app (Simulator or device) with Settings open at the top
**支持开发者** card showing the green **打赏 ¥28.00** button.
2. Capture that screen (⌘S in Simulator, or device screenshot).
3. Upload to **截屏 → 选取文件**.
4. Optional **审核备注**:
```
Optional voluntary tip only (Consumable IAP ByRockyACoffee).
All features free before and after purchase. Settings tab → top of page.
Consumable — cannot restore (stated in UI).
```
Save — status should become **准备提交**.
---
## Local testing (StoreKit Test — no Connect / sandbox account)
Uses [`OSGKeyboard.storekit`](../OSGKeyboard.storekit). The **OSGKeyboard**
scheme already references it in `project.yml` (`storeKitConfiguration`).
1. `xcodegen generate && open OSGKeyboard.xcodeproj`
2. **Product → Scheme → Edit Scheme → Run → Options**
- Confirm **StoreKit Configuration** = `OSGKeyboard.storekit`
3. Run **OSGKeyboard** on Simulator (e.g. iPhone 17) or a plugged-in device
4. Open **Settings** tab → top card **支持开发者**
5. Tap **打赏 ¥28.00** → StoreKit Test purchase sheet appears
6. **Buy** → thank-you alert; **Cancel** → no error
7. Repeat buy once (Consumable allows multiple)
**Debug menu (optional):** Xcode → **Debug → StoreKit → Manage Transactions**
to view / delete test purchases.
---
## Sandbox testing (real App Store sandbox — after Connect IAP is 准备提交)
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 without** `.storekit`:
- To hit Connect products: Edit Scheme → Run → Options → set StoreKit
Configuration to **None**, then run on device
4. Settings → **支持开发者** → purchase with sandbox account
5. Sandbox charges are free; receipt is real sandbox flow
---
## Submit to App Review (after local + sandbox pass)
Yes — **wait until testing looks good**, then:
1. IAP **ByRockyACoffee** status = **准备提交** (pricing + screenshot + localizations)
2. Bump app version in `project.yml` / `CHANGELOG.md` if needed
3. **Archive** → upload build to App Store Connect
4. Open the new **App Store version** page → **App 内购买项目****+** → select **ByRockyACoffee**
5. Fill metadata, attach build, submit **version + IAP together** (first IAP rule)
### Sandbox checklist
- [ ] Product loads and shows localized price
- [ ] Successful purchase shows thank-you alert
- [ ] User cancel returns to idle (no error spam)
- [ ] Repeat purchase works (Consumable allows multiple)
- [ ] No Restore button for this product (Consumable)
- [ ] Translation, Flow, dictionary, BYOK unchanged after tipping
### macOS note
The menu-bar Mac build (`com.osgkeyboard.mac`) ships via Developer ID outside
the Mac App Store today. StoreKit products load only for App Store builds.
The Mac Settings UI is present for parity; tip IAP requires an App Store
distribution if Mac tipping is enabled later.
---
## Files
| File | Role |
|---|---|
| `OSGKeyboardShared/Services/Tip/TipProduct.swift` | Product ID constants |
| `OSGKeyboardShared/Services/Tip/TipPurchaseManager.swift` | StoreKit 2 purchase flow |
| `OSGKeyboardShared/DesignSystem/SupportDeveloperSection.swift` | iOS Settings UI |
| `OSGKeyboardMac/MacSupportDeveloperTipRows.swift` | macOS Settings UI |
| `OSGKeyboard.storekit` | Local StoreKit Test catalog |
+9
View File
@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="36 367 952 291" fill="none" aria-hidden="true">
<g fill="currentColor">
<path d="M627.511 512.419C627.511 448.783 576.127 397.197 512.741 397.197C449.355 397.197 397.971 448.783 397.971 512.419C397.971 576.054 449.355 627.641 512.741 627.641V637.837C443.746 637.837 387.814 581.686 387.814 512.419C387.814 443.152 443.746 387 512.741 387C581.736 387 637.668 443.152 637.668 512.419C637.668 581.686 581.736 637.837 512.741 637.837V627.641C576.127 627.641 627.511 576.054 627.511 512.419Z"/>
<path d="M56.2632 512.419C56.2632 581.686 112.195 637.837 181.19 637.837C250.185 637.837 306.117 581.686 306.117 512.419C306.117 443.152 250.185 387 181.19 387C112.195 387 56.2632 443.152 56.2632 512.419Z"/>
<path d="M399.618 562.094L399.618 552.257L512.74 552.257L512.74 562.094L399.618 562.094Z"/>
<path d="M512.741 483.398V473.561H625.864V483.398H512.741Z"/>
<path d="M843.308 387.981C910.987 387.981 966.093 441.8 968.171 508.975H843.308V518.812H968.096C965.014 585.066 910.324 637.836 843.308 637.836C774.313 637.836 718.381 581.904 718.381 512.909C718.381 443.914 774.312 387.981 843.308 387.981ZM968.234 518.812H968.096C968.187 516.855 968.234 514.888 968.234 512.909C968.234 511.593 968.211 510.281 968.171 508.975H968.234V518.812Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

+872 -500
View File
File diff suppressed because it is too large Load Diff