paloma blog

NWエンジニアやってます。主に自宅環境のお遊びを書きます。Pythonもちょっと。タイトルは好きなカクテルから。

pythonでAndroidの野良アプリを作りたい2 buildozerでコンパイル編

前回作成したアプリスマホにインストールできるようパッケージ化します。

今回はbuildozerというアプリを使います。

buildozerとは

python androidapp」等で検索するとkivyとセットで出てきます。
apkファイルのビルドツールというところでしょうか。
ios用のパッケージングも出来るみたいです。

github.com

buildozer環境構築

buildozer環境を構築しないといけないのですが、この手のソフトはいろんなパッケージをインストールしないといけないのでコンテナで作ります。

コンテナ作成

コメントなし。

masashi@PC-ubuntu:~$ lxc launch ubuntu: buildozer
Creating buildozer
Starting buildozer
masashi@PC-ubuntu:~$ lxc exec buildozer -- /bin/bash
root@buildozer:~# 
root@buildozer:~# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.4 LTS
Release:    20.04
Codename:   focal
buildozerインストール

ドキュメントに添ってインストール。

buildozer.readthedocs.io

やはりそれなりのパッケージが必要ですね。
名前を着たことあるくらいですがCythonも使うようです。

root@buildozer:~# sudo apt update
root@buildozer:~# apt install python3-pip
root@buildozer:~# pip3 install --user --upgrade buildozer
root@buildozer:~# apt install -y git zip unzip openjdk-13-jdk python3-pip autoconf libtool pkg-config zlib1g-dev libncursesw5-dev libtinfo5 cmake libffi-dev libssl-dev
root@buildozer:~# pip3 install --user --upgrade Cython==0.29.19 virtualenv

bashrcにパスを追加します。

export PATH=$PATH:~/.local/bin/

この配下にbuildozerコマンドが作成されるっぽい。

build@buildozer:~$ ls .local/bin/
buildozer  buildozer-remote  cygdb  cython  cythonize  virtualenv

バージョン。

build@buildozer:~$ buildozer version
# Check configuration tokens
Buildozer 1.3.0
初期化

初期化しましたがrootユーザだと警告が出ました。

root@buildozer:~# buildozer init
Buildozer is running as root!
This is not recommended, and may lead to problems later.
Are you sure you want to continue [y/n]? n

コンテナ内なので問題ないかもしれませんが権限でトラブっても嫌なのでビルド用のユーザを作ります。
ユーザ作成後再度init。

build@buildozer:~$ buildozer init
File buildozer.spec created, ready to customize!

buildozer.specというファイルが作成されました。

build@buildozer:~$ ls
buildozer.spec
specファイル

パッケージ化する時の詳細をこのファイルで決められるみたいです。
お試しなのでほぼデフォルトですが、後述します。

ファイル配置

kivyのmain.py、kvファイルを配置します。 モジュールもsrcディレクトリに配置。

build@buildozer:~$ tree
.
├── bin
├── buildozer.spec
├── buildozer.spec.def
├── main.py
├── my.kv
└── src
    ├── configure.py
    ├── getinfo.py
    ├── gettw.py
    └── tweetapi.py

ビルド

デフォルトだとmain.pyのファイルをコンパイルしてくれるみたいです。
(コンパイルという表現で正しいのかわかりませんが)
私のマシンだと6分ほどかかりました。

ホストのスペックです。

masashi@PC-ubuntu:~$ cat /proc/cpuinfo | grep model\ name
model name  : Intel(R) Core(TM) i5-2400 CPU @ 3.10GHz
model name  : Intel(R) Core(TM) i5-2400 CPU @ 3.10GHz
model name  : Intel(R) Core(TM) i5-2400 CPU @ 3.10GHz
model name  : Intel(R) Core(TM) i5-2400 CPU @ 3.10GHz
masashi@PC-ubuntu:~$ cat /proc/meminfo | grep MemTotal
MemTotal:       12175224 kB

ビルドはコマンド一発です。

build@buildozer:~$ buildozer -v android debug

()

No setup.py/pyproject.toml used, copying full private data into .apk.
Applying Java source code patches...
Applying patch: src/patches/SDLActivity.java.patch
# Android packaging done!
# APK myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk available in the bin directory

./binにapkファイルが作成されました。 これをAndoroidに持っていけばインストールできそうです。

build@buildozer:~$ ls -lh bin/ total 26M -rw-rw-r-- 1 build build 26M Jul 3 04:02 myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk

specファイルのチューニング

パッケージ化する際のタイトルやモジュール、挙動などを指定できるようです。
今回はアプリのタイトル名などはデフォルトにしていますが、Androidで動かすまでに数回buildをやり直しました。
次回予定のAndroidにデプロイしてからいろいろ修正したので時系列が前後してしまいますが修正点をメモっておきます。

  • source.exclude_exts = spec
  • source.exclude_dirs = tests, bin, venv
  • requirements = python3,kivy,certifi,charset-normalizer,idna,oauthlib,Pillow,Pygments,requests,requests-oauthlib,tweepy,urllib3
    • 自作ツールを動かすのに必要なライブラリ。pip listで確認しました。
      バージョン指定の方法が分からなかったのですが、最新がインストールされるのかな?
      とりあえず動きました。
  • android.permissions = INTERNET
    • twitterAPIを利用しますが、Permissinがないとネットにつながらずアプリが終了してしまいました。
