BuildozerでAndroidアプリを作る 2024 WSL2

この記事はPython＋GUIをKivyで作成し、BuildozerでAndroidアプリを作成する方法についての記事です。

これはずいぶん前からある方法なのですが、Buildozerが動作する環境がシビアでよく失敗します。
Windowsで仮想のLinuxであるWSL(Windows Subsystem for Linux)を動作させてビルドすると動作したのでお知らせします。


### 1．WSLのUbuntuをインストール
Microsoft StoreでWSLをインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884555/10c44d96-50d3-d770-daed-f0c87417e192.png)
インストールしたら、スタートアップメニューから実行できます。

### 2．WSL2上で環境を作ろう
私のWindows10 PCのWSL 1の環境ではlibffiの実行中にエラーが出ました。
```
.buildozer/android/platform/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/bin/clang:
cannot execute binary file: Exec format error
```

WSL 1 では clang のバイナリが正しく実行できなかったようです。これは、clang が WSL 1 のエミュレーション環境ではサポートされていない可能性があります。
WSL2の環境であればこの問題は発生しないようです。
使用しているWSLのバージョンを確認し、WSL2へ変更します。
```powershell:windows powershell
wsl --list --verbose
  NAME                   STATE           VERSION
* docker-desktop-data    Stopped         2
  Ubuntu-20.04           Running         1
  Ubuntu-22.04           Stopped         1
  docker-desktop         Stopped         2
  Ubuntu                 Running         1
wsl --set-version Ubuntu-20.04 2
```
既に色々環境をいじっている場合は最初からやり直した方が良い事もあるので、
参考まで、wslの操作コマンドを載せておきます。
```powershell:windows powershell
#uninstall
wsl --unregister Ubuntu-22.04
#defaultのwsl versionの設定
Wsl --set-default-version 2
```
### 3.環境構築用のShファイルを用意して実行
コマンドを入力するのは面倒なので環境作成から日本語の簡単なmain.pyをビルドするまでを実行するshellスクリプトファイルを作成します。

```cmd:cmd
nano setup_buildozer.sh
```


```shell:setup_buildozer.sh
#!/bin/bash
echo WSL1ではlibffiがBinaryの問題を起こす。WSL2で起動必要。
echo pyenvでのInstallを行うと仮想環境に.buildozerをInstallする為、NGになる事あり。
echo 日本語フォントを使用するとapk起動しない問題あり。ubuntuのフォントを移植する方法が使える。
echo libssl-dev libffi-dev zlib1g-dev辺りをInstallしないとopenssl==1.1.1はDownload失敗？
echo Ubuntu 20.04 buildozerのInstallをし、android debugするとOK.
echo Ubuntu 20.04 buildozerのSourceをGitでDLしBuildしandroid debugするとOK.
echo Ubuntu 22.04 sudoを付けてinstallし、sudo buildozer android debugをしないと権限問題で停止。

# システムの更新
# システムの更新
echo "Updating and upgrading the system..."
sudo apt update
sudo apt upgrade -y

# 必要なパッケージのインストール
echo "Installing required packages..."
sudo apt-get install -y build-essential libssl-dev libffi-dev zlib1g-dev wget git zip unzip openjdk-17-jdk  autoconf libtool cmake  python3-openssl python3.11 python3-pip fonts-takao

# Pythonのバージョン確認
python3.11 --version

# 必要なPythonパッケージのインストール
echo "Installing Python packages..."
sudo pip install --upgrade pip
sudo pip install kivy cython buildozer 

# PATHに~/.local/binを追加
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc

# 設定を反映
source ~/.bashrc
export PATH=$PATH:~/.local/bin

# 日本語フォントをassetsフォルダにコピー
echo "Copying Japanese font to assets folder..."
mkdir -p assets
cp /usr/share/fonts/truetype/fonts-japanese-gothic.ttf assets/

# Buildozerバージョン確認
buildozer version
echo "Please Enter"
read 

# サンプルアプリの作成
echo "Creating a sample Kivy app..."
cat << EOF > main.py
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout

from kivy.core.text import LabelBase, DEFAULT_FONT
from kivy.utils import platform

# フォントのパスを指定してフォントを設定する
if platform == 'win':
    # Windowsの場合はシステムフォントを使用
    font_path = "C:/Windows/Fonts/YuGothR.ttc"
    LabelBase.register(DEFAULT_FONT, fn_regular=font_path)
elif platform == 'android':
    # Androidの場合はassetsフォルダ内のフォントを使用
    LabelBase.register(DEFAULT_FONT, fn_regular='assets/fonts-japanese-gothic.ttf')
else:
    # その他のプラットフォームではデフォルトフォントを使用
    LabelBase.register(DEFAULT_FONT, fn_regular='DejaVuSans.ttf')

class MyApp(App):
    def build(self):
        layout = BoxLayout(orientation='vertical', spacing=10, padding=10)
        button = Button(text='クリックしてください')
        button.bind(on_press=self.on_button_click)
        self.label = Label(text='ボタンがクリックされるとここに表示されます')
        layout.add_widget(button)
        layout.add_widget(self.label)
        return layout

    def on_button_click(self, instance):
        self.label.text = 'ボタンがクリックされました！'

if __name__ == '__main__':
    MyApp().run()
EOF

# Buildozerプロジェクトの初期化とビルド
echo "Initializing and building the Buildozer project..."
buildozer init
# buildozer.specファイルの修正
echo "Updating buildozer.spec file..."
sed -i 's/^source.include_exts = .*/source.include_exts = py,png,jpg,kv,atlas,ttf/' buildozer.spec
sed -i '/^source.include_patterns = /d' buildozer.spec

echo 'source.include_patterns = assets/*.ttf' >> buildozer.spec


sudo buildozer android clean
sudo buildozer -v android debug 2>&1 | tee buildozer.log

```

