Open8

Flutter練習|最短最速でiOS,Androidストアに出す

oo

経験

  • FlutterでiOS,Android向けにモバイルアプリ開発&リリース 1回成功
    • ごくごく簡単小さな時計アプリ

背景

  • Flutterのビルド&リリースの手順を効率化&人為的ミス低減のためにCodeMagicを導入しようかとチャレンジしていたが、数日かけてできなかったので諦める。

目的

  • その代わりに、Xcode,AndroidStudioを使用した一番原始的だけど知見があベンダーロックインされない方法でビルド&リリースをたくさん試行して経験値を貯める

ゴール

  • Flutterで作ったアプリをiOS,Androidストアに提出し、テストアプリを実端末に入れる

内容

  1. flutter createで作られた初期アプリをiOS,Androidのリリース用にビルドする。
  2. ビルドデータをiOS,Android両ストアにテスト用として提出
  3. テストリンクから実端末にアプリをインストールする。

記録

  • その過程をZennのスクラップ、またはローカルのメモに残しながら行い、記録と記憶に残す
oo

作戦

  • AIに聞きながら進めるか、自分のメモをもとに進めるか
  • Claude3.5 sonnetに聞きながら行ってみる。
oo

1. Flutterプロジェクトの作成とGitHubへのプッシュ

  • 今回の要件はiOS,Android用のモバイルアプリのみに限定する
  • iOSとAndroidでバンドル IDに関しての命名規則が異なるので、本書では以下のように俺ルールをつける←ここで決めた
    • バンドルID
      • ドメイン部分:jp.co.caen
      • じゃない部分:すべて小文字で繋げる (例 fluttertestproject )
    • SKU (iOSアプリ管理用)
      • JpCoCaenFluttertestproject(パスカルケース。ドメインじゃない部分は一つの単語にしちゃう)
  1. ターミナルから以下のコマンドを打ち、Flutterプロジェクトを作成
mkdir fluttertestproject
cd fluttertestproject
flutter create --org jp.co.caen --platforms=android,ios .
  1. Githubで新しいレポジトリを作成
    flutter_test_project アンダーバーで繋げる
    Dart でgitignoreテンプレートを適応

  2. ローカルのプロジェクトをGitHubにプッシュ

