Linuxインストール後の設定 〜 kivyの環境構築 〜 Androidのapkを作るまで

自分用の備忘録です。これで少しでもLinux使いが増えると嬉しい。

- OS ... [Linux Mint](https://linuxmint.com/) 20.2 MATE Edition (Ubuntu 20.04 LTS 派生)
- PC ... Intel [NUC5i3RYH](https://ark.intel.com/content/www/jp/ja/ark/products/83257/intel-nuc-kit-nuc5i3ryh.html) (かろうじて1080pのYoutube動画が観られる程度の弱いPC。3D gameはもってのほか。)
- RAM ... 16GB (最低8GBは無いとAndroidアプリを作る時にきついです)

# OS篇

## swapfileを無効化

まずは`$ free`でswapfileが現在有効になっているかの確認。

```shell
$ free
              total        used        free      shared  buff/cache   available
Mem:       16280664      550208    14756408       78572      974048    15356640
Swap:       2097148           0     2097148
```

swapfileをまだ使ってはいないものの<ruby>何時<rt>いつ</rt></ruby>でも使えるように備えてある事が分かります。swapfileはSSDが主流となった<ruby>今日<rt>こんにち</rt></ruby>においては利より害のほうが大きいと思われるので`$ sudo swapoff -a`で現在有効になっているswapfileを無効化します。

```shell
$ sudo swapoff -a
$ free
              total        used        free      shared  buff/cache   available
Mem:       16280648     1457856    13248092      456244     1574700    14062524
Swap:             0           0           0
```

次はswapfileを永遠に無効化します。linuxの設定fileの中にOS起動時にswapfileを作るよう指示している者が居るのでそれを次のように弄ってあげます。`$ sudo xed /etc/fstab`(`xed`はLinux Mint MATE Editionに標準装備されているtext editor)と打ってfileを開いたら

```text
(#から始まる行はcommentなので省略)
UUID=略    /          ext4    errors=remount-ro  0       1
UUID=略    /boot/efi  vfat    umask=0077         0       1
/swapfile  none       swap    sw                 0       0
```

三列目が`swap`である行を全てcomment out。

```text
# /swapfile  none       swap    sw                 0       0
```

そして残った`/swapfile`はもう無用なので消しておきます (`$ sudo rm /swapfile`)。

## 作業directoryとしてRAM Diskが使われるようにする

続いてlinuxの一時file置き場である`/tmp`にRAM Diskが使われるようにしてあげます。これを

- internetから落とすファイルの保存先
- アプリ開発

等とにかく色んな物に利用してSSDの負担を減らすのが目的です。

### 起動時に自動でRAM Diskが作られるようにする

先程のように`$ sudo xed /etc/fstab`と打って`/etc/fstab`を開いたら

```text
tmpfs /tmp tmpfs defaults,noatime,size=8G 0 0
```

をfileの最後に加えます。`size=8G`がRAM Diskの容量を指定している部分で、google playで自分のアプリを公開する事を考えているなら5G、公開せずに自分用としてしか使わない場合でも最低4Gは欲しいところです。

:::note warn
このファイルを弄り損ねるとOSが起動しなくなるので注意。仮にそうなったとしてもLive USBで別にOSを立ち上げてファイルを直せばいいだけなので大した問題ではないですが。
:::

### 直ちにRAM Diskを作る

今は再起動せずに直ちにRAM Diskを利用したいので `$ sudo mount -a` と打って`/etc/fstab`の編集結果を直ちに反映させます。

## OSを更新

画面右下のタスクトレイにあるアップデートマネージャを用いてOS更新、すると再起動を促されるので従います。

## 日本語名のdirectoryを英語名にする

「ドキュメント」「ミュージック」といった日本語名のdirectoryがあるので「Documents」「Music」といった英語名にします。`$ LANG=C xdg-user-dirs-gtk-update`

## windowをdrag/resize中に中身を描画させない

これが有効だとKivyのwindowをresizeした時に劇的に重くなってしまうので無効にしておきます。screenshotは英語になっていますがOSの言語設定を日本語にしていればちゃんと日本語になります。(できればcommand lineでこの設定を弄る方法が知りたいです)。

![Desktop Settings](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144673/0c5eefa0-8a2b-ca83-0f24-970603ab5e8d.png)

## Alt key + mouseによるwindowの移動を防ぐ

Visual Studio Codeで複数cursorを置くときの操作とかぶってしまってそれが出来なくなってしまうので無効化あるいはAlt以外のkeyを割り当てます。(できればcommand lineでこの設定を弄る方法が知りたいです)。
![Window Preference](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144673/9166b57e-0f56-b1a1-9c77-1f43b45157ea.png)

## Visual Studio Codeを入れる

[公式サイト](https://code.visualstudio.com/)より.debファイルを落として

```shell
$ sudo apt install .debファイル
```

と打つだけです。入れた後の設定に関しては幾らでも解説が見つかるので省きます。

# Python篇

私は pyenv + pipenv もしくは pyenv + poetry の組み合わせで使っているのでそれらを入れます。

## [pyenv](https://github.com/pyenv/pyenv)

初期状態ではgitが入ってなかったので入れたら(`$ sudo apt install git`)その後は[Basic GitHub Checkout](https://github.com/pyenv/pyenv#basic-github-checkout)の手順に従ってpyenvを入れます。入れたらpyenvを有効にする為にloginし直し、install可能なpythonのversionを列挙。

```shell
$ pyenv install --list
Available versions:
  2.1.3
  2.2.3
  2.3.7
  2.4.0
  .
  .
```

その中で使いたい物を好きなだけinstall。

```shell
$ pyenv install 3.8.10  # CPython 3.8.10
$ pyenv install 3.8.12  # CPython 3.8.12
$ pyenv install 3.9.6   # CPython 3.9.6
```

:::note info
PCにはpyenvのgit repositoryがまるごと入るので、pyenvを更新したい時は
cd ~/.pyenv
git pull origin master
と打つだけ。
:::

## [poetry](https://python-poetry.org/)

```shell
$ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py | python -
$ echo "export PATH=\$HOME/.local/bin:\$PATH" >> ~/.bashrc
$ poetry config virtualenvs.in-project true
```

:::note warn
実際に打ったcommandを載せはしましたが、これをcopy&pasteするような真似はせずにその都度公式のdocを読んで従って下さい。
:::

## [pipenv](https://github.com/pypa/pipenv)

```shell
$ pyenv which python3
/usr/bin/python3
```

でsystemのpythonが有効な事を確かめたら

```shell
$ python3 -m pip install --user pipenv
```

と打って入れます。その後

```shell
$ echo "export PIPENV_VENV_IN_PROJECT=1" >> ~/.bashrc
```

と打ってproject内に`.venv`が作られるようにしたら、これまでの`.bashrc`への編集を反映させるためにterminalを再起動。その後

```shell
$ poetry --help
$ pipenv --help
```

などと打って各道具が使えるようになっている事を確かめて終わりです。使えない場合は`~/.local/bin`にそれぞれのfileがある事と環境変数PATHに`~/.local/bin`が含まれている事を確かめる。

# Kivy篇

Kivyを自分でcompileしたりandroidのapk/aabを作るのに必要な物を入れていきます。自分でせずともcompile済みの物がPyPIには上がってはいるのですができた方が便利なので入れます。[Installation Components](https://kivy.org/doc/master/installation/installation-linux.html#installation-components)に書いてある物に加えて`xclip`と`xsel`のどちらか好きな方を入れたら完了。

```shell
$ apt install xclip
$ apt install xsel
```

:::note info
xclipやxselは無くてもKivyは動きますが無いとTextInputを使った時に警告が出ます。もしかしたら無いとcopy&pasteができないのかもしれません(未確認)。
:::

次は以下のlinkにあるAndroidのapk/aabを作るのに必要な物を入れていくのですが、ここではaptを用いる物だけに留め、pipを用いる物は各アプリのプロジェクトの仮想環境内で入れる事にします。

https://buildozer.readthedocs.io/en/latest/installation.html

# アプリ開発篇

ここからがアプリの開発を始める度に行う手順となります。

## projectのroot directoryを作る

```shell
# SSDの負担を減らすためにRAM Disk下に作ります。
# いつでもPCが固まっても大丈夫なように小まめに git push 推奨。
$ mkdir /tmp/myproject
$ cd /tmp/myproject
```

## 仮想環境を作り各種install

### pipenv派

```shell
# 使いたいversionのpythonをpyenvで入れた物の中から選ぶ
$ pipenv --python 3.9.6

# 仮想環境に入る
$ pipenv shell

# kivyを入れる
# 開発版
$ pipenv install "kivy[base] @ https://github.com/kivy/kivy/archive/master.zip"
# 安定版
$ pipenv install "kivy[base] @ https://github.com/kivy/kivy/archive/stable.zip"
```

### poetry派

`$ poetry init`と打つと始まる問答に答えたら以下のようにしてkivyを入れます。

```shell
# 開発版
$ poetry add https://github.com/kivy/kivy/archive/master.zip
# 安定版
$ poetry add https://github.com/kivy/kivy/archive/stable.zip

$ poetry install

# 仮想環境に入る
$ poetry shell
```

:::note info
poetryに訊かれるpackage名はPyPIに上げる時には使われますがandroidアプリのpackage名には影響ありません。
:::

## PC上で開発

installが終わったらPC上でアプリを開発し十分にtestします。

## buildozerを入れる

今からbuildozerを入れていくのですが、もしplay storeで公開するつもりなのならaab形式で出力できる[misl6氏の物](https://github.com/misl6/buildozer/tree/feat/aab-support)が要ります。そうじゃなければ公式の物でも構いません。

### pipenv派

```shell
# aab対応版 (play storeで公開予定ならこっち)
$ pipenv install --dev Cython==0.29.19 virtualenv git+https://github.com/misl6/buildozer@feat/aab-support#egg=buildozer
# 開発版 (安定版は長らく更新されていないのでこっちを推奨)
$ pipenv install --dev Cython==0.29.19 virtualenv https://github.com/kivy/buildozer/archive/master.zip
# 安定版
$ pipenv install --dev Cython==0.29.19 virtualenv buildozer
```

### poetry派

```shell
# aab対応版 (play storeで公開予定ならこっち)
$ poetry add --dev Cython==0.29.19 virtualenv git+https://github.com/misl6/buildozer@feat/aab-support
# 開発版 (安定版は長らく更新されていないのでこっちを推奨)
$ poetry add --dev Cython==0.29.19 virtualenv https://github.com/kivy/buildozer/archive/master.zip
# 安定版
$ poetry add --dev Cython==0.29.19 virtualenv buildozer
```

## buildozer.specを編集

`$ buildozer init`と打つと`buildozer.spec`が作られるので適切に設定します。

```ini
# アプリに付ける名前。日本語も使える。
title = Test Application

# Package name (これとPackage domainを繋げた物がandroidのpackage名となる)
package.name = testapp

# Package domain
package.domain = jp.gottadiveintopython

# main.pyのあるdirectory
source.dir = .

# 画像や音声、フォントなどのアプリに含めたいファイルの拡張子を全て指定
source.include_exts = py,png,ogg,mo,ttf

# アプリに含めたくないdirectory
source.exclude_dirs = .venv, venv, .git, tests, bin

# 求める権限
android.permissions =

# recipe及び依存module (開発で使ったpythonのversionと揃える)
requirements = python3==3.9.6,kivy==master,hostpython3==3.9.6,android,plyer

# アプリが対応する端末の向き landscape(横持ち) sensorLandscape(横持ち) portrait(縦持ち) all(全方向)
orientation = all

# 使用するpython-for-androidを開発版(develop)に
p4a.branch = develop

# 自分のアプリが吐くlogだけが出力されるようにする。これがFalseだと大量の無関係なlogに自分のlogが埋もれて
# しまって見づらいので最初はTrueにしておく。もし何もlogが吐かれないようならアプリの起動に失敗している可能
# 性があるのでFalseに戻し原因を探る。
android.logcat_pid_only = True

# logのlevel。これは必ずに最大にしておく。
log_level = 2
```

## apkを作成

android端末を開発者モードでPCに繋いだら

```shell
$ buildozer android debug deploy run logcat
```

と打って実機上でtest。最初はかなり時間がかかる(20-30分)ので何か別の作業をしながら時々エラーが起きていないか画面を覗くのがお薦めです。今回は一つだけエラーが出ましたがすんなり[解決](https://github.com/libffi/libffi/issues/210)できました。

## 最適なABI(CPU命令セット)の選択

自分の端末は32bitの[ABI](https://developer.android.google.cn/ndk/guides/abis?hl=ja)にしか対応してないのでABIの値は初期値の`armeabi-v7a`のままで良いですが、64bitのABIに対応した端末を持っている人は`buildozer.spec`の以下の行を弄って最適なマシンコードを吐かせたほうが良いと思われます。

```
# (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64
android.arch = armeabi-v7a
# aab対応版では複数の命令セットを選べます。複数選ぶとbuildにかかる時間がその分倍増するので開発中は一つだけにし、release buildの際に複数選ぶのがお薦めです。
android.archs = armeabi-v7a,arm64-v8a
```

端末が対応しているABIを調べるにはPCに開発者モードで端末を繋げた状態で`$ adb shell getprop | grep cpu.abi`と打ちます。以下が私の端末での出力で

```
[ro.product.cpu.abi]: [armeabi-v7a]
[ro.product.cpu.abi2]: [armeabi]
[ro.product.cpu.abilist]: [armeabi-v7a,armeabi]
[ro.product.cpu.abilist32]: [armeabi-v7a,armeabi]
[ro.product.cpu.abilist64]: []
```

64bitのABIには対応していないのが分かります。

## release build

apkによる実機testが終わったら次は公開用aabの作成です。`buildozer.spec`に以下のように複数のABIを書いて

```
# play storeで公開するには32bitと64bitのABI各一つ以上が必要となる。
android.archs = armeabi-v7a,arm64-v8a,x86_64
```

[署名用のkeystoreファイルを用意して環境変数を設定][guhan]したら

```shell
$ buildozer android release
```

と打ってaabが出来上がるのを待ちます。その後は一般的なandroid開発と手順は変わらないので手順は省きます。

# 参考資料

- [Guhan Sensam氏の資料][guhan](aabを作るのに役立った)
- [Working on Android](https://python-for-android.readthedocs.io/en/latest/apis/)(python-for-androidのdocは全て重要ですが中でもこの部分が特に)

[guhan]:https://gist.github.com/Guhan-SenSam/35c5ed7da254a7c0141e6a8b6101eb33