Skip to main content

Publishing to the Apple App Store & Google Play Store

This guide covers how to publish the three Genie apps — phone, tablet, and TV — to the Apple App Store and Google Play Store. Paths are relative to the open-genie monorepo root (apps/, packages/, and root eas.json sit side by side).

EAS and eas.json: Build and submit profiles for the phone and tablet apps live in eas.json at the monorepo root (not under apps/phone or apps/tablet). Run eas build / eas submit / eas update from apps/phone or apps/tablet so the correct app is selected; the CLI resolves the root eas.json.


Table of Contents

  1. Prerequisites
  2. Publishing the Phone App (iOS)
  3. Publishing the Phone App (Android)
  4. Publishing the Tablet App (iOS)
  5. Publishing the Tablet App (Android)
  6. Publishing the TV App (tvOS)
  7. Publishing the TV App (Android TV)
  8. OTA Updates with EAS Update
  9. Common Pitfalls

Prerequisites

Accounts You Need

AccountURLPurpose
Apple Developer Programdeveloper.apple.comRequired for App Store & TestFlight. Costs $99/year.
Google Play Consoleplay.google.com/consoleRequired for Play Store. One-time $25 fee.
Expo Accountexpo.devRequired for EAS Build & Submit (phone and tablet apps). Free tier available.

Tools to Install

# EAS CLI (for phone and tablet apps)
npm install -g eas-cli

# Log in to your Expo account
eas login

# Xcode (for TV app and local iOS builds)
# Install from the Mac App Store — you need Xcode 15+ for tvOS builds

# Fastlane (optional but recommended for automation)
brew install fastlane

Apple-Side Setup

  1. Create an App ID in Apple Developer Portal for each app:

    • Phone: com.developsmith.genie-phone (update the app.json bundleIdentifier — currently set to com.anonymous.genie-phone)
    • Tablet: com.developsmith.genie-tablet
    • TV: create a new App ID for the tvOS app
  2. Create an App Store Connect listing for each app at appstoreconnect.apple.com:

    • One listing per platform (iPhone, iPad, Apple TV)
    • Or a single universal listing if you want phone + tablet as one app
  3. Provisioning profiles & certificates: EAS handles this automatically for phone/tablet. For the TV app, you'll manage these in Xcode or via Fastlane.

Android-Side Setup

  1. Create an app listing in Google Play Console for each app.
  2. Generate a signing key: EAS can manage this for you, or you can create your own keystore.
  3. Set up Google Play App Signing: recommended — lets Google manage your signing key while you upload with an upload key.

Publishing the Phone App (iOS)

The phone app uses EAS Build and EAS Submit, which automate most of the heavy lifting. You can also open the generated native project locally: open apps/phone/ios/Genie.xcworkspace (useful for debugging; store builds for phone still go through EAS unless you set up a separate CI flow).

Step 1: Update the App Configuration

In apps/phone/app.json, make sure these fields are correct. The project currently uses com.anonymous.genie-phone for the phone bundle id; set ios.bundleIdentifier to the App ID you register (for example com.developsmith.genie-phone) before production.

{
"expo": {
"name": "Genie",
"slug": "genie-phone",
"version": "1.0.0",
"ios": {
"bundleIdentifier": "com.developsmith.genie-phone",
"supportsTablet": true,
"infoPlist": {
"NSLocalNetworkUsageDescription": "Required to discover and connect to your Genie server on the local network."
}
}
}
}

Key things to check:

  • bundleIdentifier matches your App ID in Apple Developer Portal
  • version is the user-facing version (e.g., "1.0.0")
  • supportsTablet is true in the repo so the app can be installed on iPad; the UI is still phone-oriented via layout
  • Add ios.buildNumber in app.json if you want it checked in, or let EAS apply it: the monorepo root eas.json has "autoIncrement": true on the production profile, which can bump iOS buildNumber and Android versionCode (also see cli.appVersionSource there)

Step 2: Build for Production

# From the monorepo root
cd apps/phone

# Build for iOS App Store
eas build --platform ios --profile production

EAS will:

  • Create or reuse signing credentials (certificates + provisioning profiles)
  • Build the .ipa file in the cloud
  • Provide a download link when done

Step 3: Submit to App Store Connect

# Submit the latest build to App Store Connect
eas submit --platform ios --latest

Or submit a specific build:

eas submit --platform ios --id <build-id>

Step 4: Complete the App Store Listing