build@buildozer:~$ diff -u buildozer.spec{.def,}
--- buildozer.spec.def  2022-07-03 03:56:08.785047923 +0000
+++ buildozer.spec  2022-07-03 10:19:25.865583568 +0000
@@ -19,10 +19,10 @@
 #source.include_patterns = assets/*,images/*.png
 
 # (list) Source files to exclude (let empty to not exclude anything)
-#source.exclude_exts = spec
+source.exclude_exts = spec
 
 # (list) List of directory to exclude (let empty to not exclude anything)
-#source.exclude_dirs = tests, bin, venv
+source.exclude_dirs = tests, bin, venv
 
 # (list) List of exclusions using pattern matching
 # Do not prefix with './'
@@ -37,7 +37,7 @@
 
 # (list) Application requirements
 # comma separated e.g. requirements = sqlite3,kivy
-requirements = python3,kivy
+requirements = python3,kivy,certifi,charset-normalizer,idna,oauthlib,Pillow,Pygments,requests,requests-oauthlib,tweepy,urllib3
 
 # (str) Custom source folders for requirements
 # Sets custom source for any requirements with recipes
@@ -93,7 +93,7 @@
 #icon.adaptive_background.filename = %(source.dir)s/data/icon_bg.png
 
 # (list) Permissions
-#android.permissions = INTERNET
+android.permissions = INTERNET

まとめ

初めてapkファイルを作成しました。
便利なツールがあるものでコマンド一発で作成完了というお手軽さです。
中身がよくわかっていませんが、pythonAndroidで動かせるよう言語の変換とかやってるんでしょうか?
Cythonを使っているのでpythonのコードをC言語交えていい感じに変換してるのかな。

zipファイルなので展開してみましたがよくわかりませんね。
どれがメインのプログラムなんだ? ここはapkファイル仕様を抑えないとですね。

asashi@PC-ubuntu:~/androidapp$ file myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk 
myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk: Zip archive data, at least v2.0 to extract
masashi@PC-ubuntu:~/androidapp$ unzip myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk 
Archive:  myapp-0.1-arm64-v8a_armeabi-v7a-debug.apk
  inflating: AndroidManifest.xml     
  inflating: META-INF/CERT.RSA       
  inflating: META-INF/CERT.SF        
  inflating: META-INF/MANIFEST.MF    
 extracting: assets/private.tar      
  inflating: classes.dex             
  inflating: lib/arm64-v8a/libSDL2.so  
  inflating: lib/arm64-v8a/libSDL2_image.so  
  inflating: lib/arm64-v8a/libSDL2_mixer.so  
  inflating: lib/arm64-v8a/libSDL2_ttf.so  
  inflating: lib/arm64-v8a/libcrypto1.1.so  
  inflating: lib/arm64-v8a/libffi.so  
  inflating: lib/arm64-v8a/libfreetype.so  
  inflating: lib/arm64-v8a/libhidapi.so  
  inflating: lib/arm64-v8a/libmain.so  
  inflating: lib/arm64-v8a/libpng16.so  
  inflating: lib/arm64-v8a/libpybundle.so  
  inflating: lib/arm64-v8a/libpython3.8.so  
  inflating: lib/arm64-v8a/libsqlite3.so  
  inflating: lib/arm64-v8a/libssl1.1.so  
  inflating: lib/armeabi-v7a/libSDL2.so  
  inflating: lib/armeabi-v7a/libSDL2_image.so  
  inflating: lib/armeabi-v7a/libSDL2_mixer.so  
  inflating: lib/armeabi-v7a/libSDL2_ttf.so  
  inflating: lib/armeabi-v7a/libcrypto1.1.so  
  inflating: lib/armeabi-v7a/libffi.so  
  inflating: lib/armeabi-v7a/libfreetype.so  
  inflating: lib/armeabi-v7a/libhidapi.so  
  inflating: lib/armeabi-v7a/libmain.so  
  inflating: lib/armeabi-v7a/libpng16.so  
  inflating: lib/armeabi-v7a/libpybundle.so  
  inflating: lib/armeabi-v7a/libpython3.8.so  
  inflating: lib/armeabi-v7a/libsqlite3.so  
  inflating: lib/armeabi-v7a/libssl1.1.so  
 extracting: res/drawable-hdpi-v4/ic_launcher.png  
 extracting: res/drawable-mdpi-v4/ic_launcher.png  
 extracting: res/drawable-xhdpi-v4/ic_launcher.png  
 extracting: res/drawable-xxhdpi-v4/ic_launcher.png  
 extracting: res/drawable/presplash.jpg  
  inflating: res/layout/chooser_item.xml  
  inflating: res/layout/main.xml     
  inflating: res/layout/project_chooser.xml  
  inflating: res/layout/project_empty.xml  
 extracting: res/mipmap/icon.png     
 extracting: resources.arsc          

次回はAndroidにインストールして動かしてみます。