上記を貼り付けてCtrl + Oで保存。Ctrl + Xでnanoを終了します。




実行権限を付与してからshファイルを実行します。
```cmd:cmd
chmod +x setup_buildozer.sh
./setup_buildozer.sh
```

どうでしょうか？動いたでしょうか？
動いたらWindows自体にBluestacksをInstallして\\wsl.localhost\から作業Folderのbin内にあるapkファイルを実行するとPC上で動作確認ができます。

動かない場合は・・・

・WindowsPCでWSLを使用している場合、下記のアドレスでWindowsからアクセスできるのでmain.pyの動作やフォントのフォルダ、ログなどを確認するといいかもしれません。
```
\\wsl.localhost\Ubuntu<version>\home\<username>
```

- shファイルの注意事項にあるようにpyenvを使用している環境では難易度が上がるようです。
- buildozerは環境に敏感なので場合によってはWSL2をアンインストールして最初からやり直した方が良いかもしれませんね。

- 別バージョンのshファイルも載せます。
　こちらの方が成功率は高いかもしれません。
  ・ buildozerのSourceをgitで取得して、Build。
  ・ pyenvを使用。　
``` shell:setup_buildozer_git.sh
#!/bin/bash
echo WSL1ではlibffiがBinaryの問題を起こす。WSL2で起動必要。
echo pyenvでのInstallを行うと仮想環境に.buildozerをInstallする為、NGになる事あり。
echo 日本語フォントを使用するとapk起動しない問題あり。ubuntuのフォントを移植する方法が使える。
echo Ubuntu 20.04 buildozerのInstallをし、android debugするとOK.
echo Ubuntu 20.04 buildozerのSourceをGitでDLしBuildしandroid debugするとOK.
echo Ubuntu 22.04 sudoを付けてbuildozer android debugをしないと権限問題で停止。

# システムの更新
echo "Updating and upgrading the system..."
sudo apt update
sudo apt upgrade -y

# 必要なパッケージのインストール
echo "Installing required packages..."
sudo apt-get install -y build-essential wget git zip unzip openjdk-17-jdk  autoconf libtool cmake python3.11 python3-pip fonts-takao
curl https://pyenv.run | bash

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv virtualenv-init -)"


#pip3 install --user --upgrade Cython

#export PATH=$PATH:~/.local/bin/
#buildozer version
# 設定を反映
source ~/.bashrc

pyenv install 3.11

sudo apt install -y python3
pip3 install kivy

cd ~
git clone https://github.com/kivy/buildozer
git pull
cd buildozer
python3 setup.py build
sudo python3 setup.py install


cd ~\buildozer\.buildozer/android/platform/python-for-android
git pull
python3 setup.py build
sudo python3 setup.py install

cd ~\buildozer\.buildozer\android\platform\build-arm64-v8a_armeabi-v7a\build\other_builds\pyjnius-sdl2\armeabi-v7a__ndk_target_21\pyjnius
git pull
python3 setup.py build
sudo python3 setup.py install




cd ~\buildozer\
# 日本語フォントをassetsフォルダにコピー
echo "Copying Japanese font to assets folder..."
mkdir -p assets
cp /usr/share/fonts/truetype/fonts-japanese-gothic.ttf assets/

# Buildozerバージョン確認
buildozer version
read 

# サンプルアプリの作成
echo "Creating a sample Kivy app..."
cat << EOF > main.py
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout

from kivy.core.text import LabelBase, DEFAULT_FONT
from kivy.utils import platform

# フォントのパスを指定してフォントを設定する
if platform == 'win':
    # Windowsの場合はシステムフォントを使用
    font_path = "C:/Windows/Fonts/YuGothR.ttc"
    LabelBase.register(DEFAULT_FONT, fn_regular=font_path)
elif platform == 'android':
    # Androidの場合はassetsフォルダ内のフォントを使用
    LabelBase.register(DEFAULT_FONT, fn_regular='assets/fonts-japanese-gothic.ttf')
else:
    # その他のプラットフォームではデフォルトフォントを使用
    LabelBase.register(DEFAULT_FONT, fn_regular='DejaVuSans.ttf')

class MyApp(App):
    def build(self):
        layout = BoxLayout(orientation='vertical', spacing=10, padding=10)
        button = Button(text='クリックしてください')
        button.bind(on_press=self.on_button_click)
        self.label = Label(text='ボタンがクリックされるとここに表示されます')
        layout.add_widget(button)
        layout.add_widget(self.label)
        return layout

    def on_button_click(self, instance):
        self.label.text = 'ボタンがクリックされました！'

if __name__ == '__main__':
    MyApp().run()
EOF

export PATH=$PATH:~/buildozer
buildozer init
# buildozer.specファイルの修正
echo "Updating buildozer.spec file..."
sed -i 's/^source.include_exts = .*/source.include_exts = py,png,jpg,kv,atlas,ttf/' buildozer.spec
sed -i '/^source.include_patterns = /d' buildozer.spec
echo 'source.include_patterns = assets/*.ttf' >> buildozer.spec


buildozer android clean
sudo buildozer -v android debug 2>&1 | tee buildozer.log
```