Android端末上でAndroidアプリをビルドする
はじめに
よく電車の中でコーディング&アプリビルドをしたくなる時があります。昨今のAndroidスマホは大きなメモリと高速なSoCを搭載しているので、十分にアプリ開発ができるはず。しかもこれだけ高性能化しているのに、ゲームくらいでしかその性能を存分に味わえないというのはもったいない(価格もPCと同等ともしくはそれ以上なのに...)!何よりも、手のひらでアプリ開発ができる、というロマンは素晴らしいものがあります。
しかし、意外とAndroid上でAndroid開発するための知見で、最新版に対応したものが少なく地味に苦労したため、備忘録も兼ねて記事にしたいと思います。
Android Studioは現状、直接Android端末にはインストールできません。Termux上などに構築したUbuntu Desktop上にAndroid StudioをGUIで入れるのもできなくはないそうですが、(ちょっと試したところ)挙動が不安定だったりモッサリしていたりするので、あまりベストな感じがしません。今回は、UbuntuをデスクトップなしでTermux上に構築し、その上にCLI上でAndroid環境を整え、コーディングはVSCodeで行なっていくようなスタイルでいきたいと思います。
流れ
- Termuxのインストール
- Ubuntuのインストール
- Android開発環境の構築
- aapt2の対応
- VSCodeのインストール
- おまけ
1. Termuxのインストール
Termuxは、Android用のターミナルエミュレータのアプリで、ルート化不要でLinux環境が使えます。
Play Storeにあるものはどうやら試験版のようで、あまり推奨されていなそうでした。Fdroid版またはGitHubから入れるのが良さそうだったので、自分はGitHub版のtermux-app_vXXX+github-debug_arm64-v8a.apk
となっているものを入れました。
Termuxにストレージへのアクセス許可
Termuxアプリを開き、以下のコマンドでスマホのストレージへのアクセスができるようにします。
termux-setup-storage
ポップアップまたは遷移した先の画面で、「許可」を押します。
これで、storage/
フォルダとしてスマホのストレージの中身が認識されます。
Termux内の各種アップデート
apt update -y && apt upgrade -y && pkg update -y
(apt updateは、pkgコマンドでインストールを実行するときに自動で実行されるそうですが、念のため)
Termux内の各種インストール
pkgコマンドはTermuxに用意されたパッケージマネージャーで、aptのラッパーとのこと。下記は最小限のものだけ入れているので、必要に応じて追加してください。
pkg install wget proot -y
2. Ubuntuのインストール
Termux自体もLinuxを動かしているようですが、ファイル構造が違っていたりしてそのままLinuxとして色々いじるにはやや制約が多いとのことでした。(参考)そこで、なじみの深いUbuntuをいれます。
Andronix
が配布しているインストーラーを使うと楽に構築できました。
wget https://raw.githubusercontent.com/AndronixApp/AndronixOrigin/master/Installer/Ubuntu22/ubuntu22.sh -O ubuntu22.sh
chmod +x ubuntu22.sh
./ubuntu22.sh
一度インストールした後は、Termuxで
./start-ubutnu22.sh
で起動できます。
Ubuntu内の各種アップデート
apt update -y && apt upgrade -y
Ubuntu内の各種インストール
こちらの記事内で使用する最小限のものになります。必要に応じて追加してください。
apt install nano dpkg gpg git zip unzip -y
gpg
はVSCodeを入れる際の最後に、Microsoftの最新のリポジトリを入れたいか聞かれる場合があるのですが、yesと答えるときに入っていないとエラーが出るので入れました。(参考)
3. Android開発環境の構築
Android Studioは入れられないので、手動で環境を構築する必要があります。
open-jdkのインストール
apt install openjdk-17-jdk -y
現時点のAndroidProjectで最もよく見かけるバージョン17
にて、ひとまずインストールしました。
コマンドラインツールのインストール
Google公式から、「コマンドラインツールのみ」の箇所に移動し、Linux用のcommandlinetools-linux-xxx_latest.zip
となっているファイルをダウンロードします。
スマホのストレージから、Ubuntu内のroot/android
フォルダに解凍します。(この時、Ubuntu内にいる場合はexit
でTermuxに出る必要があります。)
unzip storage/downloads/commandlinetools-linux-xxx_latest.zip -d ubuntu22-fs/root/android
sdkmanagerを使えるようにする
Google公式のガイドの言う通りに、ubuntu22-fs/root/android/cmdline-tools
直下にlatest
フォルダを作成し、元々あったファイル群をその下に移動します。再度./start-ubuntu22.sh
でUbuntuに入り、下記のコマンドで移動させます。
mkdir android/cmdline-tools/latest
find android/cmdline-tools -mindepth 1 -maxdepth 1 -not -name "latest" -exec mv {} android/cmdline-tools/latest/ \;
※コマンドが複雑なのは、cmdline-tools配下全てだと移動先であるlatest
フォルダも含まれてしまうのを考慮する必要があるため
PATHを通す
ANROID_HOME
などの環境変数へのパスを通します。エディタはお好みで...
nano ~/.bashrc
...
# ファイルの一番下に追加
export ANDROID_HOME=$HOME/android
export PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$PATH
export PATH=$ANDROID_HOME/platform-tools:$PATH
なお、platform-tools
はこの後sdkmanagerで入れます。
変更後はbashを更新します。
source ~/.bashrc
以下のコマンドで/root/android
と出れば成功
echo $ANDROID_HOME
skdmanagerで各種インストール
パスが無事に通っていれば、下記のコマンドで無事にバージョン情報が確認できます。(12.0
など)
sdkmanager --version
最新のプラットフォームツールと、APIレベル34(現時点で最新)のSDKツールをインストールします。
sdkmanager "platform-tools" "platforms;android-34"
残念ながら、emulator
は現時点ではArm64版はないようで、入れようとするとWarning: Failed to find package 'emulator'
というエラーが出ました。
その後、下記のコマンドでライセンスを追加承認する必要があります。ひたすらy
を押して承認していきます。
sdkmanager --licenses
4. aapt2の対応
試しにビルドしてみる
ここまできたら、一応Android自体のビルドはできるようになっているはずです。試しにnowinandroid
をビルドしてみましょう。
StudioProjectsフォルダ配下に、nowinandroid
をクローンします。
git clone https://github.com/android/nowinandroid.git ./StudioProjects/nowinandroid
ディレクトリ配下にそのままの名前でクローンするスマートな方法をご存知の方がいたらお教えください汗
その後、試しにdebugビルドしてみましょう。
cd StudioProjects/nowinandroid
./gradlew assembleDebug
./gradlewを使うと、自動でプロジェクトにあったバージョンのgradleのダウンロードが始まるの便利ですね〜
しかし、エラーが出る
残念ながら最後までビルドはできないはずです。なぜなら、Androidのアセット関連を扱うaapt2
(Android Asset Packaging Tool)というツールが、Arm64アーキテクチャに対応していないからです。
下記のようなエラーが出るかと思います。
> Task :app:processDemoDebugResources FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:processDemoDebugResources'. > Could not resolve all files for configuration ':app:demoDebugRuntimeClasspath'.
> Failed to transform appcompat-1.7.0.aar (androidx.appcompat:appcompat:1.7.0) to match attributes {artifactType=android-compiled-dependencies-resources, org.gradle.category=library, org.gradle.dependency.bundling=external, org.gradle.libraryelements=aar, org.gradle.status=release, org.gradle.usage=java-runtime}.
> Execution failed for AarResourcesCompilerTransform: /root/.gradle/caches/8.10/transforms/4a06d29f5dfb54242d37464d1409aabe/transformed/appcompat-1.7.0.
> AAPT2 aapt2-8.6.1-11315950-linux Daemon #0: Daemon startup failed
Arm64版aapt2に置換する
これへの対処方法を、こちらのQiita記事で書いてくださっていました。なお、Arm64版aapt2の入手先が古くなってしまっていたので、新しい入手先を探して入手しました。
入手先がこちら↓
android-sdk-tools-static-aarch64.zip
というファイルをダウンロードして解凍すると、build-tools
フォルダから、aapt2のバイナリファイルが入手できます。自分はPCで解凍してから、aapt2
ファイルだけをGoogleDrive経由でスマホに移動させました。
cp storage/downloads/aapt2 ubuntu22-fs/root/aapt2
このバイナリファイルを、Qiita記事のように、/root/.gradle/caches/modules-2/files-2.1/com.android.tools.build/aapt2
配下にある、graldeバージョンごとのキャッシュディレクトリの下に、aapt2-xxx-linux.jar
というファイルがあるので、その中のaapt2バイナリと置換します。
具体的には、aapt2-xxx-linux.jar
を一旦zipにして解凍し、中身のaapt2を置換して、再度jarにして戻します。
置換処理を簡単に行えるようにするShellScriptを作ってみました。(このShellScriptでは、/root/.gradle/caches/modules-2/files-2.1/com.android.tools.build/aapt2
配下の全てのaapt2-xxx-linux.jar
を対象にaapt
ファイルを置換します。)
以下の内容をfix_aapt2.sh
というファイル名で保存して、Ubuntuのルートディレクトリに、aapt2ファイルと共に配置し、権限を与えてから実行するだけで置換が完了します。
コードを表示
#!/bin/bash
set -e # エラー時にスクリプトを停止
AAPT2_PATH=".gradle/caches/modules-2/files-2.1/com.android.tools.build/aapt2"
AAPT2_DIR="unzip-jar"
# 一時ディレクトリを作成
mkdir -p "$AAPT2_DIR"
# aapt2ディレクトリ以下のすべてのaapt2-*-linux.jarを処理
find "$AAPT2_PATH" -name "aapt2-*-linux.jar" | while read -r AAPT2_FULL_PATH; do
AAPT2_BASENAME="$(basename "$AAPT2_FULL_PATH" .jar)"
AAPT2_ZIP="$AAPT2_BASENAME.zip"
echo "Processing: $AAPT2_FULL_PATH"
# ファイルをコピーしてzipにリネーム
cp "$AAPT2_FULL_PATH" "$AAPT2_ZIP"
# 解凍
unzip "$AAPT2_ZIP" -d "$AAPT2_DIR"
# 元のzipファイルを削除
rm "$AAPT2_ZIP"
# aapt2を適切な位置にコピー
cp "aapt2" "$AAPT2_DIR/aapt2"
# zipを再作成
(cd "$AAPT2_DIR" && zip "$AAPT2_ZIP" * && cd)
# 修正後のzipを元の場所に戻す
mv "$AAPT2_DIR/$AAPT2_ZIP" "$AAPT2_FULL_PATH"
# 一時ディレクトリをクリア
rm -rf "$AAPT2_DIR"/*
done
echo "All aapt2 files processed successfully."
aapt2
とfix_aapt2.sh
ファイルをUbuntuのルートディレクトリに配置後、下記にて権限を付与。
chmod +x fix_aapt2.sh
権限付与後、下記にて実行。
./fix_aapt2.sh
再度ビルドを実行
置換が完了したら、再度./gradlew assembleDebug
を実行します。
すると...無事にビルドが完了します!
自分の端末だと何度かTermuxが落ちて、そのたびに再実行する必要がありました。しかしちゃんと記録が蓄積されていくので、何度もやれば着実にビルドが進んでいきます。gradle.properties
のJVMメモリの設定をいろいろいじると起きづらくなった気がします。8GBメモリのスマホなら-Xmx2500m
などの値(nowinandroidはデフォルトだと4GB)にしたらデバッグビルドだと一度も落ちませんでした。小さすぎるとそれはそれでエラーが出ました。
感動のBuild Successful
の文字
assembleRelease
もいけました
5. VSCodeのインストール
TermuxのCLI上でコーディングをするのはさすがにキツイため、モダンなエディタを使いたいところです。VSCodeをUbuntuに入れて、VSCode Serverとして使うのが一番良さそうでした。通常のWeb版VSCodeであるvscode.devだと何度やってもGitHubログインや一部プラグインのインストールができなかったのですが、Ubuntu上に立てたVSCode Serverだと、無事にできました。
公式サイトからArm64版
の.deb
パッケージをダウンロードします。(code_xxx_arm64.deb
という名前でした。amd64
と紛らわしいので注意)
その後、以下のようにしてスマホのストレージからUbuntuに移動させます。Ubuntu内に入っている場合は、一旦exit
コマンドでTermuxに出ておきます。
cp storage/downloads/code_*_arm64.deb ubuntu22-fs/root/code.deb
その後、Ubuntuを./start_ubuntu22.sh
で再度起動し、Ubuntu内にインストールします。
apt install ./code.deb -y
無事にインストールできたら、下記のコマンドで開始し、ブラウザでURLを開きます。
code serve-web
通常のスマホ画面だとせまくて要素がギチギチになってしまうので、Androidの設定アプリの「開発者向けオプション」→「最小幅」を、500dp〜600dpに設定すると画面が広々使えるようになりました。(この設定にしてからZenn記事もスマホ上で編集しやすくなりました。)
before: 411dp | after: 520dp |
---|---|
![]() |
![]() |
PWAとしてスマホのホーム画面に追加できるのが嬉しいところです。
6. おまけ
端末のアーキテクチャを確認
pkg install neofetch
neofetch
これを実行すると下記のようなロマン溢れるASCIIアートと共に端末のアーキテクチャが確認できます(ただしデフォルトのTermuxのズームレベルだと見切れる可能性があるので、ピンチインしてから実行するのが良さそう)
TODO:
ビルドしたapkファイルをスムーズに端末に移動させて起動するフローを構築したいです。
おわりに
Android内でアプリ開発ができる、この感動は素晴らしいです。モバイル開発onモバイル端末の同志が他にいらっしゃいましたら、ぜひ繋がりたいです。
何か内容に間違いなどございましたら、コメントでご指摘くださいますと幸いです。
参考
Discussion
Androidのアプリ開発はあまり詳しくないですが、非常に参考になりました。
aapt2
の差し替えは、zip/unzip
ではうまくいかず、jar cf/jar xf
で圧縮/解凍を行うと、期待通りの動作をしました。私の環境(Pixel9 Fold)では、
gradle.properties
で-Xmx8g -Xms8g
と設定しないと、aapt2
が動作しませんでした。急いで作ったのでかなりベタベタですが、以下のような適当なスクリプトで最小限のプロジェクトを作って、いろいろいじって遊んでいます。
コメントありがとうございます!
zip/unzipではうまくいかない場合があるとは思い至りませんでした。ご共有くださいまして、ありがとうございます。
-Xmx8g -Xms8g
はかなり大きな値ですね。。。Pixel Foldだと、Android端末上の開発も快適にできそうです。Androidプロジェクト自体をPythonから生成してしまうの、すごすぎます👀
返信ありがとうございます。
本当に貴重な記事をありがとうございます。
コンパイルからインストールまで、なんとかコマンドライン一発でできないかと思い、以下のようなアプリを作成しました。
文字列リソースは以下のような感じです。
上記を、例えばパッケージ名
com.example.app.installer
に設定してコンパイルし、ファイルマネージャーなどからインストールします。起動後に画面上のボタンを押して「すべてのファイルへのアクセス」権限をオンにした状態で、Ubuntu on Termux から以下のコマンドを実行すると、Androidのインストーラー起動まではコマンド一発でいけます。
予め、
/storage/emulated/0/Termux
ディレクトリを作成しておいてください。例えば
MyApp
というプロジェクト内で実行すると、こんなかんじです。セキュリテイの制約で、何回か画面をタップしないとコンパイルしたアプリをインストールできませんが、無いよりかましかと。
これで気になるコードを、Android端末だけでたくさん試すことができます。
私はEmacsユーザーなので、上記コマンドをEmacs上から生成して実行できるLispを作成して
C-r
キーで実行しています。記事中のVSCodeは使ったことがないのですが、たしかVSCodeでもターミナル機能があったと思うので、同じように実行できるかと。
すみません。マニフェストと
providerです。
これがないと権限関連が混乱する話になるところでした。。。