diff --git a/.github/workflows/publish_ios_appstore.yml b/.github/workflows/publish_ios_appstore.yml index 613a4c57..d5315c3a 100644 --- a/.github/workflows/publish_ios_appstore.yml +++ b/.github/workflows/publish_ios_appstore.yml @@ -1,5 +1,7 @@ name: Publish iOS App +# kappmaker-workflow-version: 3 + # Builds and ships the iOS app on a GitHub macOS runner, so no Mac is needed # locally. Signing certificates are created on the runner by fastlane `match` # from your App Store Connect API key — nothing has to be exported from a Mac. diff --git a/MobileApp/fastlane/Fastfile b/MobileApp/fastlane/Fastfile index a4c1b49b..4a9629a2 100644 --- a/MobileApp/fastlane/Fastfile +++ b/MobileApp/fastlane/Fastfile @@ -227,7 +227,6 @@ platform :ios do submit_for_review = options[:submit_for_review].to_s == "true" upload_metadata = options[:upload_metadata].to_s == "true" upload_screenshots = options[:upload_screenshots].to_s == "true" - bump_build = options[:bump_build].to_s != "false" api_key = app_store_connect_api_key( key_id: ENV.fetch("ASC_KEY_ID"), @@ -239,22 +238,6 @@ platform :ios do setup_ci if ENV["CI"] - # Apple rejects an already-seen build number, and CI builds from a clean - # checkout — so the number in git never advances on its own. Take whatever - # TestFlight has already seen and go one past it. This is the CI equivalent - # of running `kappmaker update-version` before publishing locally. - if bump_build - latest = latest_testflight_build_number( - api_key: api_key, - app_identifier: bundle_id, - initial_build_number: 0 - ) rescue 0 - increment_build_number( - build_number: latest.to_i + 1, - xcodeproj: "iosApp/iosApp.xcodeproj" - ) - UI.message("Build number set to #{latest.to_i + 1}") - end # readonly:false so the FIRST run can create and store the certificate. Later # runs find it already there and reuse it. @@ -267,6 +250,31 @@ platform :ios do keychain_password: ENV["MATCH_KEYCHAIN_PASSWORD"] ) + # match publishes what it installed through these env vars. + profile_name = ENV["sigh_#{bundle_id}_appstore_profile-name"] + team_id = ENV["sigh_#{bundle_id}_appstore_team-id"] + UI.user_error!("match did not install a profile for #{bundle_id}") if profile_name.to_s.empty? + + # Signing must be set on the APP TARGET, and nowhere else. + # + # Through xcargs the settings hit EVERY target, and the Swift Package + # dependencies (Firebase, GoogleUtilities, nanopb, promises...) reject a + # provisioning profile outright — "does not support provisioning profiles". + # This action edits the pbxproj for the named target only. + # + # It also has to be manual: left on automatic, Xcode hunts for an iOS App + # DEVELOPMENT profile and fails, because match installed an App Store one. + # The project ships no DEVELOPMENT_TEAM either, so team_id comes from match. + update_code_signing_settings( + path: "iosApp/iosApp.xcodeproj", + use_automatic_signing: false, + team_id: team_id, + code_sign_identity: "Apple Distribution", + profile_name: profile_name, + targets: ["iosApp"], + build_configurations: ["Release"] + ) + build_app( scheme: "iosApp", project: "iosApp/iosApp.xcodeproj", @@ -275,9 +283,10 @@ platform :ios do silent: false, output_name: "iosApp", output_directory: output_dir, - # Explicitly manual: match already installed the profile, and letting Xcode - # "help" here is what causes the certificate churn described above. - xcargs: "-allowProvisioningUpdates NO" + export_options: { + signingStyle: "manual", + provisioningProfiles: { bundle_id => profile_name } + } ) ipa_path = File.join(output_dir, "iosApp.ipa") @@ -309,5 +318,4 @@ platform :ios do UI.success("Uploaded to TestFlight.") end end - end