git init
git add .
git commit -m "Initial commit"
git remote add origin [https://github.com/YOURSELF_NAME/FLUTTER_TEST_REPOSITORY.git]
git push origin main -f
oo

アプリの基本情報の設定

アプリ表示名の変更

  • iOS: ios/Runner/Info.plist内のCFBundleDisplayNameを編集。
<key>CFBundleDisplayName</key>
<!-- <string>Fluttertestproject</string> -->
<string>アプリ表示名</string>
  • Android: android/app/src/main/AndroidManifest.xml内のandroid:labelを編集。
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:label="fluttertestproject" <- 「アプリ表示名」に差し替え
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"

アプリ画像

飛ばす

スプラッシュ画像

飛ばす

oo

2. iOS固有の設定

Apple DeveloperサイトでバンドルID(App Identifier)の登録

  1. Apple Developerサイトの「Certificates, Identifiers & Profiles」ページを開く(https://developer.apple.com/account/resources/identifiers/list)


2. 「Certificates, Identifiers & Profiles」ページ中の「Identifiers」タブを選択。「+」ボタンを押す。


3. 「Register a new identifier」ページにて、「App IDs」を選択し、「Continue」をクリック


4. 同じく「Register a new identifier」ページにて、「Select a type」から「App」を選択し、「Continue」をクリック


5. 「Register an App ID」ページにて、「Description」と「 Bundle ID 」を入力


5. 内容確認画面が表示されるので、「Register」をクリック。

Xcodeでのプロジェクト設定

  1. Xcodeでプロジェクトを開く

    open ios/Runner.xcworkspace
    

  1. Signing & Capabilities タブの設定
  • Signing: Automatically manage signing にチェック
  • Team: 自分のApple Developerアカウントを選択
  • Bundle Identifier: jp.co.caen.fluttertestproject(可変部分)
  1. General タブの設定
  • 変更が必要な項目
    • 「Identity」
      • Version:アプリのバージョン番号。pubspec.yamlで設定したバージョンと一致させる必要があります。
      • Build:アプリのビルド番号。pubspec.yamlのバージョン情報と一致させます。
      • App Category: アプリのカテゴリー
  • そのままで構わない項目
    • 「Minumum Deployments」
      • iOS:アプリがサポートする最低iOSバージョン。(知見がないので、初期値のままにしてしまう)
    • 「Identity」
      • Display Name: アプリの表示名(ただし、空白のままならiOSは自動的にInfo.plist内のCFBundleDisplayNameを使用して、アプリの名前を表示する。)
      • Bundle Identifier: バンドルID。適切な設定でflutter createしていれば、そのままでかまわない。
    • 「App Icons and Launch Screen」
      • App Icon: アプリのアイコンセットを指定する項目(ただし、空白のままでも、flutter_launcher_iconsパッケージを使用している場合、アイコンは自動的に設定されるので編集不要)
      • App Icon Source: すべての必要なアプリアイコンのサイズ(iOSの様々なデバイスや解像度に対応したアイコン)が含まれているかどうかを確認される選択項目。デフォルトはオフだけど、オンにしてもいい。オンが推奨(だけど認知負荷低減のためにオフのままにする)
      • Launch Screen File: スプラッシュスクリーンを指定( ただし、空白のままでも、flutter_native_splash パッケージを使用している場合は、スプラッシュスクリーンが自動的に設定されるため編集不要。)
oo

TIPS集

  • XcodeのGeneralタブで定義するバージョンやビルド番号は、Build Settingsタブにあるバージョンやビルド番号と同期している。
  • XcodeのInfoタブは、コードのInfo.plistと同期している。どちらを編集しても問題ないので、Info.plistを編集するようにする。
  • Build Phasesタブとは?Xcodeでアプリをビルドする際の各ステップを管理するタブ。ビルドの順序や追加のスクリプト、リソースの管理などを指定する。
  • Build PhasesタブのThin binaryという項目とは?アプリのバイナリファイルから不要なアーキテクチャに対応するコードを取り除いて軽量化するプロセス。圧縮とは異なる。難しくよくわからない。
oo

3. Android固有の設定

3.1. AndroidManifest.xmlの編集

android/app/src/main/AndroidManifest.xml を編集する。

  1. アプリ名の変更
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:label="デバイス上に表示されるアプリの表示名" <!-- 可変部分 -->
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">

3.2. キーストアの設定

  1. key.properties の作成
    android/key.propertiesファイルを作成。(というか別のアプリプロジェクトからコピペ)
storeFile=/フルパス/keystore.jks
storePassword=your_store_password
keyAlias=key
keyPassword=your_key_password

3.3. build.gradleの編集

android/app/build.gradle に以下の設定を追加。というか、最終的にこれコピペしろを後で貼る。

  1. キーストア情報の読み込み
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
  1. signingConfigsの設定
android {
    ...
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
            storePassword keystoreProperties['storePassword']
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release // 初期値がdebugになっているので必ず変更
            minifyEnabled true // リリースビルドでのコード縮小(必要に応じて変更)
            shrinkResources false
            // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // ProGuardを使用する場合
            ndk {
                debugSymbolLevel 'FULL' // デバッグシンボルの生成を有効にする
            }
        }
    }
}
  1. アプリのバージョン情報の設定
defaultConfig {
    applicationId "jp.co.caen.fluttertestproject" // 可変部分
    minSdkVersion 21
    targetSdkVersion 33
    versionCode 1 // 可変部分
    versionName "1.0.0" // 可変部分
    ...
}

3.3.A. build.gradleのテンプレ

これをコピペして可変項目を書き換える。

// すべてのサブプロジェクト/モジュールに共通の構成オプションを追加できるトップレベルのビルドファイル。
plugins {
    id "com.android.application"
    id "kotlin-android"
    // Flutter Gradleプラグインは、AndroidとKotlinのGradleプラグインの後に適用する必要があります。
    id "dev.flutter.flutter-gradle-plugin"
}

// key.propertiesファイルが存在する場合、そのファイルからkeystoreのプロパティをロードします。
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}

