BeeWareことはじめ

以前から興味のあった[BeeWare](https://pybee.org/)を使ってみました。

# BeeWareとは

BeeWareは複數の環境に向けたアプリを作る為の道具の集合體で、Linux,Windows,MacOS,iOS,Android,Django用への出力ができるようです。またPyQtやTkinterやwxPythonなどが元々他の言語で書かれた物をPythonで扱えるように包んだ物なのに對し、BeeWareは最初からPython用として作られている為、Python言語の持つ力を活かし易いそうです。同じような物として私が真っ先に思い浮かぶのが[Kivy](https://kivy.org/)ですが、KivyがOpenGLを使って自前でGUI部品を用意するのに対し、BeeWareはOSの持っているGUI部品をそのまま使うようなので、車輪の再發明にはなってないということなんだと思います、多分。

# BeeWareの強み

私がBeeWareに惹きつけられた理由が[これ](https://www.youtube.com/watch?v=qaPzlIJ57dk#t=18m34s)です。通常GUIアプリケーションにおいて

```python3:駄目なコード
def some_callback():
    # 處理A
    time.sleep(10)
    # 處理B
```

のようなコードは書けません。`time.sleep(10)`の間完全に處理が止まってUIが固まってしまうからです。これをKivyで正しく實装するなら

```python3:Kivyでのやり方
def some_callback(__):
    # 處理A
    def some_callback2(__):
        # 處理B
    Clock.schedule_once(some_callback2, 10)
```

となり讀みにくいコードになるところですが、BeeWareだと

```python3:BeeWareでのやり方1
async def some_callback():
    # 處理A
    await asyncio.sleep(10)
    # 處理B
```

か

```python3:BeeWareでのやり方2
def some_callback():
    # 處理A
    yield 10
    # 處理B
```

で濟むみたいです。素晴らしい。

# 使ってみる

實際に使ってみます。上に貼ったPycon2018の動畫内の手順を參考にしました。

## pipenvで假想環境を作って有效化

```sh
mkdir ./test_beeware
cd ./test_beeware
mkdir .venv
pipenv --python 3.5.0
pipenv shell
```

PythonのVersionですが[ここ][briefcase_gs]に

> Briefcase (and the whole BeeWare toolchain) requires Python 3. Support for different Python 3 minor versions varies depending on the platform you’re targetting; Python 3.5 will give you the best results.

と書かれているので素直に従ってPython3.5系を選びました。

## BeeWareをInstall

```
pipenv install --pre beeware
```

`--pre`が要るのが**參考動畫と違う點**

[briefcase_gs]:https://briefcase.readthedocs.io/en/latest/background/getting-started.html

## 環境毎の依存物を入れる

私はUbuntu16.04派生のOSを使っているので[ここ][briefcase_gs]のUbuntu 16.04のところに書いてある

```
sudo apt-get install python3-gi gir1.2-webkit2-4.0
```

を實行しました。また記述元は忘れたのですが

```
sudo apt-get install python3-dev python3-gi python3-gi-cairo gir1.2-gtk-3.0 libgirepository1.0-dev libcairo2-dev
```

というのもしておきました。

## Projectを作成

`beeware new`と打つと幾つか質問され後にProjectが初期化されました。以下がその時の記錄。

```
略 $ beeware new
Creating new BeeWare project using the Briefcase Template...
>>> cookiecutter https://github.com/pybee/briefcase-template.git

app_name [appname]: hoge
formal_name [App Name]: hoge
description [An app that does lots of stuff]: My first time beeware project
author [Jane Developer]: gotta_dive_into_python     
author_email [jane@example.com]: hoge@hoge.jp                 
bundle [com.example]: jp.hogeeee
Select license:
1 - BSD license
2 - MIT license
3 - Apache Software License
4 - GNU General Public License v2 (GPLv2)
5 - GNU General Public License v2 or later (GPLv2+)
6 - GNU General Public License v3 (GPLv3)
7 - GNU General Public License v3 or later (GPLv3+)
8 - Other
Choose from 1, 2, 3, 4, 5, 6, 7, 8 [1]: 2  # MITを選んだ
Select gui_framework:
1 - Toga
2 - None
Choose from 1, 2 [1]: 1  # Togaを選んだ
```

`app_name`と`bundle`はおそらくAndroidへ持っていく時のpackge名になると思います。(上の場合だと`jp.hogeeee.hoge`)。

### 現在のDirectoryの状態

```
.
├── hoge
│   ├── hoge
│   │   ├── app.py
│   │   ├── __init__.py
│   │   └── __main__.py
│   ├── README.rst
│   └── setup.py
├── Pipfile
└── Pipfile.lock

```

## 實行

`hoge`というDirectoryが作られているので`cd ./hoge`で入ってから`python -m hoge.__main__`(**ここでも參考動畫に從ったコマンド`python -m hoge`では`ImportError: No module named 'hoge'`が出てうまくいきませんでした**)と打つと

![blank_window.png](https://qiita-image-store.s3.amazonaws.com/0/144673/20ce4da2-a3f7-7e62-d798-c152f1657a7e.png)

Windowが表示されましたが、中が空だと本當にできているのか不安なので文字列を表示させてみます。

```python3:app.py
import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW


class Hoge(toga.App):
    def startup(self):
        # Create a main window with a name matching the app
        self.main_window = toga.MainWindow(title=self.name)

        # Create a main content box
        main_box = toga.Box()
        main_box.add(toga.Label(text='Hello BeeWare'))  # 追加

        # Add the content on the main window
        self.main_window.content = main_box

        # Show the main window
        self.main_window.show()


def main():
    return Hoge('hoge', 'jp.hogeeee.hoge')
```

![Screenshot at 2018-06-18 23-58-59.png](https://qiita-image-store.s3.amazonaws.com/0/144673/d19a232f-8df4-ba4c-a212-5b47c9484923.png)

## いろんな環境向けに出力

次は一番重要な各環境へ出力する機能を見ていきます。

### Linux

Linuxで開發していながらLinux向けへの出力を試した理由ですが、何か單一のFileにまとめてくれるのかなと思ったからです。

```
beeware build linux
```
すると`linux`というDirectoryができて、中身は

```text:linuxの中身(全部載せると長くなるので表示する階層の深さを制限している)
│
├── linux
│   ├── app
│   │   ├── hoge
│   │   ├── hoge-0.0.1.dist-info
│   │   └── README
│   ├── app_packages
│   │   ├── gbulb
│   │   ├── gbulb-0.5.3.dist-info
│   │   ├── README
│   │   ├── tests
│   │   ├── toga
│   │   ├── toga_core-0.3.0.dev8.dist-info
│   │   ├── toga_gtk
│   │   ├── toga_gtk-0.3.0.dev8.dist-info
│   │   ├── travertino
│   │   └── travertino-0.1.2.dist-info
│   └── hoge
```

となってました。一番下の`hoge`というのを實行することでアプリを起動できはしたのですが、`hoge`のサイズを見るとたったの147bytesです。嫌な予感がして中身を見ると

```text:hogeの中身
#!/bin/bash
# Set PYTHONPATH to point at app and app_packages directory
export PYTHONPATH=./app:./app_packages

# Start the app
python3 -s -m hoge
```

となってました。というわけで單一Fileにはまとめてくれなかったようです。

### iOS, MacOS

私はiOS,MacOSどちらも持っておらず實機で確かめようがないのでやる意味は薄いですが、試してみます。

```text:iOSの場合
beeware build ios
```

```text:MacOSの場合
beeware build macos
```

どちらも標準出力に`Successfully built hoge`と出ているので、うまくいっているのかもしれません。

```text:Directoryの中身(表示する階層の深さを制限している)
├── iOS
│   ├── app
│   │   ├── hoge
│   │   ├── hoge-0.0.1.dist-info
│   │   └── README
│   ├── app_packages
│   │   ├── README
│   │   ├── rubicon
│   │   ├── rubicon_objc-0.2.10.dist-info
│   │   ├── rubicon_objc-0.2.10-py3.5-nspkg.pth
│   │   ├── tests
│   │   ├── toga
│   │   ├── toga_core-0.3.0.dev8.dist-info
│   │   ├── toga_iOS
│   │   ├── toga_iOS-0.3.0.dev8.dist-info
│   │   ├── travertino
│   │   └── travertino-0.1.2.dist-info
│   ├── hoge
│   │   ├── en.lproj
│   │   ├── hoge-Info.plist
│   │   ├── hoge-Prefix.pch
│   │   ├── Images.xcassets
│   │   └── main.m
│   ├── hoge.xcodeproj
│   │   └── project.pbxproj
│   ├── Support
│   │   ├── BZip2
│   │   ├── OpenSSL
│   │   ├── Python
│   │   └── XZ
│   └── VERSIONS
├── macOS
│   └── hoge.app
│       └── Contents
```

[公式の說明](https://briefcase.readthedocs.io/en/latest/tutorial/tutorial-0.html#ios)にはiOS向けの出力でできた物はXCodeを使って開くと書いてあるので、後の作業はおそらくMacOSを持ってないとできないのでしょう。

### Django

[公式](https://briefcase.readthedocs.io/en/latest/background/getting-started.html#django)にはNode(6.9.x)とNPM(4.x or higher)が要ると書いてあります。普通に`apt-get install nodejs npm`とするとversionが古かったので[この記事](https://qiita.com/seibe/items/36cef7df85fe2cefa3ea)を參考にして入れました。その結果入ったversionはNode(10.4.1),NPM(6.1.0)で、Nodeのversionだけ要求と合ってないのですが、とりあえずこれで進めてみます。

```
beeware build django
```

buildがうまくいったので

```
beeware run django
```

で実行したところWebBrowserが立ち上がったのですが、`Unable to connect`と出ています。またTerminal
を見ると`ImportError: No module named 'toga.django'`と出ていたのでServerの立ち上げに失敗したのだと思います。このエラーをググった所この[issue](https://github.com/pybee/briefcase/issues/115)が見つかり、參考にして`toga.django`のversionを下げたりもしましたがうまくいきませんでした。疲れたので今回は諦めます。

### Android

#### AndroidStudioをInstall

[公式](https://developer.android.com/studio/)よりAndroidStudioを落としたら、好きなところに解凍して中にある`bin/studio.sh`を實行します。Install方法として`Standard`と`Custom`の二つから選べと言われたので[ここ](https://briefcase.readthedocs.io/en/latest/background/getting-started.html#android)の指示に從って`Standard`を選びました。

Install途中では以下の畫面
![Screenshot at 2018-06-18 22-19-51.png](https://qiita-image-store.s3.amazonaws.com/0/144673/12d8f627-479a-bb0d-8807-8bfbd22682c8.png)
がでてきました。讀むにどうやらLinuxで開發する場合はAndroidEmulatorを高速化できるようなのでしておきましょう。[リンク先](https://developer.android.com/studio/run/emulator-acceleration?utm_source=android-studio#vm-linux)の指示に従って`sudo apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils ia32-libs-multiarch`としました。

#### 環境變數を設定

[ここ](https://briefcase.readthedocs.io/en/latest/background/getting-started.html#android)の指示に從って環境變數を設定します。AndroidStudioのInstall過程でAndroidSDKが`~/Android/Sdk`に落とされているのでそこへpathを通しました。

```
export ANDROID_SDK_HOME="~/Android/Sdk"
export ANDROID_HOME="~/Android/Sdk"
export PATH="$PATH:$ANDROID_SDK_HOME/platform-tools:$ANDROID_SDK_HOME/tools:$ANDROID_SDK_HOME/tools/bin"
```

#### Android假想Deviceを作成

[ここ](https://developer.android.com/studio/run/managing-avds)には
![Untitled.png](https://qiita-image-store.s3.amazonaws.com/0/144673/f5e23365-917c-5900-ce15-1cf3a41a1c14.png)
と書いてありますが`Tool`メニューに`Android`という項目なんてありません。調べたところAndroidStudio3.0からUIが變わったようで、[これ](https://ja.stackoverflow.com/questions/40928/android-studio%E3%81%AEavd-manager%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)を參考になんとか`AVD Manager`を開くことができました。

##### 空き容量が足りない

假想Deviceを作る過程で一時Directoryを大量に使うようで、私の環境では一時DirectoryとしてRamDiskを使っていて4GB近く空きがあったにも関わらず足りないと言われてしまいました。この為にわざわざOSの設定を變える氣にはなれないので斷念します。

# 最後に

というわけで

- Linux -> 成功
- Android -> 失敗
- iOS, MacOS -> 持ってないので確かめられない
- Django -> 失敗

という結果に終わりました。AndroidとDjango、誰かうまくいったら教えてください。