docs: App Store screenshots placeholders + APPSTORE_METADATA.md
App Store Connect requires screenshots at 1290x2796 (6.7") and
1179x2556 (6.1") for the iPhone 17 Pro Max / 17 / Pro lineup,
with at least 3 and at most 10 images per size. The repository
previously had no screenshots in docs/.
This commit adds:
- scripts/generate_screenshot_placeholders.py - PIL-based
generator that produces 5x 6.7" + 5x 6.1" placeholders with
status bar, mock device frame, keyboard mock, and headline /
subtitle text.
- docs/screenshots/6.7/ and 6.1/ with 5 placeholder PNGs each
(10 total, all at the correct Apple-mandated dimensions).
- docs/screenshots/README.md explaining the dimensions,
generation script, and how to capture real Simulator
screenshots via `xcrun simctl io booted screenshot`.
- docs/APPSTORE_METADATA.md - a single source of truth for
every field in App Store Connect: name, subtitle, URLs,
pricing, description (<=4000 chars), promotional text
(<=170 chars), keywords (<=100 chars), release notes
(<=4000 chars), what's new, App Privacy answers
(Data Not Collected), encryption declaration, and reviewer
notes.
- AUDIT_APPSTORE.md - the v0.1.2 pre-launch audit report
with 6 P0 items, 5 P1 items, 4 P2 items, and a 9-item
"cross-cutting observations" section addressing the items
in the original brief that turned out to be non-issues
(CFBundleURLTypes in keyboard ext, NSSupportsLiveText,
AppGroup fatalError inconsistency, AudioCaptureService
interaction with AVAudioSession, ASRService SFSpeechRecognizer
references). Includes an Appendix A with the local
xcodebuild build + test results.
Important: the placeholder PNGs are intentionally bland - they
exist so App Store Connect accepts the dimensions. They MUST
be replaced with real Simulator screenshots before the actual
upload, see docs/screenshots/README.md for the workflow.
Refs: AUDIT_APPSTORE.md P0-5
@@ -0,0 +1,286 @@
|
||||
# App Store Connect — OSGKeyboard v0.1.2
|
||||
|
||||
> Use this document as a single source of truth for App Store Connect
|
||||
> version metadata. All values are Apple-compliant (character limits
|
||||
> respected, no marketing claims that would trigger Guideline 4.0).
|
||||
|
||||
---
|
||||
|
||||
## App Information
|
||||
|
||||
| Field | Value | Notes |
|
||||
|---|---|---|
|
||||
| **App name** | `OSGKeyboard` | CFBundleDisplayName. ≤ 30 chars. |
|
||||
| **Subtitle** | `Voice input, everywhere` | ≤ 30 chars. |
|
||||
| **Bundle ID** | `com.osgkeyboard.ios` | project.yml `bundleIdPrefix` + target name. |
|
||||
| **SKU** | `OSGKB-001` | Internal; not user-visible. |
|
||||
| **Primary locale** | `en-US` | |
|
||||
| **Category (primary)** | `Utilities` | LSApplicationCategoryType. |
|
||||
| **Category (secondary)** | `Productivity` | Optional, helps discovery. |
|
||||
| **Content rights** | `No third-party content` | Default. |
|
||||
| **Age rating** | `4+` | No objectionable content. |
|
||||
|
||||
---
|
||||
|
||||
## URLs (required)
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Support URL** | `https://github.com/hkgood/OSGKeyboard/issues` |
|
||||
| **Marketing URL** | `https://github.com/hkgood/OSGKeyboard` |
|
||||
| **Privacy Policy URL** | `https://hkgood.github.io/OSGKeyboard/privacy/` |
|
||||
| **EULA** | *Leave blank* — use Apple's standard EULA |
|
||||
|
||||
---
|
||||
|
||||
## Pricing & Availability
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Price** | Free (0 USD) |
|
||||
| **Availability** | All App Store territories (default) |
|
||||
| **Pre-order** | No |
|
||||
| **Volume purchase** | No |
|
||||
|
||||
---
|
||||
|
||||
## Description (≤ 4000 chars)
|
||||
|
||||
```
|
||||
OSGKeyboard is a free, open-source custom keyboard for iOS 26 that turns
|
||||
your voice into clean, AI-polished text — in any app.
|
||||
|
||||
Hold the mic key, speak naturally, release. The keyboard transcribes
|
||||
your voice entirely on-device (Apple's iOS 26 SpeechAnalyzer +
|
||||
DictationTranscriber), and only the final text is sent to the AI you
|
||||
choose to polish it. Your audio never leaves your iPhone.
|
||||
|
||||
WHY OSGKEYBOARD
|
||||
|
||||
• Works everywhere — Messages, Notes, Mail, Slack, ChatGPT, Claude,
|
||||
Cursor, browsers, terminal apps. Anywhere you can type, OSGKeyboard
|
||||
types for you.
|
||||
• Push-to-talk, the way voice should work. No more "Hey Siri" mode that
|
||||
listens to the whole room.
|
||||
• On-device speech recognition. Powered by Apple's iOS 26 speech
|
||||
pipeline — no cloud ASR, no audio upload.
|
||||
• Bring-your-own AI. Connect any OpenAI-compatible endpoint (OpenAI,
|
||||
DeepSeek, Qwen DashScope, Moonshot, Zhipu, your own self-hosted
|
||||
server). Your API key stays in the iOS Keychain.
|
||||
• Three polish modes:
|
||||
– Off: raw transcript.
|
||||
– Transcribe: just the cleaned-up text.
|
||||
– Polish: punctuation, structure, and grammar via your chosen LLM.
|
||||
• Continuous flow. One session, many utterances — no need to re-open
|
||||
the host app between thoughts.
|
||||
• Zero dependencies. No trackers, no analytics, no crash reporters.
|
||||
The whole project is ~8,700 lines of Swift you can audit in an
|
||||
afternoon.
|
||||
• Privacy first. PrivacyInfo.xcprivacy declares zero collected data;
|
||||
we don't run a server.
|
||||
|
||||
BUILT FOR
|
||||
|
||||
• iOS 26 and later, iPhone only.
|
||||
• Anyone who types more than 100 words a day on their phone.
|
||||
• Developers, writers, students, and translators who want voice input
|
||||
that respects their privacy.
|
||||
|
||||
OPEN SOURCE
|
||||
|
||||
OSGKeyboard is MIT-licensed and developed in the open. Issues, pull
|
||||
requests, and translations are welcome on GitHub.
|
||||
|
||||
https://github.com/hkgood/OSGKeyboard
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Promotional Text (≤ 170 chars, editable without new build)
|
||||
|
||||
```
|
||||
Voice input, everywhere. Hold the mic, speak, release — AI-polished
|
||||
text lands at your cursor. On-device speech, your own API key, zero
|
||||
trackers. iOS 26+, free & open-source.
|
||||
```
|
||||
|
||||
> Apple allows you to change the Promotional Text at any time without
|
||||
> submitting a new build. Use it for launch-day announcements.
|
||||
|
||||
---
|
||||
|
||||
## Keywords (≤ 100 chars, comma-separated)
|
||||
|
||||
```
|
||||
keyboard,voice,dictation,speech,transcribe,AI,polish,whisper,gpt,openai,productivity,accessibility
|
||||
```
|
||||
|
||||
> 97 chars. Apple matches keywords against search terms; avoid the
|
||||
> app name (already indexed) and competitor names.
|
||||
|
||||
---
|
||||
|
||||
## Release Notes (for v0.1.2, ≤ 4000 chars)
|
||||
|
||||
```
|
||||
Welcome to OSGKeyboard v0.1.2 — our App Store debut!
|
||||
|
||||
This release focuses on review-driven polish for the iOS 26 launch:
|
||||
|
||||
NEW
|
||||
• Dynamic ASR locale picker — Settings now lists every locale Apple's
|
||||
speech framework supports, with an on-device badge so you know which
|
||||
ones keep your audio on your phone.
|
||||
• Apple-on-device flow polish — the continuous-capture session survives
|
||||
app switching and can run for up to an hour in the foreground.
|
||||
• Per-locale on-device indicator — choose Chinese (Simplified) and
|
||||
you'll see the iPhone icon next to it, confirming audio never leaves
|
||||
your device.
|
||||
|
||||
FIXED
|
||||
• Light/dark mode is now consistent — cards and buttons follow the
|
||||
active theme everywhere, including the in-app keyboard preview.
|
||||
• iPhone-only lock — we removed iPad multitasking support; the app
|
||||
declares iPhone as the only target family. This fixed TestFlight
|
||||
error 90474 and the previously-misleading "supports iPad" badge.
|
||||
• Keyboard preview cycling — tapping the disc now correctly cycles
|
||||
through idle → recording → processing → idle, with sample
|
||||
transcripts in the recording state.
|
||||
• Embedded keyboard strings — Chinese and English keyboard strings
|
||||
are now properly bundled into the extension binary, so language
|
||||
switching works the moment you install the keyboard.
|
||||
• Actool crash on iOS 26 — the legacy Icon Composer icon was removed
|
||||
to stop App Store Connect rejecting the build.
|
||||
|
||||
CHANGED
|
||||
• The keyboard's top divider line is gone — the subtle highlight
|
||||
gradient is retained for visual structure without the hard separator.
|
||||
• README is consistent with the implemented capability set (iOS 26
|
||||
on-device SpeechAnalyzer + DictationTranscriber only).
|
||||
|
||||
KNOWN ISSUES
|
||||
• Continuous mode requires Full Access (Apple's policy, not ours).
|
||||
The onboarding flow walks you through enabling it.
|
||||
• Some iCloud-synced keyboards can take a few seconds to appear in
|
||||
the Add New Keyboard list. This is iOS 26 behavior.
|
||||
|
||||
We'd love to hear from you — open an issue on GitHub, or rate this
|
||||
version to help others find it.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What's New in This Version
|
||||
|
||||
*(Same as Release Notes, but shorter; the What's New field is also
|
||||
capped at 4000 chars. Apple displays it in the Updates tab.)*
|
||||
|
||||
```
|
||||
Welcome to v0.1.2 — our App Store debut!
|
||||
|
||||
NEW: Dynamic ASR locale picker with on-device indicator. Continuous
|
||||
flow sessions survive app switching for up to an hour. Polish modes:
|
||||
off / transcribe / polish.
|
||||
|
||||
FIXED: Light/dark mode is now consistent across the keyboard preview.
|
||||
TestFlight error 90474 (iPhone-only) is resolved. Keyboard preview
|
||||
disc correctly cycles idle → recording → processing. Keyboard
|
||||
strings are properly embedded in the extension bundle for instant
|
||||
language switching.
|
||||
|
||||
CHANGED: The hard divider line on the keyboard is gone; the subtle
|
||||
gradient highlight remains.
|
||||
|
||||
We'd love your feedback — open an issue on GitHub or rate this app.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## App Privacy (App Store Connect "Privacy" section)
|
||||
|
||||
Choose **"Data Not Collected"** in the first question.
|
||||
|
||||
The OSGKeyboard app and keyboard extension collect **no data** from
|
||||
you. All processing happens on-device or through the LLM endpoint you
|
||||
explicitly configure. The app does not embed any analytics, crash
|
||||
report, or tracking SDK.
|
||||
|
||||
| Question | Answer |
|
||||
|---|---|
|
||||
| Data collected from this app? | **No** |
|
||||
| Data used to track you? | **No** |
|
||||
| Data linked to your identity? | **No** |
|
||||
|
||||
The `PrivacyInfo.xcprivacy` files in both `OSGKeyboard/` and
|
||||
`OSGKeyboardExt/` declare `NSPrivacyTracking: false` and
|
||||
`NSPrivacyCollectedDataTypes: []` to match.
|
||||
|
||||
---
|
||||
|
||||
## Encryption (annual survey)
|
||||
|
||||
`Info.plist` declares `ITSAppUsesNonExemptEncryption = false`. The
|
||||
annual survey will be auto-skipped on upload. If prompted manually:
|
||||
|
||||
* Does your app use encryption? **No** (the LLM call uses HTTPS, which
|
||||
Apple classifies as "standard internet protocols" and is exempt
|
||||
under category 5 part 2 note 4 of the EAR).
|
||||
* Is your app exempt under Category 5 Part 2? **Yes** (HTTPS only).
|
||||
|
||||
---
|
||||
|
||||
## App Review information
|
||||
|
||||
When the build is uploaded and you click "Add for Review", fill in:
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| **Sign-in required** | No (no account) |
|
||||
| **Demo account** | n/a |
|
||||
| **Contact info** | (your Apple Developer account email) |
|
||||
| **Phone** | (your phone; only Apple sees it) |
|
||||
| **Notes to reviewer** | (see below) |
|
||||
|
||||
### Notes to App Review
|
||||
|
||||
```
|
||||
OSGKeyboard is a free, open-source custom keyboard. To test it end
|
||||
to end, please:
|
||||
|
||||
1. Install the keyboard:
|
||||
Settings → General → Keyboard → Keyboards → Add New Keyboard →
|
||||
under "Third-Party Keyboards" choose "OSGKeyboard".
|
||||
2. Enable Full Access for OSGKeyboard (onboarding in the app walks
|
||||
through this, but you can also tap it in the keyboard settings).
|
||||
Full Access is required for the continuous-capture flow session
|
||||
(network access for the LLM polish step + shared App Group
|
||||
container with the main app). The mic is captured on-device; the
|
||||
network call only sends the final text transcript to the LLM
|
||||
endpoint configured in Settings.
|
||||
3. In any app, switch to OSGKeyboard (globe key), then hold the
|
||||
purple mic key, speak, and release.
|
||||
4. For the LLM polish demo: open OSGKeyboard's main app, Settings,
|
||||
Provider. Enter any OpenAI-compatible key (OpenAI, DeepSeek,
|
||||
Qwen, Moonshot, Zhipu, or a self-hosted URL). The default
|
||||
provider "Custom" works with a local mock server if you have
|
||||
one running.
|
||||
5. The privacy policy is at
|
||||
https://hkgood.github.io/OSGKeyboard/privacy/
|
||||
|
||||
Source code: https://github.com/hkgood/OSGKeyboard
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Submission checklist
|
||||
|
||||
- [ ] All 10 screenshots replaced with real Simulator captures
|
||||
(5 × 1290×2796 + 5 × 1179×2556)
|
||||
- [ ] Archive in Xcode → Product → Archive → Distribute App → App
|
||||
Store Connect → Upload
|
||||
- [ ] Select the new build under "Builds" in the version
|
||||
- [ ] Fill in metadata from this document
|
||||
- [ ] Privacy: "Data Not Collected"
|
||||
- [ ] Encryption: skip (auto-skipped via Info.plist key)
|
||||
- [ ] Add for review
|
||||
- [ ] Submit
|
||||
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 84 KiB |
@@ -0,0 +1,73 @@
|
||||
# App Store Screenshots
|
||||
|
||||
> ⚠️ **PLACEHOLDERS.** The 10 PNGs in this directory are
|
||||
> automatically generated blanks produced by
|
||||
> `scripts/generate_screenshot_placeholders.py` and must be
|
||||
> **replaced with real Simulator screenshots** before App Store
|
||||
> submission. They use the correct dimensions (1290×2796 for
|
||||
> 6.7", 1179×2556 for 6.1") so the upload validator will accept
|
||||
> them, but they contain no real UI.
|
||||
|
||||
## Required dimensions (2026)
|
||||
|
||||
| Size | Devices | Dimensions | Apple requirement |
|
||||
|------|---------|-----------|---|
|
||||
| 6.7" | iPhone 17 Pro Max, 17, 16 Pro Max, 16 Plus, 15 Pro Max, 15 Plus | 1290 × 2796 px | **Required** (3-10 images) |
|
||||
| 6.1" | iPhone 17 Pro, 17, 16 Pro, 16, 15 Pro, 15, 14 Pro, 14 | 1179 × 2556 px | **Required** (3-10 images) |
|
||||
| 5.5" | iPhone 8 Plus (legacy) | 1242 × 2208 px | Optional since 2024 |
|
||||
|
||||
iPad screenshots are not required because OSGKeyboard is iPhone-only
|
||||
(`TARGETED_DEVICE_FAMILY = 1`).
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
docs/screenshots/
|
||||
├── 6.7/ ← 1290×2796 (iPhone 17 Pro Max / 17)
|
||||
│ ├── 01-keyboard-default.png
|
||||
│ ├── 02-flow-session.png
|
||||
│ ├── 03-on-device-asr.png
|
||||
│ ├── 04-llm-polish.png
|
||||
│ └── 05-providers.png
|
||||
└── 6.1/ ← 1179×2556 (iPhone 17 Pro / 17)
|
||||
├── 01-keyboard-default.png
|
||||
├── 02-flow-session.png
|
||||
├── 03-on-device-asr.png
|
||||
├── 04-llm-polish.png
|
||||
└── 05-providers.png
|
||||
```
|
||||
|
||||
## How to capture real screenshots
|
||||
|
||||
1. Open `OSGKeyboard.xcodeproj` in Xcode 26+
|
||||
2. Run on **iPhone 17 Pro** simulator (6.1" set) and **iPhone 17 Pro Max** simulator (6.7" set)
|
||||
3. For each scene:
|
||||
```bash
|
||||
# Take a screenshot of the simulator window
|
||||
xcrun simctl io booted screenshot ~/Desktop/shot.png
|
||||
```
|
||||
4. Process for App Store (Apple rejects frames containing the device bezel — full-screen content only):
|
||||
```bash
|
||||
# The simulator screenshot already has a thin device frame.
|
||||
# Open in Preview, crop to full screen (⌘+K with ⌥ for precision),
|
||||
# export as PNG at 1290×2796 or 1179×2556.
|
||||
sips -z 2796 1290 shot.png --out final-6.7.png
|
||||
sips -z 2556 1179 shot.png --out final-6.1.png
|
||||
```
|
||||
5. Replace the placeholders with the real captures, keeping the
|
||||
same filenames so the App Store Connect → Version → Uploads UI
|
||||
auto-pairs by file.
|
||||
|
||||
## Scenes to capture
|
||||
|
||||
The 5 placeholders are intentional scene placeholders. Capture these
|
||||
*exact* screens, in this order:
|
||||
|
||||
1. **Keyboard at rest** — the iOS keyboard, OSGKeyboard mode, no recording
|
||||
2. **Flow session active** — keyboard with the green/orange recording ring,
|
||||
partial transcript visible in the host text field
|
||||
3. **On-device ASR** — Settings view with the locale list, the on-device
|
||||
indicator (iPhone icon) visible next to ≥ 3 supported locales
|
||||
4. **LLM polish** — Settings view with the API provider card, a sample
|
||||
"polish" transformation shown in the inline preview
|
||||
5. **Providers** — API Settings card scrolled to show all 6 provider logos
|
||||