Mobility TechnologiesでFlutterエンジニアとして働いているTomiと申します。
今回AndroidアプリケーションにFlutterを組み込む方法について調べてみました。調査した内容の中でFlutter moduleのAAR(Android ARchive)をMavenとGitHub Actionsを利用してGitHub Packagesにデプロイする方法を解説します。
はじめに
既存のAndroidアプリケーションからFlutter moduleを使うためには2つ方法があります。
- Flutterのコードをビルドし、Android Archive(AAR)を出力し、そのAARをNative側に取り込む
- Native側のビルドに、Flutter側のビルドを組み込み、一括でビルドできるようにする
この2つの方法の中で「Flutterのコードをビルドし、Android Archive(AAR)を出力し、そのAARをNative側に取り込む」ことにしました。
理由は下記の2点です。
- Native側の開発は、毎回Flutter部分をビルドしなくても良いのでビルドが早いです。
- FlutterエンジニアではないAndroidエンジニアがプロジェクトに参加する場合、Flutter側の環境構築する必要がないです。
公式ドキュメントにはローカル上の構築方法しか書かれていませんが、実際に運用するのであればCIを用いてリモートにデプロイすると思います。この記事はリモートにあるレポジトリ(GitHub Package)にMavenとGitHub Actionを使ってデプロイする方法を解説します。
注意点
GitHub PackageにMavenを利用してデプロイする方法は、Flutter v3.3.0でバグが有り、それはv3.5.0で対応予定になります。
流れ
AARを作成する
Flutter moduleをAndroidアプリケーションに組み込むためにAARファイルを作成します。
flutter build aar
上のコマンドでAARを生成するとバージョンは1.0になります。
pubspec.yamlにバージョンを指定してもAARファイルには反映されません。バージョンを変更したい場合は--build-numberオプションを使ってください。
flutter build aar --build-number 2.0.0
上のコマンドで実行すると/build/host/outputs/repoに下記が生成されます。
.
└── com
└── example
└── moduletest
├── flutter_debug
│ ├── 2.0.0
│ │ ├── flutter_debug-2.0.0.aar
│ │ ├── flutter_debug-2.0.0.aar.md5
│ │ ├── flutter_debug-2.0.0.aar.sha1
│ │ ├── flutter_debug-2.0.0.pom
│ │ ├── flutter_debug-2.0.0.pom.md5
│ │ └── flutter_debug-2.0.0.pom.sha1
│ ├── maven-metadata.xml
│ ├── maven-metadata.xml.md5
│ └── maven-metadata.xml.sha1
├── flutter_profile
│ ├── 2.0.0
│ │ ├── flutter_profile-2.0.0.aar
│ │ ├── flutter_profile-2.0.0.aar.md5
│ │ ├── flutter_profile-2.0.0.aar.sha1
│ │ ├── flutter_profile-2.0.0.pom
│ │ ├── flutter_profile-2.0.0.pom.md5
│ │ └── flutter_profile-2.0.0.pom.sha1
│ ├── maven-metadata.xml
│ ├── maven-metadata.xml.md5
│ └── maven-metadata.xml.sha1
└── flutter_release
├── 2.0.0
│ ├── flutter_release-2.0.0.aar
│ ├── flutter_release-2.0.0.aar.md5
│ ├── flutter_release-2.0.0.aar.sha1
│ ├── flutter_release-2.0.0.pom
│ ├── flutter_release-2.0.0.pom.md5
│ └── flutter_release-2.0.0.pom.sha1
├── maven-metadata.xml
├── maven-metadata.xml.md5
└── maven-metadata.xml.sha1
これでGithub Packagesにデプロイする準備できました。
💡 上のファイルtreeを見るとAARファイルが3つしかありませんが、Flutter module内で他のライブラリ(Google Mapなど)を使用するすると、増える場合があります。
MavenでGitHub Packagesにデプロイする
GitHub PackagesではMavenでデプロイする方法のドキュメントを提供しています。このドキュメントによると下記の3つを対応することでGitHub Packagesへのデプロイすることができます。
~/.m2/settings.xmlの設定するpomファイルにdistributionManagementタグを利用してリモートリポジトリの情報を追加するmvn deployコマンドを実行する
2に関して問題点があります。flutter build aarでpomファイルが複数自動生成されますが、ビルドごとに上書きされるため、ひとつづつdistributionManagementを追加することは難しいです。
自動生成されたAARファイルとpomファイルが同じ層に1:1になってるのが解決の糸口になりました。
...省略
├── flutter_debug
│ ├── 2.0.0
│ │ ├── **flutter_debug-2.0.0.aar**
│ │ ├── flutter_debug-2.0.0.aar.md5
│ │ ├── flutter_debug-2.0.0.aar.sha1
│ │ ├── flutter_debug-2.0.0.pom
│ │ ├── flutter_debug-2.0.0.pom.md5
│ │ └── flutter_debug-2.0.0.pom.sha1
...省略
この問題は、mvn deploy:deploy-fileコマンドにURLオプションでGitHubレポジトリの指定をすることで解決できます。
pomファイルリストを探す
正常に作動させるためには全てのAARファイルとpomファイルをデプロイする必要があり、findコマンドを利用してpomファイルを検索しました。
find . -name "*.pom" -type f -print0 | xargs -I{} -0
上のコマンドの実行結果が下記です。
./com/example/moduletest/flutter_profile/2.0.0/flutter_profile-2.0.0.pom ./com/example/moduletest/flutter_debug/2.0.0/flutter_debug-2.0.0.pom ./com/example/moduletest/flutter_release/2.0.0/flutter_release-2.0.0.pom
Mavenを利用してデプロイする
上記の「pomファイルリストを探す」で用いたコマンドを利用し、Mavenコマンドでデプロイします。
find . -name "*.pom" -type f -print0 | xargs -I{} -0 bash -c 'mvn -B deploy:deploy-file -Durl="https://maven.pkg.github.com/{owner}/{repository name}" -DrepositoryId=github -Dtoken=${{ secrets.GITHUB_TOKEN }} -DpomFile="$0" -Dfile="${0%.pom}.aar"' '{}' \;
- GitHub Packageは
https://maven.pkg.github.com/{owner}/{repository name}ような形でURLを設定する必要があります。 - GitHub Actionsの利用を想定しているので、
secrets.GITHUB_TOKENを利用していますが、それ以外のCIを利用する場合は、ここをGitHubのPersonal Access Tokenで置き換えてください。
しかしこのままでは認証エラーが発生します。
Settings.xmlファイルを設定して認証エラーを回避する
元々mavenでGitHub Packagesにデプロイする時には~/.m2/settings.xmlファイルを設定する必要がありますがsettings.xml設定してないので認証エラーが発生しました。
解決方法はmvnコマンドの-sオプションを使ってsettings.xmlを指定することです。
settings.xmlを作成します。
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <servers> <server> <id>github</id> <username>Mobility Technologies</username> <password>${env.GITHUB_TOKEN}</password> </server> </servers> </settings>
下のコマンドはmvnコマンドの-sオプションを使ってsettings.xmlを指定しました
find . -name "*.pom" -type f -print0 | xargs -I{} -0 bash -c 'mvn -B -s settings.xml deploy:deploy-file -Durl="https://maven.pkg.github.com/{owner}/{repository name}" -DrepositoryId=github -Dtoken=${{ secrets.GITHUB_TOKEN }} -DpomFile="$0" -Dfile="${0%.pom}.aar"' '{}' \;
上のコマンドを実行するとGithub Packagesにデプロイできると思います。
GitHub Actionsを使ってデプロイを自動化する
💡 基本的なGitHub Actionsの設定方法はこちらを参照してください。
今まで説明したコマンドをGitHub Actionsのyamlファイルに追加すれば終わりですが、先にバージョンをどのように指定するか考える必要があります。
バージョンを指定してAARファイルをビルドする
...省略 on: push: tags: - '[1-9].[0-9]+.[0-9]+' ...省略 - name: build aar run: | flutter build aar --build-number=$(echo $GITHUB_REF | cut -d / -f 3)
GitHub Actionsのyamlファイル上で上記のように設定するとバージョン設定が可能ですが、1つずつ解説いたします。
on: push: tags: - '[1-9].[0-9]+.[0-9]+'
tagをpushすると、それがトリガーとなり、このWorkflowが走ります。
echo $GITHUB_REF | cut -d / -f 3
tagを2.0.0で指定した場合、GitHubのcontext変数ref($GITHUB_REF)では”refs/tags/2.0.0" が入ってきますが、echoとcutを利用してバージョンだけ抽出します。
上記のechoを実行すると”2.0.0”が抽出されます。
この”2.0.0”を使ってaarファイルをビルドします。
- name: build aar run: | flutter build aar --build-number=$(echo $GITHUB_REF | cut -d / -f 3)
これでtagの名前を2.0.0にした場合、2.0.0バージョンでビルドされてAARファイルとpomファイルが生成されます。
デプロイする
- name: mvn deploy run: | find . -name "*.pom" -type f -print0 | xargs -I{} -0 bash -c 'mvn -B -s settings.xml deploy:deploy-file -Durl="https://maven.pkg.github.com/{owner}/{repository name}" -DrepositoryId=github -Dtoken=${{ secrets.GITHUB_TOKEN }} -DpomFile="$0" -Dfile="${0%.pom}.aar"' '{}' \; env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
上のアクションで該当するGitHubレポジトリにデプロイすることが可能です。
env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
上の部分は前述したsettings.xmlで使う環境変数です。
全体コード
Flutter Project Path/settings.xml
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <servers> <server> <id>github</id> <username>Mobility Technologies</username> <password>${env.GITHUB_TOKEN}</password> </server> </servers> </settings>
Flutter Project Path/.github/workflows/push-tag-deploy.yml
name: push tag deploy on: push: tags: - '[1-9].[0-9]+.[0-9]+' jobs: build-and-deploy: runs-on: ubuntu-latest timeout-minutes: 10 permissions: contents: read packages: write steps: - name: Get the version id: get_version run: echo ::set-output name=VERSION::$(echo $GITHUB_REF | cut -d / -f 3) - name: Checkout code uses: actions/checkout@v3 - name: flutter action uses: subosito/flutter-action@v2 with: flutter-version: '3.0.5' - name: Add path run: echo "$(pwd)/flutter/bin" >> $GITHUB_PATH - name: Get dependencies run: flutter pub get - name: build aar run: | flutter build aar --build-number=${{ steps.get_version.outputs.VERSION }} - name: mvn deploy run: | find . -name "*.pom" -type f -print0 | xargs -I{} -0 bash -c 'mvn -B deploy:deploy-file -Durl="https://maven.pkg.github.com/{owner}/{repository name}" -DrepositoryId=github -Dtoken=${{ secrets.GITHUB_TOKEN }} -DpomFile="$0" -Dfile="${0%.pom}.aar"' '{}' \; env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Android Project Path/build.gradle
allprojects {
repositories {
google()
mavenCentral()
maven { url "$storageUrl/download.flutter.io" }
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com//{owner}/{repository name}")
credentials {
username = User Name
password = [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
}
}
}
}
Android Project Path/app/build.gradle
dependencies {
debugImplementation 'com.example.app:flutter_debug:2.0.0'
profileImplementation 'com.example.app:flutter_profile:2.0.0'
releaseImplementation 'com.example.app:flutter_release:2.0.0'
}
おわり
頑張ってGitHub Packagesにデプロイすることを成功させましたが、2日後にFlutter v3.3.0 発表され、いきなりデプロイできなくなってしまいました。その時、バージョンの影響に受けない方法を探す必要があるかと思いまして、GitHub Packagesを使わずGitHub Repositoryに/build/host/outputs/repoをそのままpushしておいてAndroid側でraw.githubusercontent.com を使って依存性を取得するような方法で変更しました。
この方法は別の記事で扱ってみようかと思います。