android {
    // **変数部分**: アプリのパッケージ名(逆ドメイン名表記)に置き換えてください。
    namespace = "あなたのアプリのバンドルID"

    compileSdk = flutter.compileSdkVersion

    // **オプション**: アプリがネイティブコードを使用する場合、NDKバージョンを指定します。
    ndkVersion = flutter.ndkVersion

    defaultConfig {
        // **変数部分**: アプリのパッケージ名(逆ドメイン名表記)に置き換えてください。
        applicationId = "あなたのアプリのバンドルID"

        minSdk = flutter.minSdkVersion
        targetSdk = flutter.targetSdkVersion

        versionCode flutter.versionCode.toInteger()
        versionName flutter.versionName

        // **オプション**: 必要に応じてアーキテクチャを指定します。
        // ndk {
        //     abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
        // }
    }

    signingConfigs {
        // リリース署名構成を設定します。
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
            storePassword keystoreProperties['storePassword']
        }
    }

    buildTypes {
        release {
            // どのキーストアでアプリに署名するかを指定するための設定。
            signingConfig signingConfigs.release // 必ずreleaseに変更

            // ProGuardなどを使用してリリースビルドのためにコード縮小と難読化を有効にするフラグ。
            minifyEnabled true
            shrinkResources true

            // ProGuardはコードの縮小や難読化するツール
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            // ネイティブデバッグシンボルの生成を有効にするフラグ
            ndk {
                debugSymbolLevel 'FULL'
            }
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8
    }
}

flutter {
    source = "../.."
}

3.4. 機密情報の確認

通常Githubレポジトリ作成時に"Dart"のテンプレートを作成すると、gitignoreされているが。

# Key properties
/android/key.properties

# Keystore files
*.jks
*.keystore

これらがちゃんとgitの追跡外になっていることを確認する。

oo

4.リリースビルドの作成

4.1 iOS向けリリースビルド

  1. Flutterでビルド
flutter clean
flutter build ios --release


このような表示で成功。

  1. Xcodeでアーカイブ

    2.1. Xcodeでプロジェクトを開き、メニューバー「Product」から「Archive」 を選択


2.2. アーカイブが完了したら、「Distribute App」を選択し、App Store Connect にアップロード


2.3. 「App Store Connect」を選択し、「Distribute」をクリック


2.4. アプリ情報を入力

  • Name(アプリ名):App Store Connectの管理画面や、App Storeのリストで表示されるアプリの正式な名前

解説: App Store上で表示されるアプリの名前です。ここでは「Runner」となっていますが、実際に公開するアプリの名前に変更することができます。アプリのブランディングに応じた正式名称を入力します。

  • SKU(Stock Keeping Unit):俺ルールで、バンドルIDをパスカルケースにしたものにする。「JpCoCaenFluttertestproject」

解説: SKUはアプリの一意の識別子です。開発者が任意に決めるIDで、App Storeでは表示されませんが、アプリを管理する際に役立ちます。この例では「jp.co.caen.fluttertestproject」となっています。組織名やプロジェクト名など、管理しやすい名前を使います。

  • Primary Language(主要言語)

解説: アプリのデフォルトの言語を指定します。ここでは「Japanese(日本語)」が選択されています。アプリが複数の言語に対応している場合、この言語がApp Store上で最初に表示される情報の基準となります。

  • Bundle Identifier(バンドルID)

解説: アプリの一意の識別子で、XcodeプロジェクトのInfo.plistで指定されたものと一致しています。通常、リバースドメイン形式(例: com.example.app)で記述され、アプリのデバイス内での識別にも使用されます。ここでは「jp.co.caen.fluttertestproject」となっています。


2.6. なんかエラー出た

このエラーメッセージは、App Store Connectへのアップロード時に、**Bundle Identifier(バンドルID)**が既に使われている、または利用できないため、登録に失敗したことを示しています。バンドルIDは、アプリを一意に識別するために使用されるIDで、Appleのシステムで重複して使用することはできません。

原因:
既に使用されているバンドルID: 他のアプリが同じバンドルIDを使用している可能性があります。バンドルIDは一意でなければならないため、すでに他のプロジェクトやアプリで使われているIDを使用することはできません。
バンドルIDが無効: Apple DeveloperアカウントにバンドルIDが正しく登録されていないか、他の問題で無効と判断された可能性もあります。

解決策
バンドルIDを確認・変更:
Xcodeの設定でバンドルIDを確認し、他のアプリと重複していないことを確認します。
重複している場合は、バンドルIDを変更する必要があります。リバースドメイン形式(例: com.example.appname)で、新しい一意のバンドルIDを作成してください。
変更手順:
Xcodeの「General」タブで「Bundle Identifier」を確認。
必要に応じて新しいバンドルIDを入力し、再度アップロードを試みてください。
Apple Developerのポータルで確認:
Apple Developerアカウントにログインし、すでに登録されているバンドルIDと重複していないか確認します。重複している場合は新しいバンドルIDを登録してください。