【iOS】【Flutter】Github Actionsを使用してipaファイルを手動署名でビルドする
こんにちは。リテールアプリ共創部のYahiroです。
今回は、以下の記事の追補版です。
上記の記事は、自動署名でAppStoreConnectに配信までを行う方法を解説しています。
今回は、自動署名ではなく、手動署名でipaファイルを作成するところまでを記載していきます。
この記事でわかること
- Flutter/Dartで実装した、iOSアプリのipaの作成までを手動署名で行う方法
準備
実際に準備していきましょう。
iOS Distribution証明書の取得
iOS Distribution証明書の.p12ファイルは、証明書登録作業を行ったMacでのみ取得可能です。
作業を行っているPCが、登録作業を行ったMacである場合、キーチェーンから書き出しが可能です。
それ以外のMacで作業を行っている場合は、作業を行った人から.p12ファイルを連携してもらってください。
プロビジョニングファイルの取得
続いてプロビジョニングファイルの取得を行います。
以下にログインしてください。
次に、「証明書、ID、プロファイル」から「証明書(英語)」を選択してください。

Profilesを選択し、TYPEが「App Store」になっているものを選択し、押下してください。

「Download」を押下してください。

Github Secretsへの登録
Secretsに各種証明書、パスワードを登録していきます。
その前に、前項で取得したiOS Distribution証明書とプロビジョニングファイルを、それぞれBase64に変換しましょう。
ターミナルで以下を実行:
# 証明書をBase64に変換(クリップボードにコピー)
base64 -i your_certificate.p12 | pbcopy
# プロビジョニングプロファイルをBase64に変換
base64 -i your_profile.mobileprovision | pbcopy
クリップボードにコピーできたら、以下をGithub Secretsに設定してください。
| Secrets名 | 内容 |
|---|---|
| IOS_CERTIFICATE_BASE64 | .p12のBase64文字列 |
| IOS_CERTIFICATE_PASSWORD | .p12エクスポート時のパスワード |
| IOS_PROVISIONING_PROFILE_BASE64 | .mobileprovisionのBase64文字列 |
| KEYCHAIN_PASSWORD | 任意の文字列(例:Classmethod-2026-GithubActions) |
ExportOptions.plistの設置
ExportOptions.plistの内容になります。これは、XCode上でArchiveを行なって生成する方法もありますが、今回は下記の内容を値に記載します。
ワークフローではpathをios/ExportOptions.plistとしています。
「YOUR_TEAM_ID」の部分はApple Developer Programの「メンバーシップの詳細」から確認して、置き換えてください。
「YOUR_BUNDLE_ID」には、アプリのバンドルIDに置き換えてください。
「PROVISIONING_PROFILE_NAME」は証明書ダウンロード時のProfilesページの「NAME」の値に置き換えてください。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
<key>signingStyle</key>
<string>manual</string>
<key>provisioningProfiles</key>
<dict>
<key>YOUR_BUNDLE_ID</key>
<string>PROVISIONING_PROFILE_NAME</string>
</dict>
</dict>
</plist>
ワークフローの設定
Secretsの設定ができたらワークフローを設定していきます。
以下がサンプルとなります。
なお、ビルドコマンドやFlutterバージョンなどは環境ごとに適宜設定してください。
name: iOS IPA Build
on:
workflow_dispatch:
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: "3.29.0"
- name: Setup packages
run: |
flutter pub get
dart run build_runner build -d
- name: Install Apple certificate and provisioning profile
env:
IOS_CERTIFICATE_BASE64: ${{ secrets.IOS_CERTIFICATE_BASE64 }}
IOS_CERTIFICATE_PASSWORD: ${{ secrets.IOS_CERTIFICATE_PASSWORD }}
IOS_PROVISIONING_PROFILE_BASE64: ${{ secrets.IOS_PROVISIONING_PROFILE_BASE64 }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# Create variables
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
# Import certificate and provisioning profile from secrets
echo -n "$IOS_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
echo -n "$IOS_PROVISIONING_PROFILE_BASE64" | base64 --decode -o $PP_PATH
# Create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# Import certificate to keychain
security import $CERTIFICATE_PATH -P "$IOS_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
# Apply provisioning profile
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
- name: Build IPA
run: |
flutter build ipa --export-options-plist ios/ExportOptions.plist
- name: Upload IPA artifact
uses: actions/upload-artifact@v4
with:
name: app.ipa
path: build/ios/ipa/*.ipa
retention-days: 30
- name: Clean up keychain
if: always()
run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true
AppStoreConnectへのアップロード
前述の記事では、コマンドで直接アップロードしていましたが、以下のApple公式アプリ「Transporter」を使用してアップロードすることが可能です。
おわりに
今回は手動署名での方法を検証しました。
自動と手動をそれぞれ、プロジェクトによってうまく使い分けていきたいと思います。






