Convert your Shopify store into a native mobile app (Android APK/AAB + iOS IPA) with a single command. No coding required.
- WebView-based native apps for Android (Java) and iOS (Swift)
- Splash screen with customizable logo and theme color
- Deep linking —
https://yourstore.comURLs open in-app - Pull-to-refresh, progress bar, offline detection with retry
- File upload support (camera + gallery on Android, document picker on iOS)
- Notifications — local reminders + optional FCM push notifications (Android) and APNs (iOS)
- One-command cloud build —
shopify2app buildhandles repo, CI, and artifact download - GitHub Actions CI/CD — builds are automated on every push
- Build outputs: Debug APK, signed Release APK, Release AAB (Play Store), iOS archive
npm install -g shopify2appOr run locally:
git clone https://github.com/mithun50/shopify-app.git
cd shopify-app
npm install# 1. Generate your app
shopify2app init --url https://mystore.myshopify.com --name "My Store" --color "#FF5733"
# 2. (Optional) Generate a signing keystore for release builds
shopify2app keystore
# 3. Build in the cloud (creates GitHub repo, runs CI, downloads APK + iOS archive)
shopify2app build
# That's it! Your APK is in ./builds/Or interactive setup:
shopify2app init # prompts for store URL, app name, etc.
shopify2app build # prompts for GitHub token, then builds automaticallyThis generates a complete project in output/ with Android + iOS source code and GitHub Actions workflows.
Initialize a new mobile app project.
| Option | Description |
|---|---|
-u, --url <url> |
Shopify store URL |
-n, --name <name> |
App display name |
-p, --package <id> |
Package name (e.g., com.mystore.app) |
-c, --color <hex> |
Theme color (e.g., #FF5733) |
-l, --logo <path> |
Splash screen logo image |
--fcm <path> |
Path to google-services.json for Firebase push notifications |
Set a custom app icon. Copies the image to all Android density buckets and iOS assets.
shopify2app icon ./my-icon.pngTip: Use a 1024x1024 PNG for best results.
Set or update the splash screen logo.
shopify2app splash ./my-logo.pngTip: Use a transparent PNG (e.g., 512x512) for best results.
View or update the current configuration.
# View config
shopify2app config
# Update values
shopify2app config --url https://newstore.com --color "#000000"Build your app in the cloud using GitHub Actions. This command automates the entire flow: creates a private GitHub repo, pushes your generated project, waits for CI builds to complete, and downloads the build artifacts locally.
# Interactive (prompts for GitHub token)
shopify2app build
# With token flag
shopify2app build --token ghp_xxxxxxxxxxxx
# Custom repo name and output directory
shopify2app build --token ghp_xxx --repo my-app --output ./my-builds
# Create a public repo instead of private
shopify2app build --token ghp_xxx --public| Option | Description |
|---|---|
-t, --token <token> |
GitHub personal access token (or set GITHUB_TOKEN env var) |
-r, --repo <name> |
Repository name (defaults to app name) |
-o, --output <path> |
Artifact download directory (default: ./builds/) |
--public |
Create a public repository (default: private) |
Token resolution order: --token flag → GITHUB_TOKEN env variable → saved config → interactive prompt.
What it does:
- Validates your project (
output/directory, workflows, and config must exist) - Authenticates with GitHub using your token
- Creates a private repo named after your app (or reuses an existing one)
- Restructures and pushes code so GitHub Actions can discover workflows
- Polls GitHub Actions every 15s until all builds complete (30 min timeout)
- Downloads and extracts build artifacts to your local output directory
How the push works — repo structure:
Your local output/ directory has workflows nested inside it (output/.github/workflows/), but GitHub Actions only discovers workflows at the repo root (.github/workflows/). The build command creates a staging directory that restructures the files:
Local: Pushed to GitHub:
output/ .github/
.github/workflows/ ──→ workflows/
build-android.yml build-android.yml
build-ios.yml build-ios.yml
android/ ──→ output/
ios/ android/...
ios/...
The workflow templates already reference ./output/android and ./output/ios as their working-directory, which matches this pushed structure. No template changes are needed — the build command handles the restructuring automatically.
If you modify workflow templates (templates/.github/workflows/), keep these path rules:
working-directory:must use./output/androidor./output/iospath:inupload-artifactmust useoutput/android/...oroutput/ios/...(no leading./)- These paths work because
output/is preserved as a subdirectory in the pushed repo
Build artifacts:
| Artifact | File | Description |
|---|---|---|
| Debug APK | AppName-debug.apk |
Unsigned debug build (always produced) |
| Release APK | AppName-release.apk |
Signed release (requires signing secrets) |
| Release AAB | AppName-release.aab |
Play Store bundle (requires signing secrets) |
| iOS Archive | AppName-ios.xcarchive.zip |
Xcode archive (unsigned, for re-signing) |
Creating a GitHub Token:
The token needs repo and workflow scopes to create repos and push workflow files.
- Go to GitHub Settings → Personal Access Tokens → Tokens (classic)
- Click Generate new token (classic)
- Select scopes:
repo(full) andworkflow - Copy the token — use it with
--tokenor setGITHUB_TOKENenv var
Note: Fine-grained tokens also work — grant
Read and writeaccess toContents,Actions, andAdministrationon the target repo.
Re-running builds:
Running shopify2app build again will detect the existing repo, force-push updated code, and trigger fresh builds. Previous build artifacts on GitHub are not affected.
Generate a persistent signing keystore for Android release builds. The keystore is saved to your config and automatically included in every shopify2app build — one keystore, consistent across all your projects.
# Generate a new keystore
shopify2app keystore
# View current keystore status
shopify2app keystore --show| Option | Description |
|---|---|
--show |
Show current keystore status |
What it does:
- Generates a 2048-bit RSA keystore using
keytool(requires JDK) - Saves it base64-encoded to
app.config.jsonwith a random 32-char password - On
shopify2app build, the keystore is automatically included in the repo'ssigning/directory - The GitHub Actions workflow detects it and uses it for release signing
Requirements: JDK must be installed (keytool command). Install with:
- Ubuntu/Debian:
sudo apt install default-jdk - macOS:
brew install openjdk - Termux:
pkg install openjdk-17
IMPORTANT: Back up your
app.config.json! If you lose the keystore, you cannot push updates to apps already published on the Play Store.
Configure push notifications.
# View notification status
shopify2app notifications
# Enable FCM push notifications
shopify2app notifications --fcm ./google-services.json
# Disable FCM (local notifications remain active)
shopify2app notifications --disable| Option | Description |
|---|---|
--fcm <path> |
Enable FCM with google-services.json |
--disable |
Disable FCM push notifications |
The generated app includes both local notifications and optional push notifications.
A "Welcome back" reminder is automatically scheduled 24 hours after the user opens the app. This works on both Android and iOS without any server setup.
To enable server-driven push notifications on Android:
- Create a Firebase project
- Add an Android app with your package name
- Download
google-services.json - Run:
shopify2app init --url https://mystore.com --name "My Store" --fcm ./google-services.jsonOr enable FCM on an existing project:
shopify2app notifications --fcm ./google-services.json
shopify2app init # regenerate projectWhen FCM is not configured:
- No Firebase dependencies are added to the build
- No FCM service is included in the manifest
- Local notifications still work
When FCM is enabled:
- Firebase BOM + Messaging are added to
build.gradle google-services.jsonis copied toapp/ShopifyFirebaseMessagingServicehandles incoming push messages- Notification taps open the app (optionally navigating to a URL via
urldata payload)
iOS uses native APNs (no Firebase SDK required). The app registers for remote notifications at launch. To send push notifications:
- Enable Push Notifications capability in your Apple Developer account
- Generate an APNs key or certificate
- Use your backend or a service to send notifications via APNs
Android (local): Install the debug APK, open the app, then wait 24h (or adjust the delay in MainActivity.java for testing).
Android (FCM): Use the Firebase Console > Cloud Messaging > Send test message.
iOS (local): Run on a device, open the app, notification fires after 24h.
iOS (remote): Requires a physical device and APNs configuration.
The generated project includes workflows that build automatically on push to main.
The workflow uses the first available signing method:
| Priority | Method | Setup |
|---|---|---|
| 1. Repo keystore | signing/keystore.jks in the repo |
Run shopify2app keystore before shopify2app build (recommended) |
| 2. GitHub secrets | KEYSTORE_BASE64 secret |
Add secrets manually in repo settings |
| 3. Auto-generated | Temporary keystore created during build | No setup needed (not for production) |
Recommended: Run shopify2app keystore once. It generates a persistent keystore saved in your config. Every shopify2app build automatically includes it — no manual secret setup required.
If you prefer managing secrets manually, add these to your GitHub repo (Settings > Secrets and variables > Actions):
| Secret | Description |
|---|---|
KEYSTORE_BASE64 |
Base64-encoded Android keystore file |
KEYSTORE_PASSWORD |
Keystore password |
KEY_ALIAS |
Key alias name |
KEY_PASSWORD |
Key password |
# Generate keystore manually
keytool -genkey -v -keystore release.jks -keyalg RSA -keysize 2048 -validity 10000 -alias myapp
# Base64 encode it
base64 -i release.jks | tr -d '\n'Copy the base64 output to the KEYSTORE_BASE64 secret.
Every build produces all three Android artifacts:
- Debug APK —
app-debugartifact (unsigned debug build) - Release APK —
app-releaseartifact (signed, direct install) - Release AAB —
app-release-bundleartifact (signed, Play Store upload) - iOS Archive —
ios-archiveartifact (unsigned, for re-signing)
On GitHub Release creation, signed APK and AAB are automatically attached.
- Configure signing secrets in GitHub (see above)
- Push to
mainor create a GitHub Release - Download the
app-release-bundleartifact (.aabfile) - Upload to Google Play Console > Your App > Production > Create new release
- Download the
ios-archiveartifact from GitHub Actions - Open in Xcode, re-sign with your distribution certificate
- Upload via Xcode Organizer or
altoolto App Store Connect
Note: iOS builds require code signing. The GitHub Actions workflow produces an unsigned archive that you re-sign locally with your Apple Developer certificate.
Set during init or update later:
shopify2app config --color "#1a1a2e"The theme color is applied to:
- Splash screen background
- Android status bar and progress bar
- iOS window tint color
- Placeholder app icon (until you set a custom one)
shopify2app icon ./icon-1024.pngCopies your icon to all required sizes for both platforms.
shopify2app splash ./logo.pngDisplayed centered on the splash screen above the app name. If no logo is provided, a default store icon is generated automatically (SVG design rasterized to PNG).
output/
.github/workflows/ # CI/CD workflows
.gitignore
android/ # Complete Android project (Java + Gradle)
app/src/main/
java/.../ # MainActivity, SplashActivity, NotificationHelper, NotificationReceiver
res/ # Layouts, icons, splash logo, themes
build.gradle
ios/ # Complete iOS project (Swift + Xcode)
ShopifyApp/ # AppDelegate, WebViewController, NotificationHelper, assets
ShopifyApp.xcodeproj/
Mithun Gowda B — mithungowda.b7411@gmail.com
MIT