# Submit to app stores



Applications built from the [`hello-pear-electron`](https://github.com/holepunchto/hello-pear-electron#store-submissions) template can also be distributed through platform-specific application stores. This guide covers the Linux store flows the template supports: **Flathub** (Flatpak) and the **Snap Store**. Mobile apps built on [`pear-mobile`](/pear/reference/pear/mobile) submit through the standard iOS App Store and Google Play flows—see [iOS](#ios) and [Android](#android) below.

Both flows start from the Linux distributables produced by `npm run make`—see [Build desktop distributables](/pear/how-to/operate-an-app/build-and-package/build-desktop-distributables#linux) first. Store distribution complements, rather than replaces, peer-to-peer distribution: apps installed from a store still update over the air through [Pear OTA](/pear/reference/pear/runtime).

## Flathub [#flathub]

Flathub packages applications as Flatpaks. This section covers preparing a Flatpak manifest and submitting releases for review.

### Prepare the submission [#prepare-the-submission]

Fork the [flathub repository](https://github.com/flathub/flathub) in your GitHub organization, clone it, and create a branch targeting the repository's `new-pr` branch:

```sh skip="store-tooling"
git clone git@github.com:<org>/flathub.git
cd flathub
git checkout -b my-app-submission -t new-pr
```

Create these files in the flathub directory:

* a metainfo file generated with the [AppStream web form](https://www.freedesktop.org/software/appstream/metainfocreator/#/), like [`com.pears.HelloPear.metainfo.xml`](https://github.com/holepunchto/hello-pear-electron/blob/main/flatpak/com.pears.HelloPear.metainfo.xml)
* a Flatpak YAML manifest, like [`com.pears.HelloPear.yml`](https://github.com/holepunchto/hello-pear-electron/blob/main/flatpak/com.pears.HelloPear.yml)

### Test the Flatpak locally [#test-the-flatpak-locally]

Install the Flatpak tools:

```sh skip="store-tooling"
sudo apt install flatpak
flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install flathub org.flatpak.Builder
```

In the project directory, build the app for Linux and serve the generated Flatpak artifacts over HTTP:

```sh skip="store-tooling"
python3 -m http.server --directory out/make/
```

In the `flatpak` directory, build and install the Flatpak:

```sh skip="store-tooling"
flatpak run --command=flathub-build org.flatpak.Builder --disable-rofiles-fuse com.pears.HelloPear.yml
flatpak install --user ./repo com.pears.HelloPear
```

Repeat the build command after making any changes to the manifest.

Launch the application from your desktop environment or run it from the CLI:

```sh skip="store-tooling"
flatpak run com.pears.HelloPear
```

Uninstall using:

```sh skip="store-tooling"
flatpak uninstall com.pears.HelloPear
rm -rf ~/.var/app/com.pears.HelloPear
```

If the builds take up too much disk space, clear the build files from the `flatpak` directory:

```sh skip="store-tooling"
rm -rf builddir repo .flatpak-builder
```

### Submit for review [#submit-for-review]

After confirming that the Flatpak works:

1. Upload the Flatpak artifacts to a publicly accessible location with versioned URLs, like [this site](https://static.keet.io/downloads/), and update the artifact links in the Flatpak YAML.
2. For verification, upload an empty file to your app website at `https://<app-website>/.well-known/org.flathub.VerifiedApps.txt`.
3. Open a PR on the [flathub repository](https://github.com/flathub/flathub) from your branch, like [this PR](https://github.com/flathub/flathub/pull/8716), and address the review comments.
4. Comment `bot, build` to test building the Flatpak on the Flathub CI.
5. Once the submission is accepted, the Flathub maintainers create a repository in the flathub organization from your submission branch, like [this repository](https://github.com/flathub/io.keet.Keet).
6. Log in to the [Flathub Developer Portal](https://flathub.org/en/developer-portal) to manage the app, and complete verification by copying the token from that page to `https://<app-website>/.well-known/org.flathub.VerifiedApps.txt`.
7. In a few hours the app should be available on Flathub, like [this app](https://flathub.org/en/apps/io.keet.Keet).

If the app doesn't show up on Flathub:

* If the Flathub bot opens an issue on the repository containing build errors, address it.
* If it's unrelated, comment `bot, retry` or open an issue in [Flathub](https://github.com/flathub/flathub/issues) for assistance from the maintainers.
* Follow the build status at [builds.flathub.org](https://builds.flathub.org); app-specific status is at `https://builds.flathub.org/status/<app-id>`.

### Automate new releases [#automate-new-releases]

To have the Flathub bot open PRs when new versions of the app are available on your website, follow the [external data checker guide](https://github.com/flathub-infra/flatpak-external-data-checker/#changes-to-flatpak-manifests) and configure it on the `type: archive` source, matching the format of your download site:

```yml skip="manifest-config"
x-checker-data:
  type: html
  url: https://static.keet.io/downloads/
  version-pattern: href="((?:\d+\.)+\d+)/"
  url-template: https://static.keet.io/downloads/$version/Keet-arm64-flatpak.tar.gz
```

Flathub's central external data checker runs as a GitHub Action on a cron schedule every 4 hours, so new releases can take up to that long to be picked up. To avoid the delay, opt out of the central workflow and add a **Check for updates** workflow to the app's Flathub repository, which you can trigger on demand from its GitHub Actions tab:

1. Add a workflow based on [this example](https://github.com/flathub/io.keet.Keet/blob/master/.github/workflows/update.yml), replacing the Flatpak YAML filename in its `args` with yours.
2. Add a [`flathub.json`](https://github.com/flathub/io.keet.Keet/blob/master/flathub.json) file that sets `"disable-external-data-checker": true` to opt out of the central checker.

## Snap [#snap]

Snap packages applications for Linux and distributes them through the Snap Store. This section covers preparing a Snap package, testing it locally, and publishing releases.

### Build and test the Snap [#build-and-test-the-snap]

Install the Snap tools:

```sh skip="store-tooling"
snap install snapcraft --classic
snap install lxd
sudo usermod -a -G lxd $USER
sudo lxd init --auto
```

In the project directory, build the app for Linux—this creates a `.snap` package in the `out/make` directory. Install it:

```sh skip="store-tooling"
snap install out/make/hellopear_1.0.0_arm64.snap --devmode
```

After making changes to the Snap configuration, rebuild the application and reinstall the generated Snap.

Launch the application from your desktop environment or run it from the CLI:

```sh skip="store-tooling"
hellopear
```

Uninstall using:

```sh skip="store-tooling"
snap remove hellopear
```

If the builds take up too much disk space, clean the build container:

```sh skip="store-tooling"
cd out
snapcraft clean
```

Refer to the [Electron Forge Snap Maker documentation](https://github.com/holepunchto/electron-forge-maker-snap) to configure the Snap.

### Publish to the Snap Store [#publish-to-the-snap-store]

After confirming that the Snap works:

1. Create your developer account at [login.ubuntu.com](https://login.ubuntu.com/) and log in.
2. Log in from your terminal with `snapcraft login`.
3. Register your Snap using [the name](https://documentation.ubuntu.com/snapcraft/9.0/how-to/publishing/register-a-snap/#name-your-snap) with `snapcraft register <snap-name>`, or `snapcraft register --private <snap-name>` for a private Snap.
4. Publish with `snapcraft upload --release=stable <my-snap>.snap`.
5. Check the release status with `snapcraft status <snap-name>`.

Snapcraft will guide you with the next steps if a release fails. Once released, the Snap is available on the Snap Store at `https://snapcraft.io/<snap-name>`:

```sh skip="store-tooling"
snap install <snap-name>
<snap-name>
```

### Automate Snap releases [#automate-snap-releases]

To publish from CI, first create a credentials file:

```sh skip="store-tooling"
snapcraft export-login <credentials-filename>
```

Set the contents of the file as a secret in your automation pipeline and authenticate Snap with:

```sh skip="store-tooling"
export SNAPCRAFT_STORE_CREDENTIALS=$(cat <credentials-filename>)
```

Upload a new Snap release to the desired channel (for example, `stable`):

```sh skip="store-tooling"
snapcraft upload <snap-name>.snap --release stable
```

## iOS [#ios]

`hello-pear-react-native` carries no App Store submission tooling—no bundled EAS or CI release workflow, and signing/provisioning are project-specific. This section covers the Pear-specific parts of getting a build to the App Store; the submission mechanics themselves are standard Expo/React Native tooling.

### Prepare the iOS submission [#prepare-the-ios-submission]

The `ios/` project is generated by `npx expo prebuild` and carries the [`pear-runtime-react-native`](/pear/reference/pear/mobile-boot-control) boot-control patch—regenerate with `--clean` before archiving if the plugin version changed. `app.json` checklist: `ios.bundleIdentifier` and icons, the same brand checklist as [Build the OTA payload](/pear/how-to/operate-an-app/manual-deployment/mobile#build-the-ota-payload-steps-34). `package.json` `version` drives `CFBundleShortVersionString` at prebuild—see [Version synchronization](/pear/reference/pear/mobile-boot-control#version-synchronization).

### Build and test (iOS) [#build-and-test-ios]

```sh skip="store-tooling"
npm run production:ios
```

Exercises the same release path the store binary will use, so boot-control and OTA selection can be verified before archiving. Archive from the generated `ios/` project with Xcode (**Product → Archive**), or via [EAS Build](https://docs.expo.dev/build/introduction/) if the project uses Expo's managed build service—EAS is **not** pre-wired by the `hello-pear-react-native` template.

<Callout type="warn">
  If you do use EAS Build: the worker bundle (`src/worker.bundle.js`) is generated and gitignored, so a fresh EAS checkout won't have one—the app builds and installs fine but has no worklet, the same silent-failure shape as a missing `upgrade` link. Cover it by hooking the bundling step into the [EAS build lifecycle](https://docs.expo.dev/build-reference/npm-hooks/):

  ```json skip="config-illustration"
  {
    "scripts": {
      "eas-build-post-install": "npm run bundle:bare"
    }
  }
  ```
</Callout>

### Submit for review (iOS) [#submit-for-review-ios]

Standard [App Store Connect](https://developer.apple.com/help/app-store-connect/) flow: upload the archive (Xcode Organizer or Transporter), complete the listing, submit.

Pear-specific timing: set `pear.json` `updates.minver` to this release's version *before* staging any OTA payload that depends on it, and remember [store review can take days](/pear/how-to/operate-an-app/manual-deployment/mobile#store-submissions)—a payload staged during that window must not require the unreleased native build.

### Automate (iOS, optional) [#automate-ios-optional]

No CI release workflow ships with the template. [EAS Submit](https://docs.expo.dev/submit/ios/) or [Fastlane](https://docs.fastlane.tools/) are the standard options if automating, configured the same way they would be for any Expo/React Native app—nothing Pear-specific to add.

## Android [#android]

### Prepare the Android submission [#prepare-the-android-submission]

The `android/` project is generated by `npx expo prebuild` and carries the boot-control patch to `MainApplication.kt`—regenerate with `--clean` before building if the plugin version changed. `app.json` checklist: `android.package`, `minSdkVersion` (29, set via `expo-build-properties`—see [Expo setup](/pear/reference/pear/mobile-boot-control#expo-setup)), and icons. `package.json` `version` drives `versionName` at prebuild.

### Build and test (Android) [#build-and-test-android]

```sh skip="store-tooling"
npm run production:android
```

Then a signed release build:

```sh skip="store-tooling"
cd android && ./gradlew bundleRelease
```

Or `eas build --platform android` on the managed build service—if you do, the same `eas-build-post-install` worker-bundle hook from [the iOS section above](#ios) applies here too; the worker bundle is gitignored regardless of platform.

### Submit for review (Android) [#submit-for-review-android]

Standard [Google Play Console](https://support.google.com/googleplay/android-developer/answer/9859152) flow: create the app listing, upload the `.aab`, submit. Same `minver`/timing caveat as iOS.

### Automate (Android, optional) [#automate-android-optional]

Same as iOS: [EAS Submit](https://docs.expo.dev/submit/android/) or Fastlane—not pre-wired by the template.

## See also [#see-also]

* [Build desktop distributables](/pear/how-to/operate-an-app/build-and-package/build-desktop-distributables)—produce the Linux artifacts these store flows package.
* [Deploy your application](/pear/how-to/operate-an-app/manual-deployment/deployment)—the peer-to-peer release flow that store installs update through.
* [Deploy your mobile application](/pear/how-to/operate-an-app/manual-deployment/mobile)—build the mobile OTA payload before submitting to the App Store or Play Store.
* [Pear Mobile OTA](/pear/reference/pear/mobile)—the `pear-mobile` API and the `minver` gate that store timing has to respect.
* [Distribute as a binary](/pear/how-to/operate-an-app/build-and-package/distribute-as-binary)—direct binary distribution without a store.
* [Pear OTA](/pear/reference/pear/runtime)—how store-installed apps keep updating over the air.
