Flutter開発を始めた時に知りたかったAndroidのこと
こんにちは。リテールアプリ共創部のマッハチームのきんくまです。
マッハチームのメンバーで開発速度向上に関する知見を共有するブログの連載を始めました。
今回は第4弾で、私がFlutter開発を始めたときに知りたかったAndroidのことです。
これまでのブログ記事です!ぜひご覧ください〜
私はもともとiOSの開発をやっていたのですが、Flutter開発を始めました。
そうするとAndroidもさわることになります。Androidは入門書を1-2冊やったぐらいで実案件の開発はやったことがなかったです。
なので実践だと出てくるTips的な「こういうことだったのか〜。もっと早くしりたかった〜」みたいなところを、パラパラと書いていきます。
アプリのビルド設定
アプリのビルド設定ファイルは以下のパスです
flutterルート/android/app/build.gradle.kts
この中に以下のようなことを書きます
- ライブラリへのリンク
- ビルドターゲット(Android APIレベル設定)
- アプリバージョン番号 / アプリバージョンコード
- 証明書のひもづけ設定
- 環境ごとのflavor設定
一部抜粋
android {
// ネームスペース
// もしソースディレクトリの場所を変えた場合はここも変更する必要がある
// 今だと android/app/src/main/kotlin/com/xxx/yyyyapp の中にMainActivityがある
namespace = "com.xxx.yyyyapp"
// コンパイル時に使用するAndroid SDKバージョン
compileSdk = 36
// ときどき使用ライブラリによってエラーが出るので直接指定してあげる
ndkVersion = "27.0.12077973"
defaultConfig {
// アプリID
applicationId = "com.samplecompany.sampleapp"
// インストール可能な最小SDKバージョン
// これ未満のAndroid OSはインストール不可
minSdk = 26
// アプリが対象とするSDKバージョン
// targetSdk ≤ compileSdk である必要がある
// 基本はcompileSdkと揃える
targetSdk = 36
// バージョンコード。数値。今はflutter側での設定を受け付けているが、変えるなら1とか300とかに設定する。
// ユーザーからは見えない
versionCode = flutter.versionCode
// バージョン番号。文字列。今はflutter側での設定を受け付けているが、変えるなら"1.0.0"とかに設定する。
// ストアやユーザーから見える
versionName = flutter.versionName
}
Android SDKはAndroid OSのバージョンと違うAPI levelという概念があります。
例えば API レベル 36 = Android 16 となります。
AndroidManifest.xml
AndroidManifest.xmlはAndroidのアプリの動作設定を行います
- 権限まわり(位置情報とかネットワークとか)
- activityの登録
- 外部アプリからの起動を受け付けるintent-filterの設定
- serviceの登録
などを行います。
パス
android/app/src/main/AndroidManifest.xml
Flutter開発の最初に、ライブラリを組み込もうとしたときに、マニュアルでAndroidMenifestに何かを追加すると書いてあるんだけど、どのタグの中にどれを書いて良いかが特にわからなかったです。例だとだいたいこんな感じです。
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- manifestはXMLなのでhtmlと同じようにコメントもかける -->
<!-- パーミンション設定 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- applicationはパーミッションと同階層 -->
<application
android:label="@string/app_name"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<!-- activityはapplicationの中。複数activityを登録したい場合は、
このactivityと同階層に並列で書く -->
<activity
android:name=".MainActivity">
<!-- activityにひもづくmeta-dataとintent-filterはactivityの中に書く -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- serviceはactivityと同階層 -->
<service android:name="com.sample.xxx.yyyyMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>
環境ごとのflavorを作ったときに、AndroidManifest.xmlもマージされます。
あとで説明します。
resフォルダがリソースフォルダ
resフォルダの中にリソースが入ります。
パス
android/app/src/main/res
中身
res/
├── drawable/ # 画像リソース
├── mipmap/ # アプリアイコン
├── layout/ # レイアウトXML
├── values/ # 文字列、色、スタイルなど
├── xml/ # その他のXML
├── raw/ # 生ファイル
├── font/ # フォントファイル
└── animator/ # アニメーション定義
valuesフォルダの中に、こんなものが入ります
values/
├── strings.xml # 文字列
└── colors.xml # 色定義
ここで、大事なポイントとして、使うときはこんな感じになります。
定義
res/values/strings.xml
<resources>
<!-- 基本的な文字列 -->
<string name="app_name">My Application</string>
<string name="welcome_message">Welcome to our app!</string>
<string name="button_submit">Submit</string>
</resources>
Kotlinで使うとき
val appName = getString(R.string.app_name)
val welcomeMsg = getString(R.string.welcome_message)
xmlで使うとき。これはアプリのレイアウト用xmlファイルもそうなのですが、AndroidManifest.xmlもそうなのです。(これにハマった、、、)
activity_sample.xml レイアウトファイル
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/welcome_message" />
AndroidManifest.xml
<application
android:label="@string/app_name"
環境ごとのflavor設定をしたときの、AndroidManifestとresのマージ
環境ごとの設定をしたいときにflavorを設定します。
flutter側のflavor設定はこちらです。
Set up Flutter flavors for Android
Android側の設定はこちらです
このとき、さきほど説明した AndroidManifestとres はフレーバーごとのディレクトリを作ると、それらが最終的にマージされます。
android/app/src/
├── staging/
│ ├── res/
│ │ └── values/
│ │ └── strings.xml
│ └── AndroidManifest.xml
│
├── main/
│ ├── res/
│ │ └── values/
│ │ └── strings.xml
│ └── AndroidManifest.xml
│
└── production/
├── res/
│ └── values/
│ └── strings.xml
└── AndroidManifest.xml
mainは共通です。ここにベースとなる共通部分を配置します。
stagingとproductionがそれぞれのフレーバーです。mainからの差分だけを配置します。
AndroidManifest.xmlのマージルールと、やり方は以下のマニュアルからわかります。
flutterでの最終的なマージの場所は例としてこんな場所にあります。設定がうまくされているか確認してください。
build/app/intermediates/merged_manifests/stagingDebug/processStagingDebugManifest/AndroidManifest.xml
ディープリンク(カスタムURLスキーム。AppLinksではない)のテスト
まず端末(実機とエミュレータ)をリストで出す
adb devices -l
ディープリンクで立ち上げる
adb shell am start
-W -a android.intent.action.VIEW
-d <URI> <PACKAGE>
-s は端末選択の引数
例
adb -s 1C021FDF6002J6 shell am start \
-W -a android.intent.action.VIEW \
-d "sample-scheme://samplehost/sample/path?foo=bar" com.xxx.yyyy.stg
余談 go_routerのURLスキームの扱い
余談ですが、go_routerは、URLスキームの形が以下を想定しているところもハマりどころです
カスタムスキーム://ホスト/パス
例
sampleapp://com.abccompany/account
カスタムスキームは気にしなくてもよいのですが、必ずホスト(ドメイン)を設定してあげる必要があります。
ホスト部分は上の例だと com.abccompany と書いてますが、別に abccompany だけでもOKです。
これをしないと、パスがうまくとれません。(ホストを省略した場合、go_routerからみるとパスをホストとして認識してしまう)
APKファイルの署名を確認
APKファイルの署名(フィンガープリント)を確認するときのコマンドです。
一時的にPathを通す
export PATH="/path/to/directory:$PATH"
例
export PATH="/Users/ユーザー名/Library/Android/sdk/build-tools/35.0.0:$PATH"
コマンド実行
apksigner verify --print-certs -v app-staging-release.apk
最後に
こんな感じの内容が知れたら良かったな〜というのをまとめてみました。
何かのお役に立てればうれしいです!ではでは








