From 897b3b9425ea4194f48e9010897b53ebd5ad4ecc Mon Sep 17 00:00:00 2001 From: opficdev Date: Fri, 1 May 2026 21:57:03 +0900 Subject: [PATCH 1/3] =?UTF-8?q?test:=20=EC=9C=84=EC=A0=AF=20identfier?= =?UTF-8?q?=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=95=98=EC=97=AC=20=EC=9C=84?= =?UTF-8?q?=EC=A0=AF=EB=8F=84=20=EB=B0=B0=ED=8F=AC=20=EA=B0=80=EB=8A=A5?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastlane/Fastfile | 38 +++++++++++++++++++++++++------------- fastlane/Matchfile | 5 ++++- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 65c5eacc..b7a5c866 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -1,6 +1,9 @@ XCODE_PROJ = "DevLog.xcodeproj" APP_IDENTIFIER = "opfic.DevLog" +WIDGET_IDENTIFIER = "opfic.DevLog.DevLogWidget" +APP_IDENTIFIERS = [APP_IDENTIFIER, WIDGET_IDENTIFIER] TARGET_NAME = "DevLog" +WIDGET_TARGET_NAME = "DevLogWidgetExtension" TESTFLIGHT_BUILD_OUTPUT_DIRECTORY = File.expand_path("testflight_build", __dir__) TESTFLIGHT_IPA_OUTPUT_PATH = File.join(TESTFLIGHT_BUILD_OUTPUT_DIRECTORY, "#{TARGET_NAME}.ipa") @@ -76,23 +79,32 @@ platform :ios do match( api_key: api_key, type: "appstore", + app_identifier: APP_IDENTIFIERS, readonly: ENV["CI"] == "true" ) if ENV["CI"] == "true" - provisioning_profile_specifier = lane_context[SharedValues::MATCH_PROVISIONING_PROFILE_MAPPING][APP_IDENTIFIER].to_s - UI.user_error!("Missing App Store provisioning profile mapping for #{APP_IDENTIFIER}") if provisioning_profile_specifier.empty? - - update_code_signing_settings( - use_automatic_signing: false, - path: XCODE_PROJ, - sdk: "iphoneos*", - team_id: ENV["APP_STORE_TEAM_ID"], - targets: [TARGET_NAME], - build_configurations: ["Release"], - code_sign_identity: "Apple Distribution", - profile_name: provisioning_profile_specifier - ) + profile_mapping = lane_context[SharedValues::MATCH_PROVISIONING_PROFILE_MAPPING] + signing_targets = { + TARGET_NAME => APP_IDENTIFIER, + WIDGET_TARGET_NAME => WIDGET_IDENTIFIER + } + + signing_targets.each do |target_name, app_identifier| + provisioning_profile_specifier = profile_mapping[app_identifier].to_s + UI.user_error!("Missing App Store provisioning profile mapping for #{app_identifier}") if provisioning_profile_specifier.empty? + + update_code_signing_settings( + use_automatic_signing: false, + path: XCODE_PROJ, + sdk: "iphoneos*", + team_id: ENV["APP_STORE_TEAM_ID"], + targets: [target_name], + build_configurations: ["Release"], + code_sign_identity: "Apple Distribution", + profile_name: provisioning_profile_specifier + ) + end end build_app( diff --git a/fastlane/Matchfile b/fastlane/Matchfile index 8787d38d..c2577129 100644 --- a/fastlane/Matchfile +++ b/fastlane/Matchfile @@ -3,7 +3,10 @@ git_url(ENV["MATCH_GIT_URL"]) storage_mode("git") git_branch("main") type("appstore") -app_identifier(["opfic.DevLog"]) +app_identifier([ + "opfic.DevLog", + "opfic.DevLog.DevLogWidget" +]) team_id(ENV["APP_STORE_TEAM_ID"]) readonly(ENV["CI"] == "true") From eeb32455f519550cd07d3a7342033a8d5cc83aa4 Mon Sep 17 00:00:00 2001 From: opficdev Date: Fri, 1 May 2026 22:10:00 +0900 Subject: [PATCH 2/3] =?UTF-8?q?ci:=20=EC=9C=84=EC=A0=AF=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=8C=8C=EC=9D=BC=20=EB=8F=99=EA=B8=B0=ED=99=94=20?= =?UTF-8?q?=EC=9B=8C=ED=81=AC=ED=94=8C=EB=A1=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/sync-code-signing.yml | 42 +++++++++++++++++++++++++ fastlane/Fastfile | 12 +++++++ 2 files changed, 54 insertions(+) create mode 100644 .github/workflows/sync-code-signing.yml diff --git a/.github/workflows/sync-code-signing.yml b/.github/workflows/sync-code-signing.yml new file mode 100644 index 00000000..08ef8a09 --- /dev/null +++ b/.github/workflows/sync-code-signing.yml @@ -0,0 +1,42 @@ +name: iOS Code Signing + +on: + workflow_dispatch: + +env: + RUBY_VERSION: "3.2" + APP_STORE_TEAM_ID: ${{ secrets.APP_STORE_TEAM_ID }} + ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }} + ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }} + ASC_KEY_PATH: fastlane/AuthKey.p8 + SPACESHIP_CONNECT_API_IN_HOUSE: "false" + MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }} + MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} + MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} + +permissions: + contents: read + +jobs: + sync-appstore-profiles: + runs-on: macos-latest + timeout-minutes: 20 + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + ruby-version: ${{ env.RUBY_VERSION }} + + - name: Write App Store Connect API key + env: + ASC_KEY_CONTENT: ${{ secrets.ASC_KEY_CONTENT }} + run: | + printf '%s' "$ASC_KEY_CONTENT" | base64 -D > "$ASC_KEY_PATH" + + - name: Sync App Store profiles + run: bundle exec fastlane sync_appstore_profiles diff --git a/fastlane/Fastfile b/fastlane/Fastfile index b7a5c866..928c3fc9 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -129,6 +129,18 @@ platform :ios do build_for_store end + lane :sync_appstore_profiles do + api_key = asc_api_key + + match( + api_key: api_key, + type: "appstore", + app_identifier: APP_IDENTIFIERS, + force: true, + readonly: false + ) + end + lane :upload_testflight_build do api_key = asc_api_key # lane_context는 같은 fastlane 실행 내에서만 유지되므로, 별도 CI step에서는 고정 ipa 경로를 사용한다. From a33c9cc6ce6fb26932dac74b6398abd051e92fbe Mon Sep 17 00:00:00 2001 From: opficdev Date: Fri, 1 May 2026 22:20:13 +0900 Subject: [PATCH 3/3] =?UTF-8?q?ci:=20=ED=94=84=EB=A1=9C=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=20=EA=B0=95=EC=A0=9C=20=EA=B0=B1=EC=8B=A0=20=EC=98=B5=EC=85=98?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/sync-code-signing.yml | 10 ++++++++++ fastlane/Fastfile | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sync-code-signing.yml b/.github/workflows/sync-code-signing.yml index 08ef8a09..616b9d76 100644 --- a/.github/workflows/sync-code-signing.yml +++ b/.github/workflows/sync-code-signing.yml @@ -2,6 +2,15 @@ name: iOS Code Signing on: workflow_dispatch: + inputs: + force: + description: Force regenerate profiles + required: true + default: "true" + type: choice + options: + - "true" + - "false" env: RUBY_VERSION: "3.2" @@ -13,6 +22,7 @@ env: MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }} MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} + MATCH_FORCE: ${{ inputs.force }} permissions: contents: read diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 928c3fc9..75b16e5e 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -131,12 +131,13 @@ platform :ios do lane :sync_appstore_profiles do api_key = asc_api_key + match_force = ENV.fetch("MATCH_FORCE", "false") == "true" match( api_key: api_key, type: "appstore", app_identifier: APP_IDENTIFIERS, - force: true, + force: match_force, readonly: false ) end