In App Store Connect:

  1. Add screenshots for the required device sizes (6.7", 6.5", 5.5")
  2. Write the app description, keywords, and what's new
  3. Set the age rating and privacy policy URL
  4. Fill in the App Privacy section (data collection disclosures)
  5. Submit for App Review

Step 5: App Review

Apple reviews typically take 24-48 hours. Common rejection reasons:

  • Missing privacy policy
  • Incomplete metadata or screenshots
  • Crashes during review
  • Accessing APIs without proper permission descriptions (camera, microphone, etc.)

Publishing the Phone App (Android)

Step 1: Update the App Configuration

In apps/phone/app.json, set a Play Store application id and align assets with the checked-in app. The repo already defines adaptive icon files under assets/images/; add android.package and versionCode before you ship to Google Play (see expo.android in the Expo app config):

{
"expo": {
"android": {
"package": "com.developsmith.geniephone",
"versionCode": 1,
"adaptiveIcon": {
"backgroundColor": "#E6F4FE",
"foregroundImage": "./assets/images/android-icon-foreground.png",
"backgroundImage": "./assets/images/android-icon-background.png",
"monochromeImage": "./assets/images/android-icon-monochrome.png"
},
"edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false
}
}
}

Step 2: Build for Production

cd apps/phone

# Build an Android App Bundle (.aab) for Play Store
eas build --platform android --profile production

On your first build, EAS will ask if you want it to manage your Android keystore. Say yes — this is the simplest approach.

Step 3: Submit to Google Play

# Submit to Google Play (requires service account JSON key)
eas submit --platform android --latest

First-time setup for eas submit on Android:

  1. Create a Google Cloud service account with Play Console permissions
  2. Download the JSON key file (for example, place it at the monorepo root as google-play-key.json and keep it out of version control)
  3. Merge a submit block into the monorepo root eas.json (see current file for the existing submit.production entry):
{
"submit": {
"production": {
"android": {
"serviceAccountKeyPath": "./google-play-key.json",
"track": "production"
}
}
}
}

Paths in eas.json are relative to the repository root where that file lives.

Alternatively, you can manually upload the .aab file from the EAS build output to the Google Play Console.

Step 4: Complete the Play Store Listing

In Google Play Console:

  1. Fill in the store listing — title, description, screenshots
  2. Complete the content rating questionnaire
  3. Set up pricing and distribution
  4. Fill in the data safety section
  5. Submit for review

Google reviews typically take a few hours to a few days for first submissions.


Publishing the Tablet App (iOS)

The process is nearly identical to the phone app, with a few differences.

Key Differences

  • Bundle identifier: com.developsmith.genie-tablet
  • Orientation: The tablet app defaults to landscape — make sure your screenshots are landscape
  • iPad-specific screenshots: App Store requires iPad Pro (12.9") screenshots
  • You can either publish this as a separate app or as a universal app combined with the phone version

Build and Submit

cd apps/tablet

# Build
eas build --platform ios --profile production

# Submit
eas submit --platform ios --latest

Separate App vs. Universal App

Option A — Separate listings (current setup): Each app has its own bundle ID, its own App Store listing, and its own reviews/ratings.

Option B — Universal app: Merge phone and tablet into a single App Store listing by using the same bundle ID and setting supportsTablet: true in the phone app's config. This requires architectural changes since the apps currently have different navigation patterns (tabs vs. drawer).


Publishing the Tablet App (Android)

Same process as the phone app for Android, but use the tablet app directory:

cd apps/tablet

eas build --platform android --profile production
eas submit --platform android --latest

Make sure the tablet and phone use different android.package values when you add them to each app.json (neither is set in the repo yet, but you will need them for Play).


Publishing the TV App (tvOS)

The TV app uses react-native-tvos (not Expo), so it cannot use EAS Build. You'll build and submit through Xcode.

Step 1: Open the Xcode Project

cd apps/tv

# Install pods (if applicable)
cd ios && pod install && cd ..

# Open in Xcode
open ios/GenieTV.xcworkspace

Step 2: Configure Signing in Xcode

  1. Select the GenieTV target
  2. Go to Signing & Capabilities
  3. Select your Team (your Apple Developer account)
  4. Set the Bundle Identifier (e.g., com.developsmith.genie-tv)
  5. Xcode will automatically create the provisioning profile

Step 3: Create an Archive

  1. In Xcode, select Product → Destination → Any Apple TV
  2. Select Product → Archive
  3. Wait for the build to complete

Step 4: Upload to App Store Connect

  1. In the Organizer window (Window → Organizer), select the archive
  2. Click Distribute App
  3. Choose App Store Connect
  4. Follow the prompts to upload

Step 5: Complete the Listing

In App Store Connect:

  1. Create a new tvOS app listing (or add tvOS to an existing app)
  2. Add Apple TV screenshots (1920x1080 or 3840x2160)
  3. Add a top shelf image (wide banner shown on the Apple TV home screen)
  4. Fill in the description, privacy policy, etc.
  5. Submit for review

Create a Fastfile in apps/tv/ios/fastlane/:

default_platform(:ios)

platform :ios do
desc "Build and upload to TestFlight"
lane :beta do
build_app(
workspace: "GenieTV.xcworkspace",
scheme: "GenieTV",
destination: "generic/platform=tvOS"
)
upload_to_testflight
end

desc "Build and upload to App Store"
lane :release do
build_app(
workspace: "GenieTV.xcworkspace",
scheme: "GenieTV",
destination: "generic/platform=tvOS"
)
upload_to_app_store
end
end

Then run:

cd apps/tv/ios
fastlane beta # Upload to TestFlight
fastlane release # Upload to App Store

Publishing the TV App (Android TV)

The current TV app targets tvOS only. This repository has no android/ project for apps/tv—only the Apple TV native tree under apps/tv/ios/. The upstream react-native-tvos ecosystem can in principle target Android TV, but doing so would require adding an Android app, AndroidManifest leanback/television metadata, and a release pipeline. That is not set up here.


OTA Updates with EAS Update

For the phone and tablet apps (Expo-based), you can push JavaScript-only updates without going through the App Store review process.

Setup

# Install the expo-updates package (if not already installed)
npx expo install expo-updates

# Configure the update URL in app.json
# EAS handles this automatically when you run:
eas update:configure

Pushing an Update

cd apps/phone # or apps/tablet

# Push an update to the production channel
eas update --branch production --message "Fix chat scrolling bug"

When to Use OTA vs. a New Build

Change TypeUse OTA UpdateUse New Build
Bug fix in JS/TS codeYesNo
UI tweaksYesNo
New native module addedNoYes
Expo SDK upgradeNoYes
New app permissionsNoYes
Native code changesNoYes

OTA updates are not available for the TV app since it does not use Expo.


Common Pitfalls

iOS

  1. Bundle ID mismatch: Make sure the bundleIdentifier in app.json matches exactly what's registered in Apple Developer Portal. The phone app currently uses com.anonymous.genie-phone — you'll want to change this before your first production build.

  2. Privacy descriptions: iOS requires descriptions for any sensitive API access. Make sure app.json includes infoPlist entries for:

    • NSCameraUsageDescription (if using camera)
    • NSMicrophoneUsageDescription (tablet app uses this for voice)
    • NSPhotoLibraryUsageDescription (if accessing photos)
    • NSLocalNetworkUsageDescription (for LAN server connection)
  3. Push notification entitlements: The phone and tablet apps use push notifications — make sure the Push Notifications capability is enabled in Apple Developer Portal for their App IDs.

  4. App Transport Security: If connecting to a local server over HTTP (not HTTPS), you'll need an ATS exception in infoPlist.

Android

  1. Keystore management: If EAS manages your keystore, back it up. You can download it with eas credentials. Losing your keystore means you can never update the app — you'd have to publish a new listing.

  2. Permissions: Android requires permissions in AndroidManifest.xml. Expo handles common ones, but double-check that all required permissions are declared.

  3. 64-bit requirement: Google Play requires 64-bit native libraries. EAS builds include these by default.

  4. Target API level: Google Play requires targeting a recent Android API level. Expo keeps up with this, but verify before submitting.

General

  1. Version numbering: Increment the user-facing version in app.json when it makes sense for your release. The monorepo root eas.json is configured with "autoIncrement": true on the production profile so EAS can bump buildNumber (iOS) and versionCode (Android) automatically, subject to EAS/Expo’s version source settings.

  2. Test on real devices: Always test production builds on real hardware before submitting. Simulators don't catch everything — especially push notifications, background tasks, and performance issues.

  3. Privacy policy: Both Apple and Google require a privacy policy URL. Have this ready before your first submission.

  4. Screenshots: Prepare screenshots for all required device sizes before submitting. You'll need different sets for iPhone, iPad, and Apple TV.


Quick Reference: Build & Submit Commands

eas.json is in the monorepo root; the commands below use apps/phone or apps/tablet as the app directory (same as the step-by-step sections above).

# ---- Phone ----
cd apps/phone
eas build --platform ios --profile production
eas build --platform android --profile production
eas submit --platform ios --latest
eas submit --platform android --latest

# ---- Tablet ----
cd apps/tablet
eas build --platform ios --profile production
eas build --platform android --profile production
eas submit --platform ios --latest
eas submit --platform android --latest

# ---- TV (tvOS — via Xcode) ----
cd apps/tv/ios
# Open Xcode → Product → Archive → Distribute App

# ---- OTA Updates (phone & tablet only) ----
cd apps/phone # or apps/tablet
eas update --branch production --message "description of changes"