Oh, and now I will share my actual config, which supports multiple bundle IDs and mobile server URLs. Took me awhile to figure out a good way to do this but I’m quite pleased now.
Directory structore
capacitor
├── Justfile
├── projects
│ ├── com.myapp.mobileapp
│ │ └── ios
│ ├── com.myapp.mobilebeta
│ │ └── ios
│ └── com.myapp.mobiledev
│ └── ios
├── WALS-shim.html
└── www-dist
├── 577bf1c44c857cea41071ab15397ec6f6c06d8a2.js
├── favicon.ico
├── [other files in /public]
└── index.html
capacitor.config.ts
import type { CapacitorConfig } from '@capacitor/cli';
const isProd = process.env.ROOT_URL === 'https://myapp.com';
const isBeta = process.env.ROOT_URL === 'https://beta.myapp.com';
const bundleId = isProd
? 'com.myapp.mobileapp'
: isBeta
? 'com.myapp.mobilebeta'
: 'com.myapp.mobiledev';
const appName = isProd ? 'My App' : isBeta ? 'MyApp Beta' : 'MyApp Dev';
const config: CapacitorConfig = {
appId: bundleId,
appName,
webDir: 'capacitor/www-dist',
loggingBehavior: 'none', // Capacitor logs are too noisy
ios: {
path: `capacitor/projects/${bundleId}/ios`,
},
android: {
path: `capacitor/projects/${bundleId}/android`,
},
backgroundColor: '#265C86',
plugins: {
'SplashScreen': {
'launchAutoHide': false,
'launchFadeOutDuration': 300,
},
},
};
export default config;
Justfile
Note: This is from before I started using my
@banjerluke/capacitor-meteor-webappplugin, but the idea is the same.
# List all commands as default command
list:
@just --list --unsorted
# Build iOS beta app
[group('mobile')]
build-ios-beta:
@just build-ios com.strummachine.mobilebeta https://beta.strummachine.com "SM Beta"
# Build iOS dev app
[group('mobile')]
build-ios-dev:
@just build-ios com.strummachine.mobiledev https://3k.fdf.sh "SM Dev"
# Build iOS app
[group('mobile')]
build-ios-prod:
@just build-ios com.strummachine.mobileapp https://strummachine.com "Strum Machine"
# Build iOS app
[group('mobile')]
build-ios bundle_id='com.strummachine.mobileapp' root_url='https://strummachine.com' display_name='Strum Machine':
#!/usr/bin/env sh
set -euxo pipefail
cleanup() {
kill $SERVER_PID 2>/dev/null || true
}
trap cleanup SIGINT SIGTERM # cleanup on Ctrl+C
export PORT=3333
export ROOT_URL='{{root_url}}'
# Version number for mobile app build
export MOBILE_VERSION="1.$(node -p "JSON.parse(require('fs').readFileSync('package.json', 'utf8')).version.replace(/^(\d+\.\d+).*/, '\$1')")"
# Dummy API key to boot server
export STRIPE_API_KEY='sk_test_asdf'
# Need a valid MongoDB connection to boot server
export MONGO_URL=$(sops exec-env .deployment/secrets-qa.sops.env 'echo $MONGO_URL')
rm -rf {{build_dir}}
meteor build --directory {{build_dir}}/ --headless --server-only --mobile-settings ".deployment/mobile-settings.json" --server $ROOT_URL
rm -rf capacitor/www-dist || exit 1
mkdir -p capacitor/www-dist
cp -r {{build_dir}}/bundle/programs/web.cordova/*.js capacitor/www-dist || exit 1
cp -r {{build_dir}}/bundle/programs/web.cordova/app/* capacitor/www-dist/ || exit 1
rm -rf capacitor/www-dist/**/*.map || exit 1 # remove sourcemaps
sed -i '' "s|WebAppLocalServer\.onError(function(e){console\.error(e)})||g" capacitor/www-dist/*.js || exit 1
(cd {{build_dir}}/bundle/programs/server && npm install --no-audit --loglevel error --omit=dev)
# Start server in background and capture PID
node {{build_dir}}/bundle/main.js &
export SERVER_PID=$!
sleep 3
# Fetch index.html and patch cordova paths
curl -f --connect-timeout 20 'http://localhost:3333/__cordova/index.html' | \
sed -e 's|/__cordova/client/|/client/|g' -e 's|/__cordova/|/|g' \
> capacitor/www-dist/index.html
# Sync www files to Capacitor
npx cap sync
# Sync version number and bump build number
(cd capacitor/projects/{{bundle_id}}/ios/App/App.xcodeproj/; \
sed -i '' "s/MARKETING_VERSION = [^;]*;/MARKETING_VERSION = $MOBILE_VERSION;/g" project.pbxproj; \
awk '/CURRENT_PROJECT_VERSION = / { match($0, /[0-9]+/); gsub(/[0-9]+/, substr($0, RSTART, RLENGTH)+1) } 1' project.pbxproj > temp && mv temp project.pbxproj; \
)
# Open Xcode
npx cap open ios
cleanup
Now I run just build-ios-dev, just build-ios-beta, or just build-ios-prod and get the appropriate app built.