diff --git a/codemagic.yaml b/codemagic.yaml
new file mode 100644
index 0000000..4214d36
--- /dev/null
+++ b/codemagic.yaml
@@ -0,0 +1,74 @@
+# Codemagic CI/CD configuration for OOTT.
+#
+# Builds the Flutter iOS app on a cloud macOS machine and publishes it to
+# TestFlight. No local Mac is required.
+#
+# Triggered automatically by the `vX.Y.Z` git tags that `release.sh` pushes,
+# so cutting a release also ships a new TestFlight build. Can also be run
+# on demand via the "Run build" button in the Codemagic UI.
+#
+# SECRETS: none live in this repo. The App Store Connect API key (.p8, Key ID,
+# Issuer ID) is stored in Codemagic's encrypted credential store and referenced
+# here only by integration name. Signing certificates and provisioning profiles
+# are fetched on the build machine at build time and discarded with it.
+#
+# One-time setup required in the Codemagic UI before the first build:
+# 1. Add an App Store Connect integration (upload the .p8, Key ID, Issuer ID)
+# and put its name in `integrations.app_store_connect` below.
+# 2. Create an environment variable group named `appstore_connect` containing
+# APP_STORE_APP_ID = the numeric Apple ID of the app record in
+# App Store Connect.
+
+workflows:
+ ios-testflight:
+ name: iOS TestFlight
+ instance_type: mac_mini_m2
+ max_build_duration: 60
+ working_directory: frontend
+ integrations:
+ # Replace with the name of the App Store Connect integration configured
+ # in the Codemagic UI.
+ app_store_connect: OOTT App Store Connect
+ environment:
+ flutter: stable
+ xcode: latest
+ cocoapods: default
+ groups:
+ - appstore_connect # provides APP_STORE_APP_ID (not a secret)
+ vars:
+ BUNDLE_ID: "net.oott-security.app" # not secret; ships inside every app
+ triggering:
+ events:
+ - tag
+ tag_patterns:
+ - pattern: "v*" # matches the vX.Y.Z tags release.sh pushes
+ include: true
+ scripts:
+ - name: Set up automatic code signing
+ script: |
+ keychain initialize
+ app-store-connect fetch-signing-files "$BUNDLE_ID" \
+ --type IOS_APP_STORE \
+ --create
+ keychain add-certificates
+ xcode-project use-profiles
+ - name: Get Flutter packages
+ script: flutter pub get
+ - name: Run frontend tests
+ script: flutter test
+ - name: Build IPA
+ script: |
+ # Each TestFlight upload needs a unique, increasing build number.
+ BUILD_NUMBER=$(($(app-store-connect get-latest-testflight-build-number "$APP_STORE_APP_ID") + 1))
+ flutter build ipa --release \
+ --build-number=$BUILD_NUMBER \
+ --export-options-plist=/Users/builder/export_options.plist
+ artifacts:
+ - build/ios/ipa/*.ipa
+ - /tmp/xcodebuild_logs/*.log
+ publishing:
+ app_store_connect:
+ auth: integration
+ submit_to_testflight: true
+ beta_groups:
+ - Internal Testers
diff --git a/frontend/ios/Runner.xcodeproj/project.pbxproj b/frontend/ios/Runner.xcodeproj/project.pbxproj
index dc26eb9..ade41ec 100644
--- a/frontend/ios/Runner.xcodeproj/project.pbxproj
+++ b/frontend/ios/Runner.xcodeproj/project.pbxproj
@@ -368,7 +368,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend;
+ PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@@ -384,7 +384,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend.RunnerTests;
+ PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app.RunnerTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -401,7 +401,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend.RunnerTests;
+ PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app.RunnerTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -416,7 +416,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend.RunnerTests;
+ PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app.RunnerTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -547,7 +547,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend;
+ PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -569,7 +569,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.example.frontend;
+ PRODUCT_BUNDLE_IDENTIFIER = "net.oott-security.app";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
diff --git a/frontend/ios/Runner/Info.plist b/frontend/ios/Runner/Info.plist
index 848830a..b110363 100644
--- a/frontend/ios/Runner/Info.plist
+++ b/frontend/ios/Runner/Info.plist
@@ -5,7 +5,7 @@
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleDisplayName
- Frontend
+ OOTT
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier