docs: add Apple App Store + Google Play Store release guides
- APPLE/README.md: API key details, App Store Connect setup, TestFlight workflow, submission checklist, provisioning, screenshots/metadata requirements - GOOGLE/README.md: Play Console setup, service account config, signing keys, AAB upload, testing tracks, data safety, content rating, submission checklist
This commit is contained in:
parent
05594a334f
commit
a762c5b07f
283
docs/_MobileApps/APPLE/README.md
Normal file
283
docs/_MobileApps/APPLE/README.md
Normal file
@ -0,0 +1,283 @@
|
||||
# Apple Developer — App Store & TestFlight Guide
|
||||
|
||||
## API Key
|
||||
|
||||
| Field | Value |
|
||||
| --------- | -------------------------------------- |
|
||||
| Key ID | `PPATU9GL73` |
|
||||
| Issuer ID | `1dbc2980-1621-4fb9-940b-e28257e6322c` |
|
||||
| Role | App Manager |
|
||||
| File | `AuthKey_PPATU9GL73.p8` |
|
||||
|
||||
> **⚠️ The `.p8` file is NOT checked into git** (blocked by secret scanner). It lives at `~/.appstoreconnect/private_keys/AuthKey_PPATU9GL73.p8` on each machine. Copy it manually between machines or re-download from App Store Connect (one-time download only — keep a backup).
|
||||
|
||||
### Setup on any machine
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.appstoreconnect/private_keys
|
||||
# Copy the .p8 from another machine or your backup
|
||||
cp /path/to/AuthKey_PPATU9GL73.p8 ~/.appstoreconnect/private_keys/
|
||||
chmod 600 ~/.appstoreconnect/private_keys/AuthKey_PPATU9GL73.p8
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Apple Developer Account
|
||||
|
||||
| Field | Value |
|
||||
| ----------------- | ------------------------------------------------------------------ |
|
||||
| Team ID | `748N7QPX7J` |
|
||||
| Apple ID | `saravanakumardb1@gmail.com` |
|
||||
| Portal | [developer.apple.com/account](https://developer.apple.com/account) |
|
||||
| App Store Connect | [appstoreconnect.apple.com](https://appstoreconnect.apple.com) |
|
||||
|
||||
---
|
||||
|
||||
## Registered Apps
|
||||
|
||||
| Product | Bundle ID | App Store Connect | SKU | Status |
|
||||
| ------------------ | --------------------------------- | ----------------- | ---------- | ------------------------------------------ |
|
||||
| LysnrAI | `com.bytelyst.LysnrAI` | ✅ Created | lysnrai | In TestFlight (build 59) |
|
||||
| ChronoMind | `com.saravana.chronomind` | ❌ Needs creation | chronomind | Bundle ID registered, pending app creation |
|
||||
| ChronoMind Widgets | `com.saravana.chronomind.widgets` | N/A (extension) | — | Bundle ID registered |
|
||||
|
||||
---
|
||||
|
||||
## App Store Connect — Creating a New App
|
||||
|
||||
1. Go to [App Store Connect → My Apps](https://appstoreconnect.apple.com/apps)
|
||||
2. Click **"+"** → **"New App"**
|
||||
3. Fill in:
|
||||
- **Platforms:** iOS
|
||||
- **Name:** Product display name (e.g., `ChronoMind`)
|
||||
- **Primary Language:** English (U.S.)
|
||||
- **Bundle ID:** Select from dropdown (must be registered first — see below)
|
||||
- **SKU:** Lowercase product ID (e.g., `chronomind`)
|
||||
- **User Access:** Full Access
|
||||
4. Click **Create**
|
||||
|
||||
---
|
||||
|
||||
## Registering a New Bundle ID
|
||||
|
||||
### Via API (preferred)
|
||||
|
||||
```python
|
||||
import jwt, time, json, urllib.request
|
||||
|
||||
with open('AuthKey_PPATU9GL73.p8', 'r') as f:
|
||||
key = f.read()
|
||||
|
||||
token = jwt.encode(
|
||||
{'iss': '1dbc2980-1621-4fb9-940b-e28257e6322c', 'iat': int(time.time()),
|
||||
'exp': int(time.time()) + 1200, 'aud': 'appstoreconnect-v1'},
|
||||
key, algorithm='ES256', headers={'kid': 'PPATU9GL73', 'typ': 'JWT'}
|
||||
)
|
||||
|
||||
data = json.dumps({'data': {'type': 'bundleIds', 'attributes': {
|
||||
'identifier': 'com.saravana.PRODUCT',
|
||||
'name': 'ProductName',
|
||||
'platform': 'IOS'
|
||||
}}}).encode()
|
||||
|
||||
req = urllib.request.Request(
|
||||
'https://api.appstoreconnect.apple.com/v1/bundleIds',
|
||||
data=data,
|
||||
headers={'Authorization': f'Bearer {token}', 'Content-Type': 'application/json'},
|
||||
method='POST'
|
||||
)
|
||||
resp = urllib.request.urlopen(req)
|
||||
print(json.loads(resp.read())['data']['id'])
|
||||
```
|
||||
|
||||
### Via Portal
|
||||
|
||||
1. Go to [Certificates, Identifiers & Profiles → Identifiers](https://developer.apple.com/account/resources/identifiers/list)
|
||||
2. Click **"+"** → **App IDs** → **App**
|
||||
3. Enter description + bundle ID
|
||||
4. Enable capabilities (App Groups, Push Notifications, etc.)
|
||||
5. Click **Register**
|
||||
|
||||
---
|
||||
|
||||
## TestFlight — Uploading a Build
|
||||
|
||||
### Automated (recommended)
|
||||
|
||||
Each product repo has a `release-testflight.sh` script:
|
||||
|
||||
```bash
|
||||
# LysnrAI
|
||||
cd learning_voice_ai_agent/mobile_app/ios
|
||||
# (uses manual pbxproj — see .windsurf/workflows/release-testflight.md)
|
||||
|
||||
# ChronoMind
|
||||
cd learning_ai_clock/ios
|
||||
bash release-testflight.sh
|
||||
```
|
||||
|
||||
### Manual CLI
|
||||
|
||||
```bash
|
||||
# 1. Archive
|
||||
xcodebuild archive \
|
||||
-project MyApp.xcodeproj \
|
||||
-scheme MyApp \
|
||||
-configuration Release \
|
||||
-archivePath /tmp/MyApp.xcarchive \
|
||||
-destination 'generic/platform=iOS'
|
||||
|
||||
# 2. Export + Upload
|
||||
xcodebuild -exportArchive \
|
||||
-archivePath /tmp/MyApp.xcarchive \
|
||||
-exportPath /tmp/MyApp_export \
|
||||
-exportOptionsPlist ExportOptions.plist \
|
||||
-allowProvisioningUpdates \
|
||||
-authenticationKeyPath ~/.appstoreconnect/private_keys/AuthKey_PPATU9GL73.p8 \
|
||||
-authenticationKeyID PPATU9GL73 \
|
||||
-authenticationKeyIssuerID 1dbc2980-1621-4fb9-940b-e28257e6322c
|
||||
```
|
||||
|
||||
### ExportOptions.plist (template)
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
||||
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>method</key>
|
||||
<string>app-store-connect</string>
|
||||
<key>teamID</key>
|
||||
<string>748N7QPX7J</string>
|
||||
<key>destination</key>
|
||||
<string>upload</string>
|
||||
<key>signingStyle</key>
|
||||
<string>automatic</string>
|
||||
<key>uploadSymbols</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## App Store Submission Checklist
|
||||
|
||||
Before submitting for App Store review, ensure:
|
||||
|
||||
### Required Assets
|
||||
|
||||
| Asset | Spec | Notes |
|
||||
| ------------------ | ----------------------- | ---------------------------------------- |
|
||||
| App Icon | 1024×1024 PNG | No alpha channel, no rounded corners |
|
||||
| Screenshots (6.7") | 1290×2796 | iPhone 15 Pro Max — required |
|
||||
| Screenshots (6.5") | 1284×2778 | iPhone 14 Plus — required |
|
||||
| Screenshots (5.5") | 1242×2208 | iPhone 8 Plus — optional but recommended |
|
||||
| iPad Screenshots | 2048×2732 | Required if app supports iPad |
|
||||
| App Preview Video | 1920×1080 or device res | Optional, up to 30 seconds |
|
||||
|
||||
### Required Metadata
|
||||
|
||||
| Field | Notes |
|
||||
| ------------------ | ------------------------------------------------ |
|
||||
| App Name | Max 30 characters |
|
||||
| Subtitle | Max 30 characters |
|
||||
| Description | Required, no max (but first 3 lines matter most) |
|
||||
| Keywords | Max 100 characters, comma-separated |
|
||||
| Support URL | Must be a valid, reachable URL |
|
||||
| Privacy Policy URL | **Required** — must be a valid, reachable URL |
|
||||
| Category | Primary + optional secondary |
|
||||
| Age Rating | Answer the questionnaire honestly |
|
||||
| Copyright | e.g., `© 2026 ByteLyst` |
|
||||
|
||||
### Required for Review
|
||||
|
||||
| Requirement | Details |
|
||||
| ---------------------- | --------------------------------------------------------------- |
|
||||
| Privacy Policy URL | Must be publicly accessible |
|
||||
| App Review Information | Contact info (name, phone, email) for reviewer |
|
||||
| Demo Account | If app requires login, provide test credentials |
|
||||
| Notes for Review | Explain any non-obvious features or permissions |
|
||||
| Content Rights | Confirm you have rights to all content |
|
||||
| IDFA Declaration | If using AdSupport framework |
|
||||
| Export Compliance | Encryption usage (most apps: standard encryption = YES, exempt) |
|
||||
|
||||
### Privacy & Permissions
|
||||
|
||||
For each permission your app uses, you must:
|
||||
|
||||
1. Add a usage description string in Info.plist (e.g., `NSMicrophoneUsageDescription`)
|
||||
2. Declare it in App Store Connect → App Privacy
|
||||
|
||||
Common permissions for ByteLyst apps:
|
||||
|
||||
| Permission | Info.plist Key | Apps |
|
||||
| ------------------ | ------------------------------------- | ----------------- |
|
||||
| Microphone | `NSMicrophoneUsageDescription` | LysnrAI |
|
||||
| Speech Recognition | `NSSpeechRecognitionUsageDescription` | LysnrAI |
|
||||
| Location | `NSLocationWhenInUseUsageDescription` | PeakPulse |
|
||||
| Health | `NSHealthShareUsageDescription` | PeakPulse, NomGap |
|
||||
| Notifications | `NSUserNotificationsUsageDescription` | All |
|
||||
| Camera | `NSCameraUsageDescription` | MindLyst |
|
||||
|
||||
### App Privacy (Data Collection)
|
||||
|
||||
In App Store Connect → App Privacy, declare:
|
||||
|
||||
- What data types your app collects
|
||||
- Whether data is linked to user identity
|
||||
- Whether data is used for tracking
|
||||
- Purpose of each data type
|
||||
|
||||
---
|
||||
|
||||
## TestFlight Beta Testing
|
||||
|
||||
### Internal Testing (up to 100 testers)
|
||||
|
||||
1. Upload build (see above)
|
||||
2. Wait ~15-30 min for processing
|
||||
3. Go to App Store Connect → TestFlight → Internal Testing
|
||||
4. Add testers by Apple ID email
|
||||
5. Testers install via TestFlight app
|
||||
|
||||
### External Testing (up to 10,000 testers)
|
||||
|
||||
1. Create a beta group in TestFlight
|
||||
2. Add a build to the group
|
||||
3. Submit for **Beta App Review** (required for external testers)
|
||||
4. Review takes ~24-48 hours
|
||||
5. Once approved, distribute via link or email
|
||||
|
||||
### Beta App Review Requirements
|
||||
|
||||
- Same as App Store review but slightly more lenient
|
||||
- Still needs: privacy policy URL, app description, contact info
|
||||
- Crashes or obvious bugs will be rejected
|
||||
|
||||
---
|
||||
|
||||
## Certificates & Signing
|
||||
|
||||
| Type | Purpose | Managed By |
|
||||
| ------------------ | ----------------------------- | ------------------------------ |
|
||||
| Apple Development | Debug builds, simulator | Xcode (automatic) |
|
||||
| Apple Distribution | App Store / TestFlight builds | Xcode (automatic with API key) |
|
||||
|
||||
With `-allowProvisioningUpdates` and the API key, Xcode automatically manages certificates and provisioning profiles. No manual certificate management needed.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Error | Fix |
|
||||
| ------------------------------------------- | -------------------------------------------------------- |
|
||||
| `No signing certificate "iOS Distribution"` | Use `-allowProvisioningUpdates` with API key |
|
||||
| `Authentication failed` | Check .p8 key path, Key ID, Issuer ID |
|
||||
| `Error Downloading App Information` | Create app record in App Store Connect first |
|
||||
| `App Groups capability` | Register App Group in developer portal |
|
||||
| `FORBIDDEN_ERROR` on app creation | API key needs Admin role (App Manager can't create apps) |
|
||||
| `Bundle ID not available` | Someone else registered it — use a different one |
|
||||
| `Missing compliance` | Set Export Compliance in App Store Connect |
|
||||
| `Build processing stuck` | Wait up to 1 hour; check email for processing errors |
|
||||
331
docs/_MobileApps/GOOGLE/README.md
Normal file
331
docs/_MobileApps/GOOGLE/README.md
Normal file
@ -0,0 +1,331 @@
|
||||
# Google Play Store — Android App Distribution Guide
|
||||
|
||||
## Google Play Console
|
||||
|
||||
| Field | Value |
|
||||
| ----------------- | ---------------------------------------------------------- |
|
||||
| Console URL | [play.google.com/console](https://play.google.com/console) |
|
||||
| Developer Account | ByteLyst / saravanakumardb1@gmail.com |
|
||||
|
||||
---
|
||||
|
||||
## Registered Apps
|
||||
|
||||
| Product | Package Name | Play Console | Status |
|
||||
| ---------- | ---------------------- | ----------------- | -------------------------------- |
|
||||
| LysnrAI | `com.bytelyst.lysnrai` | ❌ Needs creation | Gradle builds, pending setup |
|
||||
| ChronoMind | `com.chronomind.app` | ❌ Needs creation | Gradle builds, pending setup |
|
||||
| MindLyst | `com.mindlyst.android` | ❌ Needs creation | KMP shared module, pending setup |
|
||||
| JarvisJr | `com.jarvisjr.app` | ❌ Needs creation | Jetpack Compose, pending setup |
|
||||
|
||||
---
|
||||
|
||||
## One-Time Setup
|
||||
|
||||
### 1. Google Play Console Account
|
||||
|
||||
If you don't have one yet:
|
||||
|
||||
1. Go to [play.google.com/console/signup](https://play.google.com/console/signup)
|
||||
2. Pay the one-time $25 registration fee
|
||||
3. Complete identity verification (can take 48 hours)
|
||||
|
||||
### 2. Create a Service Account (for CLI uploads)
|
||||
|
||||
1. Go to [Google Cloud Console → IAM → Service Accounts](https://console.cloud.google.com/iam-admin/serviceaccounts)
|
||||
2. Select or create a project (e.g., `bytelyst-releases`)
|
||||
3. Click **"+ Create Service Account"**
|
||||
- Name: `play-upload`
|
||||
- Role: (skip — we'll grant access in Play Console)
|
||||
4. Click **"..."** → **"Manage keys"** → **"Add Key"** → **"Create new key"** → **JSON**
|
||||
5. Save the JSON key file to this directory and `~/.google-play/`
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.google-play
|
||||
cp service-account-key.json ~/.google-play/
|
||||
chmod 600 ~/.google-play/service-account-key.json
|
||||
```
|
||||
|
||||
### 3. Link Service Account to Play Console
|
||||
|
||||
1. Go to [Play Console → Settings → API access](https://play.google.com/console/developers/api-access)
|
||||
2. Click **"Link"** next to Google Cloud project
|
||||
3. Under Service Accounts, find `play-upload` → **"Grant access"**
|
||||
4. Set permissions: **Release manager** (or **Admin** for full control)
|
||||
5. Add the apps it can manage
|
||||
|
||||
---
|
||||
|
||||
## Creating a New App in Play Console
|
||||
|
||||
1. Go to [Play Console → All apps](https://play.google.com/console/developers)
|
||||
2. Click **"Create app"**
|
||||
3. Fill in:
|
||||
- **App name:** Product name (e.g., `ChronoMind`)
|
||||
- **Default language:** English (United States)
|
||||
- **App or Game:** App
|
||||
- **Free or Paid:** Free
|
||||
4. Accept declarations and click **"Create app"**
|
||||
|
||||
### After Creation — Complete the Store Listing
|
||||
|
||||
Navigate through the **Dashboard** checklist:
|
||||
|
||||
| Section | Required For |
|
||||
| --------------- | ------------------------------------------------ |
|
||||
| App access | If app requires login → provide test credentials |
|
||||
| Ads | Declare if app contains ads |
|
||||
| Content rating | Complete IARC questionnaire |
|
||||
| Target audience | Select age groups |
|
||||
| News apps | Declare if it's a news app |
|
||||
| COVID-19 apps | Declare if related |
|
||||
| Data safety | Privacy questionnaire (like Apple's App Privacy) |
|
||||
| Government apps | Declare if government-related |
|
||||
|
||||
---
|
||||
|
||||
## Building an Android Release
|
||||
|
||||
### Signing Key Setup (one-time per app)
|
||||
|
||||
```bash
|
||||
# Generate an upload keystore
|
||||
keytool -genkey -v \
|
||||
-keystore ~/keystores/chronomind-upload.jks \
|
||||
-keyalg RSA -keysize 2048 -validity 10000 \
|
||||
-alias upload \
|
||||
-storepass <PASSWORD> \
|
||||
-keypass <PASSWORD> \
|
||||
-dname "CN=ByteLyst, O=ByteLyst, L=Dallas, ST=TX, C=US"
|
||||
```
|
||||
|
||||
> **⚠️ CRITICAL:** Back up the keystore file and passwords. If you lose them, you cannot update the app. Store a copy in this directory.
|
||||
|
||||
### Configure signing in the app
|
||||
|
||||
Create or edit `android/keystore.properties` (gitignored):
|
||||
|
||||
```properties
|
||||
storePassword=<PASSWORD>
|
||||
keyPassword=<PASSWORD>
|
||||
keyAlias=upload
|
||||
storeFile=/Users/<you>/keystores/chronomind-upload.jks
|
||||
```
|
||||
|
||||
Reference in `android/app/build.gradle.kts`:
|
||||
|
||||
```kotlin
|
||||
val keystoreProperties = Properties()
|
||||
val keystoreFile = rootProject.file("keystore.properties")
|
||||
if (keystoreFile.exists()) keystoreProperties.load(keystoreFile.inputStream())
|
||||
|
||||
android {
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
keyAlias = keystoreProperties["keyAlias"] as? String
|
||||
keyPassword = keystoreProperties["keyPassword"] as? String
|
||||
storeFile = file(keystoreProperties["storeFile"] as? String ?: "")
|
||||
storePassword = keystoreProperties["storePassword"] as? String
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Build the Release AAB
|
||||
|
||||
```bash
|
||||
cd android
|
||||
./gradlew :app:bundleRelease
|
||||
# Output: app/build/outputs/bundle/release/app-release.aab
|
||||
```
|
||||
|
||||
### Build a Release APK (for direct install)
|
||||
|
||||
```bash
|
||||
./gradlew :app:assembleRelease
|
||||
# Output: app/build/outputs/apk/release/app-release.apk
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Uploading to Play Console
|
||||
|
||||
### Manual Upload (Play Console UI)
|
||||
|
||||
1. Go to app → **Production** (or **Internal testing** / **Closed testing**)
|
||||
2. Click **"Create new release"**
|
||||
3. Upload the `.aab` file
|
||||
4. Add release notes
|
||||
5. Click **"Review release"** → **"Start rollout"**
|
||||
|
||||
### CLI Upload via bundletool + Google API
|
||||
|
||||
```bash
|
||||
pip install google-api-python-client google-auth
|
||||
|
||||
python3 -c "
|
||||
from googleapiclient.discovery import build
|
||||
from google.oauth2 import service_account
|
||||
|
||||
creds = service_account.Credentials.from_service_account_file(
|
||||
'$HOME/.google-play/service-account-key.json',
|
||||
scopes=['https://www.googleapis.com/auth/androidpublisher']
|
||||
)
|
||||
|
||||
service = build('androidpublisher', 'v3', credentials=creds)
|
||||
package = 'com.chronomind.app'
|
||||
|
||||
edit = service.edits().insert(body={}, packageName=package).execute()
|
||||
edit_id = edit['id']
|
||||
|
||||
service.edits().bundles().upload(
|
||||
editId=edit_id, packageName=package,
|
||||
media_body='app/build/outputs/bundle/release/app-release.aab',
|
||||
media_mime_type='application/octet-stream'
|
||||
).execute()
|
||||
|
||||
service.edits().tracks().update(
|
||||
editId=edit_id, packageName=package, track='internal',
|
||||
body={'releases': [{'status': 'completed', 'versionCodes': ['1']}]}
|
||||
).execute()
|
||||
|
||||
service.edits().commit(editId=edit_id, packageName=package).execute()
|
||||
print('Upload complete!')
|
||||
"
|
||||
```
|
||||
|
||||
### Using Gradle Play Publisher Plugin (recommended for CI)
|
||||
|
||||
Add to `android/build.gradle.kts`:
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
id("com.github.triplet.play") version "3.11.0"
|
||||
}
|
||||
|
||||
play {
|
||||
serviceAccountCredentials.set(file("$HOME/.google-play/service-account-key.json"))
|
||||
track.set("internal") // internal, alpha, beta, production
|
||||
defaultToAppBundles.set(true)
|
||||
}
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```bash
|
||||
./gradlew publishBundle # Upload AAB to configured track
|
||||
./gradlew publishInternalBundle # Upload to internal testing
|
||||
./gradlew publishAlphaBundle # Upload to closed testing
|
||||
./gradlew publishBundle --track production # Upload to production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Tracks
|
||||
|
||||
| Track | Testers | Review Required | Purpose |
|
||||
| ---------------------- | -------------------- | -------------------- | ----------------- |
|
||||
| Internal testing | Up to 100 (by email) | No | Quick dev testing |
|
||||
| Closed testing (Alpha) | Invite-only | No (first time: yes) | Wider beta |
|
||||
| Open testing (Beta) | Anyone with link | Yes (first time) | Public beta |
|
||||
| Production | Everyone | Yes | Full release |
|
||||
|
||||
### Internal Testing Setup
|
||||
|
||||
1. Go to app → **Testing** → **Internal testing**
|
||||
2. Click **"Create new release"**
|
||||
3. Upload `.aab`
|
||||
4. Click **"Review release"** → **"Start rollout"**
|
||||
5. Go to **Testers** tab → Create email list → Add tester emails
|
||||
6. Share the opt-in link with testers
|
||||
|
||||
---
|
||||
|
||||
## Play Store Submission Checklist
|
||||
|
||||
### Required Assets
|
||||
|
||||
| Asset | Spec | Notes |
|
||||
| ------------------------ | ------------------------ | ----------------------------- |
|
||||
| App Icon | 512×512 PNG | 32-bit, no alpha |
|
||||
| Feature Graphic | 1024×500 PNG or JPG | Required for store listing |
|
||||
| Screenshots (Phone) | 320-3840px, 16:9 or 9:16 | Min 2, max 8 per device type |
|
||||
| Screenshots (7" Tablet) | Same as phone | Required if targeting tablets |
|
||||
| Screenshots (10" Tablet) | Same as phone | Required if targeting tablets |
|
||||
| Promo Video | YouTube URL | Optional |
|
||||
|
||||
### Required Metadata
|
||||
|
||||
| Field | Notes |
|
||||
| ------------------- | --------------------------- |
|
||||
| App name | Max 30 characters |
|
||||
| Short description | Max 80 characters |
|
||||
| Full description | Max 4000 characters |
|
||||
| App category | Select from predefined list |
|
||||
| Contact email | Required, public |
|
||||
| Privacy Policy URL | **Required** |
|
||||
| App type & category | App or Game + category |
|
||||
|
||||
### Data Safety Declaration
|
||||
|
||||
In Play Console → App content → Data safety:
|
||||
|
||||
- Declare all data types collected
|
||||
- Whether data is encrypted in transit
|
||||
- Whether users can request deletion
|
||||
- Whether data is shared with third parties
|
||||
- Purpose of each data type
|
||||
|
||||
### Content Rating (IARC)
|
||||
|
||||
1. Go to App content → Content rating
|
||||
2. Complete the IARC questionnaire
|
||||
3. Receive ratings for all regions automatically
|
||||
|
||||
---
|
||||
|
||||
## Corporate Network / Gradle Proxy
|
||||
|
||||
When building on the corporate network:
|
||||
|
||||
```bash
|
||||
# Ensure NETWORK=corp is set (switch-network.sh)
|
||||
echo $GRADLE_OPTS
|
||||
# Should show -Djavax.net.ssl.trustStore=~/.gradle/ssl/gradle-cacerts.jks
|
||||
|
||||
# If not set:
|
||||
export GRADLE_OPTS="-Djavax.net.ssl.trustStore=$HOME/.gradle/ssl/gradle-cacerts.jks -Djavax.net.ssl.trustStorePassword=changeit"
|
||||
```
|
||||
|
||||
See `learning_ai_common_plat/AGENTS.md` § 9 for full proxy setup docs.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Error | Fix |
|
||||
| ----------------------------- | ------------------------------------------------------------ |
|
||||
| `Keystore was tampered with` | Wrong password or corrupted keystore |
|
||||
| `No key with alias 'upload'` | Check `keyAlias` in keystore.properties |
|
||||
| `Version code already exists` | Bump `versionCode` in build.gradle.kts |
|
||||
| `APK/AAB not signed` | Check signingConfig in release buildType |
|
||||
| `Deobfuscation file missing` | Upload mapping.txt alongside the AAB |
|
||||
| `Data safety form incomplete` | Complete all sections in App content → Data safety |
|
||||
| `Target API level` | Google requires targeting latest Android API (currently 34+) |
|
||||
| Gradle proxy failure | Set `GRADLE_OPTS` with truststore (see above) |
|
||||
| `SDK not found` | Set `sdk.dir` in `local.properties` |
|
||||
|
||||
---
|
||||
|
||||
## Key Files
|
||||
|
||||
| File | Location | Purpose |
|
||||
| ------------------- | ------------------------------------------ | -------------------- |
|
||||
| Service Account Key | `~/.google-play/service-account-key.json` | CLI uploads |
|
||||
| Upload Keystore | `~/keystores/<app>-upload.jks` | Release signing |
|
||||
| keystore.properties | `android/keystore.properties` (gitignored) | Local signing config |
|
||||
Loading…
Reference in New Issue
Block a user