python3使用kivy生成Android程式

技術背景

雖然現在蘋果佔據了很大一部分的市場,但是從銷量數據來看,Android還是佔據了人口的高地。這裡我們介紹一個用python的kivy+buildozer來進行AndroidAPP開發的簡單教程,從整個過程中來看,環境部署這一塊所需的工作量是非常大的,可能這就是從0到1的困難?文末我們會總結出,哪一種方案是最容易的,希望能夠對大家有所幫助。

kivy的安裝

官方推薦的方式是使用虛擬環境來進行安裝和部署,關於虛擬環境的相關操作,在前面寫過的一篇部落格中有稍微詳細一點的介紹,這裡我們先給出操作步驟。假定我們已經在環境中用pip安裝了virtualenv,那麼我們先構建一個kivy的虛擬環境:

[dechin@dechin-manjaro kivy]$ virtualenv kivy_venv
created virtual environment CPython3.8.5.final.0-64 in 123ms
  creator CPython3Posix(dest=/home/dechin/projects/2021-python/kivy/kivy_venv, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/home/dechin/.local/share/virtualenv)
    added seed packages: pip==21.0.1, setuptools==54.1.2, wheel==0.36.2
  activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator

構建完成後會在當前目錄下生成一個文件夾:

[dechin@dechin-manjaro kivy]$ ll
總用量 4
drwxr-xr-x 4 dechin dechin 4096  4月  3 22:00 kivy_venv

我們可以用source ./kivy_env/bin/activate的方式對虛擬環境進行激活,激活後每次執行系統操作指令,會在指令的最前端顯示一個虛擬環境的標識,比如這裡我們在虛擬環境中用pip來安裝kivy:

(kivy_venv)[dechin@dechin-manjaro kivy]$ python3 -m pip install kivy -i //mirrors.cloud.tencent.com/pypi/simple 
Looking in indexes: //mirrors.cloud.tencent.com/pypi/simple
Collecting kivy
  Downloading //mirrors.cloud.tencent.com/pypi/packages/fd/4c/eb36890982bb11daaea68df62486ce36bde26cc9bec6a57e02c0e2aa8982/Kivy-2.0.0-cp38-cp38-manylinux2010_x86_64.whl (22.2 MB)
     |████████████████████████████████| 22.2 MB 7.7 MB/s 
Collecting pygments
  Downloading //mirrors.cloud.tencent.com/pypi/packages/3a/80/a52c0a7c5939737c6dca75a831e89658ecb6f590fb7752ac777d221937b9/Pygments-2.8.1-py3-none-any.whl (983 kB)
     |████████████████████████████████| 983 kB 688 kB/s 
Collecting Kivy-Garden>=0.1.4
  Downloading //mirrors.cloud.tencent.com/pypi/packages/7d/68/decaee596ff8168a39432eb3949fc7c0be952ebb9467806823bffc165d48/kivy-garden-0.1.4.tar.gz (6.8 kB)
Collecting docutils
  Downloading //mirrors.cloud.tencent.com/pypi/packages/9a/65/76aea825b59727b556cca74e28d68e4d73244d2e1e8a8945c29d6d3d5e11/docutils-0.17-py2.py3-none-any.whl (575 kB)
     |████████████████████████████████| 575 kB 912 kB/s 
Collecting requests
  Downloading //mirrors.cloud.tencent.com/pypi/packages/29/c1/24814557f1d22c56d50280771a17307e6bf87b70727d975fd6b2ce6b014a/requests-2.25.1-py2.py3-none-any.whl (61 kB)
     |████████████████████████████████| 61 kB 1.0 MB/s 
Collecting certifi>=2017.4.17
  Downloading //mirrors.cloud.tencent.com/pypi/packages/5e/a0/5f06e1e1d463903cf0c0eebeb751791119ed7a4b3737fdc9a77f1cdfb51f/certifi-2020.12.5-py2.py3-none-any.whl (147 kB)
     |████████████████████████████████| 147 kB 726 kB/s 
Collecting idna<3,>=2.5
  Downloading //mirrors.cloud.tencent.com/pypi/packages/a2/38/928ddce2273eaa564f6f50de919327bf3a00f091b5baba8dfa9460f3a8a8/idna-2.10-py2.py3-none-any.whl (58 kB)
     |████████████████████████████████| 58 kB 644 kB/s 
Collecting urllib3<1.27,>=1.21.1
  Downloading //mirrors.cloud.tencent.com/pypi/packages/09/c6/d3e3abe5b4f4f16cf0dfc9240ab7ce10c2baa0e268989a4e3ec19e90c84e/urllib3-1.26.4-py2.py3-none-any.whl (153 kB)
     |████████████████████████████████| 153 kB 564 kB/s 
Collecting chardet<5,>=3.0.2
  Downloading //mirrors.cloud.tencent.com/pypi/packages/19/c7/fa589626997dd07bd87d9269342ccb74b1720384a4d739a1872bd84fbe68/chardet-4.0.0-py2.py3-none-any.whl (178 kB)
     |████████████████████████████████| 178 kB 827 kB/s 
Building wheels for collected packages: Kivy-Garden
  Building wheel for Kivy-Garden (setup.py) ... done
  Created wheel for Kivy-Garden: filename=Kivy_Garden-0.1.4-py3-none-any.whl size=4532 sha256=70dd6bf0a005868e9aca0710f7b717432bda7925c0fac236b99d2527ec112b78
  Stored in directory: /home/dechin/.cache/pip/wheels/c9/d0/d4/2cb72931b74be8ce5fbee5ed87d66366f356a3161ea772d015
Successfully built Kivy-Garden
Installing collected packages: urllib3, idna, chardet, certifi, requests, pygments, Kivy-Garden, docutils, kivy
Successfully installed Kivy-Garden-0.1.4 certifi-2020.12.5 chardet-4.0.0 docutils-0.17 idna-2.10 kivy-2.0.0 pygments-2.8.1 requests-2.25.1 urllib3-1.26.4

為了加快安裝,我們使用了騰訊的pip源。安裝完成後,可以在已安裝列表中看到剛才安裝的kivy及其依賴組件:

(kivy_venv)[dechin@dechin-manjaro kivy]$ python3 -m pip list
Package     Version
----------- ---------
certifi     2020.12.5
chardet     4.0.0
docutils    0.17
idna        2.10
Kivy        2.0.0
Kivy-Garden 0.1.4
pip         21.0.1
Pygments    2.8.1
requests    2.25.1
setuptools  54.1.2
urllib3     1.26.4
wheel       0.36.2

kivy的hello world

配置好kivy的環境後,我們可以直接在電腦端測試python所編寫的app實例,比如kivy的hello world:

# kivy_hello_world.py

import kivy
kivy.require('2.0.0') # 注意匹配版本號

from kivy.app import App
from kivy.uix.label import Label

class MyApp(App):
    def build(self):
        return Label(text='Hello world')

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

可以直接用python3 kivy_hello_world.py的指令來執行,執行結果如下圖所示:

執行期間我們可以在螢幕上看到一系列的日誌輸出,在有報錯問題的時候,查詢執行日誌是必須使用的定位手段:

[INFO   ] [Logger      ] Record log in /home/dechin/.kivy/logs/kivy_21-04-03_1.txt
[INFO   ] [Kivy        ] v2.0.0
[INFO   ] [Kivy        ] Installed at "/home/dechin/projects/2021-python/kivy/kivy_venv/lib/python3.8/site-packages/kivy/__init__.py"
[INFO   ] [Python      ] v3.8.5 (default, Sep  4 2020, 07:30:14) 
[GCC 7.3.0]
[INFO   ] [Python      ] Interpreter at "/home/dechin/projects/2021-python/kivy/kivy_venv/bin/python3"
[INFO   ] [Factory     ] 186 symbols loaded
[INFO   ] [Image       ] Providers: img_tex, img_dds, img_sdl2 (img_pil, img_ffpyplayer ignored)
[INFO   ] [Text        ] Provider: sdl2
[INFO   ] [Window      ] Provider: sdl2
[INFO   ] [GL          ] Using the "OpenGL" graphics system
[INFO   ] [GL          ] Backend used <sdl2>
[INFO   ] [GL          ] OpenGL version <b'4.6 (Compatibility Profile) Mesa 20.3.1'>
[INFO   ] [GL          ] OpenGL vendor <b'Intel'>
[INFO   ] [GL          ] OpenGL renderer <b'Mesa Intel(R) UHD Graphics 620 (WHL GT2)'>
[INFO   ] [GL          ] OpenGL parsed version: 4, 6
[INFO   ] [GL          ] Shading version <b'4.60'>
[INFO   ] [GL          ] Texture max size <16384>
[INFO   ] [GL          ] Texture max units <32>
[INFO   ] [Window      ] auto add sdl2 input provider
[INFO   ] [Window      ] virtual keyboard not allowed, single mode, not docked
[INFO   ] [ProbeSysfs  ] device match: /dev/input/event16
[INFO   ] [MTD         ] Read event from </dev/input/event16>
[INFO   ] [Base        ] Start application main loop
[INFO   ] [GL          ] NPOT texture support is available
[WARNING] [MTD         ] Unable to open device "/dev/input/event16". Please ensure you have the appropriate permissions.
[INFO   ] [Base        ] Leaving application in progress...

到這裡,我們的第一步工作就基本完成了,但是需要注意的是,這裡我們的程式還是運行在電腦端的,我們需要將其打包成apk文件之後,才能在手機端運行。

選擇使用虛擬環境的原因

這裡我們單獨一個小章節,說明一下為什麼官方推薦的使用方法很多都是使用虛擬環境,這個其實跟後面要介紹的apk打包有較大關係。我們在打包apk的過程中,如果有相關的python依賴包,都需要在配置文件中提前標識。這一點非常重要,最好是能夠指定具體的版本號進行安裝,否則會出現打包失敗的問題,如果到了打包的階段再去定位和解決此類問題,會非常的麻煩。

apk構建環境配置

我們在本地採用了buildozer的方案來進行apk的構建,如果在本地其他環境依賴如jdk等都已經部署完畢,在虛擬環境裡面直接安裝buildozer是沒有問題的。但是由於本地環境中依賴都比較缺乏,因此為了避免環境切換混亂,這裡我們使用虛擬環境來展示安裝和使用的基本方法,但是實際應用場景下,我們還是直接使用了本地的python3環境,而不是虛擬環境

安裝buildozer

跟其他python庫一樣的,我們可以通過pip來對buildozer進行安裝和管理:

(kivy_venv)[dechin@dechin-manjaro kivy]$ python3 -m pip install buildozer -i //mirrors.cloud.tencent.com/pypi/simple
Looking in indexes: //mirrors.cloud.tencent.com/pypi/simple
Collecting buildozer
  Downloading //mirrors.cloud.tencent.com/pypi/packages/ac/62/a53738c604ebc86d3b62f654c3169e8c0b4178a066d7398cf53377a5cb3b/buildozer-1.2.0-py3-none-any.whl (77 kB)
     |████████████████████████████████| 77 kB 783 kB/s 
Collecting sh
  Downloading //mirrors.cloud.tencent.com/pypi/packages/50/38/f7dcc62943d0870f02df9e2fa527b7f0cd86b233a80d6e503a08f3ef5ddc/sh-1.14.1-py2.py3-none-any.whl (40 kB)
     |████████████████████████████████| 40 kB 1.7 MB/s 
Collecting pexpect
  Downloading //mirrors.cloud.tencent.com/pypi/packages/39/7b/88dbb785881c28a102619d46423cb853b46dbccc70d3ac362d99773a78ce/pexpect-4.8.0-py2.py3-none-any.whl (59 kB)
     |████████████████████████████████| 59 kB 1.0 MB/s 
Collecting virtualenv
  Downloading //mirrors.cloud.tencent.com/pypi/packages/91/fb/ca6c071f4231e06a9f0c3bd81c15c233bbacd4a7d9dbb7438d95fece8a1e/virtualenv-20.4.3-py2.py3-none-any.whl (7.2 MB)
     |████████████████████████████████| 7.2 MB 2.2 MB/s 
Collecting ptyprocess>=0.5
  Downloading //mirrors.cloud.tencent.com/pypi/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl (13 kB)
Collecting distlib<1,>=0.3.1
  Downloading //mirrors.cloud.tencent.com/pypi/packages/f5/0a/490fa011d699bb5a5f3a0cf57de82237f52a6db9d40f33c53b2736c9a1f9/distlib-0.3.1-py2.py3-none-any.whl (335 kB)
     |████████████████████████████████| 335 kB 721 kB/s 
Collecting six<2,>=1.9.0
  Downloading //mirrors.cloud.tencent.com/pypi/packages/ee/ff/48bde5c0f013094d729fe4b0316ba2a24774b3ff1c52d924a8a4cb04078a/six-1.15.0-py2.py3-none-any.whl (10 kB)
Collecting appdirs<2,>=1.4.3
  Downloading //mirrors.cloud.tencent.com/pypi/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl (9.6 kB)
Collecting filelock<4,>=3.0.0
  Downloading //mirrors.cloud.tencent.com/pypi/packages/93/83/71a2ee6158bb9f39a90c0dea1637f81d5eef866e188e1971a1b1ab01a35a/filelock-3.0.12-py3-none-any.whl (7.6 kB)
Installing collected packages: six, ptyprocess, filelock, distlib, appdirs, virtualenv, sh, pexpect, buildozer
Successfully installed appdirs-1.4.4 buildozer-1.2.0 distlib-0.3.1 filelock-3.0.12 pexpect-4.8.0 ptyprocess-0.7.0 sh-1.14.1 six-1.15.0 virtualenv-20.4.3

安裝完成後,應該要在本地可以看到buildozer的安裝位置:

(kivy_venv)[dechin@dechin-manjaro kivy]$ which buildozer
/home/dechin/projects/2021-python/kivy/kivy_venv/bin/buildozer

buildozer的基本使用

從框架上來說,buildozer的使用方法其實只有兩個步驟:先用init生成配置文件,然後使用buildozer debug就可以構造一個apk文件了,如果順利的話:)

(kivy_venv) [dechin@dechin-manjaro kivy]$ buildozer init
File buildozer.spec created, ready to customize!

按照流程第一步初始化完成後,當前的目錄下會生成一個buildozer.spec的配置文件,與其他軟體所不一樣的是,這個配置文件又臭又長,修改起來非常的不便,對新手極其不友好。但是,運氣好的情況下也不需要去修改這個配置文件就可以成功構建apk。

(kivy_venv) [dechin@dechin-manjaro kivy]$ ll
總用量 24
-rw-r--r-- 1 dechin dechin 10489  4月  3 22:17 buildozer.spec
-rw-r--r-- 1 dechin dechin   243  4月  3 22:06 kivy_hello_world.py
drwxr-xr-x 4 dechin dechin  4096  4月  3 22:00 kivy_venv

當你執行下面的指令,正常情況下麻煩才剛剛開始:

(kivy_venv) [dechin@dechin-manjaro kivy]$ buildozer android debug deploy run
# Check configuration tokens
# Ensure build layout
# Create directory /home/dechin/.buildozer
# Create directory /home/dechin/.buildozer/cache
# Create directory /home/dechin/projects/2021-python/kivy/.buildozer
# Create directory /home/dechin/projects/2021-python/kivy/bin
# Create directory /home/dechin/projects/2021-python/kivy/.buildozer/applibs
# Create directory /home/dechin/.buildozer/android/platform/android/platform
# Create directory /home/dechin/projects/2021-python/kivy/.buildozer/android/platform
# Create directory /home/dechin/projects/2021-python/kivy/.buildozer/android/app
# Check configuration tokens
# Read available permissions from api-versions.xml
# Preparing build
# Check requirements for android
# Run 'dpkg --version'
# Cwd None
/bin/sh:行1: dpkg:未找到命令
# Search for Git (git)
#  -> found at /usr/bin/git
# Search for Cython (cython)
#  -> found at /home/dechin/anaconda3/bin/cython
# Search for Java compiler (javac)
# Java compiler (javac) not found, please install it.

沒有dpkg,沒有jdk,在參考鏈接5裡面還有人專門整理了各種可能猜到的坑,對這些環境有依賴,為何不能在文檔中提前說明呢?這裡還有一點需要注意的是,雖然buildozer官方提供了docker的解決方案,但是我們極其不推薦使用官方提供的docker解決方案,因為官方的docker方案只解決buildozer的問題,不解決其他的環境依賴問題

構建問題處理

以下整理了一些在使用過程中所遇到的問題,正是為了解決這些問題,所以我們後來放棄了在虛擬環境中繼續測試的方法,改用本地環境直接來運行。這裡有個區別需要注意,buildozer每次初始化會在特定帳號和環境的目錄下產生一個.buildozer的目錄,而普通帳號和root帳號的~/目錄是不一樣的,這點首先要明確。而如果使用虛擬環境,在虛擬環境下也可以產生一個獨立的.buildozer目錄。

dpkg的依賴安裝

我們使用了基於Arch的Manjaro Linux系統,大部分的軟體通過pacman、yay和yaourt都是可以直接下載到的,當然,最好是配置好AUR的源,這裡dpkg我們直接使用pacman來安裝:

[dechin-root kivy]# pacman -S dpkg
正在解析依賴關係...
正在查找軟體包衝突...

軟體包 (1) dpkg-1.20.5-2

下載大小:  1.75 MiB
全部安裝大小:  8.26 MiB

:: 進行安裝嗎? [Y/n] Y
:: 正在獲取軟體包......
 dpkg-1.20.5-2-x86_64      1795.8 KiB   524 KiB/s 00:03 [#############################] 100%
(1/1) 正在檢查密鑰環里的密鑰                            [#############################] 100%
(1/1) 正在檢查軟體包完整性                              [#############################] 100%
(1/1) 正在載入軟體包文件                                [#############################] 100%
(1/1) 正在檢查文件衝突                                  [#############################] 100%
(1/1) 正在檢查可用存儲空間                              [#############################] 100%
:: 正在處理軟體包的變化...
(1/1) 正在安裝 dpkg                                     [#############################] 100%
    dpkg installs Debian package manager.
    This is useful for those who want to create/modify DEB files.
    However, *do not* use dpkg to install Debian packages in your ArchLinux machine.
    This will break your system!
    You will need to go back to Arch wiki and read the installation guide again.
    You've been warned!
:: 正在運行事務後鉤子函數...
(1/1) Arming ConditionNeedsUpdate...

中間如果沒有報錯即為安裝成功。

基於docker的buildozer方案

雖然並不是很推薦這個容器化方案,因為這個容器所能夠解決的問題實在太少,但是這裡我們還是展示一下buildozer官方容器的配置和使用方法。首先是下載官方鏡像:

[dechin-root kivy]# docker pull kivy/buildozer
Using default tag: latest
latest: Pulling from kivy/buildozer
5d3b2c2d21bb: Pull complete 
3fc2062ea667: Pull complete 
75adf526d75b: Pull complete 
1e25f7347ef2: Pull complete 
5f20dec9b37e: Pull complete 
50f409884337: Pull complete 
eee420e57cec: Pull complete 
cf2da2cede0f: Pull complete 
6581da051d43: Pull complete 
e9f936019286: Pull complete 
517947681358: Pull complete 
Digest: sha256:b2923081b45829555cd27356fbc0ab364474c64d9879fa730eccd4ce63e22cc4
Status: Downloaded newer image for kivy/buildozer:latest
docker.io/kivy/buildozer:latest

下載完成後,綁定當前目錄運行容器鏡像:

[dechin-root first_app]# docker run --volume "$(pwd)":/home/user/hostcwd kivy/buildozer
Buildozer 1.2.0.dev0

可以直接查看幫助:

[dechin-root first_app]# docker run -it --volume "$(pwd)":/home/user/hostcwd kivy/buildozer --help
Usage:
    buildozer [--profile <name>] [--verbose] [target] <command>...
    buildozer --version

Available targets:
  ios                iOS target, based on kivy-ios project
  android            Android target, based on python-for-android project

Global commands (without target):
  appclean           Clean the .buildozer folder in the app directory.
  distclean          Clean the whole Buildozer environment.
  help               Show the Buildozer help.
  init               Create a initial buildozer.spec in the current directory
  serve              Serve the bin directory via SimpleHTTPServer
  setdefault         Set the default command to run when no arguments are given
  version            Show the Buildozer version

Target commands:
  clean      Clean the target environment
  update     Update the target dependencies
  debug      Build the application in debug mode
  release    Build the application in release mode
  deploy     Deploy the application on the device
  run        Run the application on the device
  serve      Serve the bin directory via SimpleHTTPServer

Target "ios" commands:
  list_identities    List the available identities to use for signing.
  xcode              Open the xcode project.

Target "android" commands:
  adb                Run adb from the Android SDK. Args must come after --, or
                     use --alias to make an alias
  clean              Clean the build and distribution
  logcat             Show the log from the device
  p4a                Run p4a commands. Args must come after --, or use --alias
                     to make an alias

第一次初始化,出現了許可權不足的問題,一開始以為是容器內部讀寫許可權配置的問題,因此這裡先給容器加上了privileged許可權,但是執行後發現這個問題依然存在:

[dechin-root first_app]# docker run -it --volume "$(pwd)":/home/user/hostcwd --privileged=True kivy/buildozer init
Traceback (most recent call last):
  File "/home/user/.local/bin/buildozer", line 8, in <module>
    sys.exit(main())
  File "/home/user/.local/lib/python3.8/site-packages/buildozer/scripts/client.py", line 13, in main
    Buildozer().run_command(sys.argv[1:])
  File "/home/user/.local/lib/python3.8/site-packages/buildozer/__init__.py", line 1010, in run_command
    getattr(self, cmd)(*args)
  File "/home/user/.local/lib/python3.8/site-packages/buildozer/__init__.py", line 1049, in cmd_init
    copyfile(join(dirname(__file__), 'default.spec'), 'buildozer.spec')
  File "/usr/lib/python3.8/shutil.py", line 261, in copyfile
    with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
PermissionError: [Errno 13] Permission denied: 'buildozer.spec'

那就有可能是本地配置文件和目錄許可權的問題,因為目錄是在普通帳號下產生的,一般是644的許可權,那麼就算是root許可權的寫入可能也會首先,乾脆直接遞歸的改成777

[dechin-root kivy]# chmod -R 777 first_app/

再次運行,發現在本地一樣也可以生成配置文件:

[dechin-root first_app]# docker run -it --volume "$(pwd)":/home/user/hostcwd --privileged=True kivy/buildozer init && ll
File buildozer.spec created, ready to customize!
總用量 24
-rw-r--r-- 1 dechin dechin 12305  4月  4 10:59 buildozer.spec
-rwxrwxrwx 1 root   root     243  4月  4 10:42 main.py
drwxrwxrwx 3 root   root    4096  4月  4 10:43 user

但是這個容器鏡像跟常規的有所不同,整個的容器鏡像就只能執行buildozer的指令,這尤其對中國用戶非常的不友好,因為我們缺乏的就是buildozer那一堆依賴環境,在中國網路上會受到一定的限制。比如我們下述展示的運行結果,就卡在這個地方很久:

[dechin-root first_app]# docker run -it --volume "$(pwd)":/home/user/hostcwd --privileged=True kivy/buildozer android debug deploy run
# Check configuration tokens
# Ensure build layout
# Create directory /home/user/.buildozer
# Create directory /home/user/.buildozer/cache
# Create directory /home/user/hostcwd/.buildozer
# Create directory /home/user/hostcwd/bin
# Create directory /home/user/hostcwd/.buildozer/applibs
# Create directory /home/user/.buildozer/android/platform/android/platform
# Create directory /home/user/hostcwd/.buildozer/android/platform
# Create directory /home/user/hostcwd/.buildozer/android/app
# Check configuration tokens
# Read available permissions from api-versions.xml
# Preparing build
# Check requirements for android
# Run 'dpkg --version'
# Cwd None
Debian 'dpkg' package management program version 1.19.7 (amd64).
This is free software; see the GNU General Public License version 2 or
later for copying conditions. There is NO warranty.
# Search for Git (git)
#  -> found at /usr/bin/git
# Search for Cython (cython)
#  -> found at /home/user/.local/bin/cython
# Search for Java compiler (javac)
#  -> found at /usr/lib/jvm/java-13-openjdk-amd64/bin/javac
# Search for Java keytool (keytool)
#  -> found at /usr/lib/jvm/java-13-openjdk-amd64/bin/keytool
# Install platform
# Run 'git clone -b master --single-branch //github.com/kivy/python-for-android.git python-for-android'
# Cwd /home/user/hostcwd/.buildozer/android/platform
Cloning into 'python-for-android'...

網路卡了很長一段時間後會彈出眾多的報錯:

Cloning into 'python-for-android'...
fatal: unable to access '//github.com/kivy/python-for-android.git/': GnuTLS recv error (-54): Error in the pull function.
# Command failed: git clone -b master --single-branch //github.com/kivy/python-for-android.git python-for-android
# ENVIRONMENT:
#     PATH = '/home/user/.buildozer/android/platform/apache-ant-1.9.4/bin:/home/user/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
#     HOSTNAME = '69325b48f53a'
#     TERM = 'xterm'
#     USER = 'user'
#     HOME_DIR = '/home/user'
#     WORK_DIR = '/home/user/hostcwd'
#     SRC_DIR = '/home/user/src'
#     LANG = 'en_US.UTF-8'
#     LANGUAGE = 'en_US.UTF-8'
#     LC_ALL = 'en_US.UTF-8'
#     HOME = '/home/user'
# 
# Buildozer failed to execute the last command
# The error might be hidden in the log above this error
# Please read the full log, and search for it before
# raising an issue with buildozer itself.
# In case of a bug report, please add a full log with log_level = 2

實際上這就是網路的問題,如果你能上Google,那麼你就同時解決了這個問題。如果網路不行的話,即使在官方商店裡面可以看到也是下載安裝不了的:

adb日誌定位apk問題

假定你已經解決了上述提到了訪問Google網站的問題,那麼環境依賴的問題基本上就已經解決了,只需要注意jdk跟gradle的版本配套關係即可,這裡我們本地使用的是jdk-8,同樣的也可以使用yaourt來進行安裝。最後就還有可能出現,部署到Android設備上面之後,app閃退的問題。首先我們如果執行buildozer androiid debug deploy run,並且同時保障Android手機USB接入以及USB調試開關的打開,順利情況下會出現以下資訊:

List of devices attached
xxx        device

# Deploy on xxx
# Run '/home/dechin/.buildozer/android/platform/android-sdk/platform-tools/adb install -r "/home/dechin/projects/2021-python/kivy/first_app/bin/myapp-0.1-armeabi-v7a-debug.apk"'
# Cwd /home/dechin/.buildozer/android/platform
Performing Streamed Install
Success
# Application pushed.
# Run on xxx
# Run '/home/dechin/.buildozer/android/platform/android-sdk/platform-tools/adb shell am start -n org.test.myapp/org.kivy.android.PythonActivity -a org.kivy.android.PythonActivity'
# Cwd /home/dechin/.buildozer/android/platform
Starting: Intent { act=org.kivy.android.PythonActivity cmp=org.test.myapp/org.kivy.android.PythonActivity }
# Application started.

但這並不是終點,我們發現在手機上用apk安裝的app會出現閃退,這一般都是由於程式報錯而導致的,我們可以在連接USB調試的狀態下,進入adb shell查看日誌:

[dechin@dechin-manjaro first_app]$ adb shell
HWPCT:/ $ run-as org.test.myapp
HWPCT:/data/data/org.test.myapp 
$ cd files/app/.kivy/logs/                                  
HWPCT:/data/data/org.test.myapp/files/app/.kivy/logs 
$ ls
kivy_21-04-06_0.txt
$ cat kivy_21-04-06_0.txt                                                                     <
[INFO   ] Logger: Record log in /data/user/0/org.test.myapp/files/app/.kivy/logs/kivy_21-04-06_0.txt
[WARNING] [Config      ] Upgrading configuration in progress.
[WARNING] [Config      ] Older configuration version detected (0 instead of 21)
[INFO   ] Kivy: v1.11.1
[INFO   ] Kivy: Installed at "/data/user/0/org.test.myapp/files/app/_python_bundle/site-packages/kivy/__init__.pyc"
[INFO   ] Python: v3.8.1 (default, Apr  6 2021, 10:41:43) 
[Clang 8.0.2 (//android.googlesource.com/toolchain/clang 40173bab62ec7462
[INFO   ] Python: Interpreter at ""
[WARNING] stderr: Traceback (most recent call last):
[WARNING] stderr:   File "/home/dechin/projects/2021-python/kivy/first_app/.buildozer/android/app/main.py", line 4, in <module>
[WARNING] stderr:   File "/home/dechin/projects/2021-python/kivy/first_app/.buildozer/android/platform/build-armeabi-v7a/build/python-installs/myapp/kivy/__init__.py", line 138, in require
[WARNING] stderr: Exception: The version of Kivy installed on this system is too old. (You have 1.11.1, but the application requires 2.0.0)
HWPCT:/data/data/org.test.myapp/files/app/.kivy/log

從日誌中我們看到,這是因為對應的kivy程式版本過低導致的,這需要我們修改buildozer.spec配置文件。我們找到requirements這裡,發現這裡的兩個倉庫都沒有指定版本號,這裡我們採取的方案是加上版本號的要求,然後清除.buildozer目錄,重新進行環境安裝。

requirements = python3,kivy

修改後如下:

requirements = python3,kivy==2.0.0

然後在重新執行buildozer debug deploy run,得到手機介面上的效果如下(如果只運行debug或者release,那就不需要連接手機USB調試,這裡的操作相當於直接把apk傳輸到手機上進行安裝和運行):

實在是感動哭了~~~

順便複習vim基本操作

首先是顯示行號,剛打開的介面如下:

使用:set nu顯示行號:

使用/或者?向前與前後查找字元串,這裡查找的是kivy

找到之後回車,游標移動到當前目標的最前端:

Shift+N查找下一個目標:

kivy的字元串計算器案例

讓我們假定環境的問題都已經解決了,只剩下編寫kivy程式的時候,可以讓我們來測試一些簡單的案例:根據字元串輸出字元串計算的結果,就像是在python的命令行裡面測試一般。當然,這需要我們先做一些準備工作。

kivy按鈕實例

首先我們測試一個按鈕的實例,先學習下kivy中按鈕的使用方法:

# main7.py

from kivy.app import App
from kivy.uix.togglebutton import ToggleButton

class ToggleButtonApp(App):
    def build(self):
        #text按鈕標籤
        #color標籤文本顏色
        #background_color按鍵顏色
        #font_size標籤字體大小
        TogBu=ToggleButton(text="Red",color=(0,1,0,1),background_color=(0.5,0,0.5,1),font_size=200)
        return TogBu

if __name__=="__main__":
    ToggleButtonApp().run()

執行結果的介面如下:

點擊按鈕:

再次點擊按鈕則返回上一個介面。

kivy文本框示例

由於需要輸入文本框,所以我們也得測試一下文本框的基本使用方法:

# main8.py

from kivy.app import App
from kivy.uix.textinput import TextInput

class TextInputApp(App):
    def build(self):
        text=TextInput(font_size=150)#font_size輸入文本框大小
        return text

if __name__=="__main__":
    TextInputApp().run()

運行結果如下:我們可以在介面上輸入文本:

但是需要注意的是,我們在電腦端所看到的字體大小和手機端所看到的字體大小是不一致的,要根據實際情況來進行調整。

核心:打包math倉庫到app中

數學運算倉庫math是python中非常常用的一個庫,這裡我們計劃將其打包到一個Android的app中,這樣一來我們就可以在移動端調用python庫來計算一些簡單任務。那麼我們的邏輯是這樣的:先把所有的math函數導入,然後給定兩個文本框,一個作為輸入窗口一個作為輸出窗口,再加上一個運行的按鈕,那就齊活兒了。具體的成品程式碼如下:

# main.py

from kivy.app import App
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from math import *

def message(self):
    pop = Popup(text=self.text)

class TextInputApp(App):
    def build(self):
        layout = BoxLayout(orientation='vertical', spacing=15, padding=10)
        self.text=TextInput(font_size=150) # font_size輸入文本框大小
        self.out_text=TextInput(font_size=150)
        button = Button(text="Run", size_hint=(1.0, 0.5), 
                        pos_hint={"center_x":0.5, "center_y":0.5})
        button.bind(on_press=self.press)
        layout.add_widget(self.text)
        layout.add_widget(self.out_text)
        layout.add_widget(button)
        return layout
    def press(self, instance):
        # pop = Popup(text=self.text.text)
        try: # 捕獲異常,避免程式中斷
            print (eval(self.text.text)) # eval內置函數,執行字元串指令
            self.out_text.text=str(eval(self.text.text))
        except:
            self.out_text.text="wrong input" # 如果是不合法資訊,輸出錯誤
            pass

if __name__=="__main__":
    TextInputApp().run()

以下展示一些基本的運行結果:





該apk文件也已經傳到百度網盤上面以供分享,感興趣的朋友可以下載使用:
鏈接: //pan.baidu.com/s/1M0mKFFuJw3Z-giA04mmTTg 提取碼:4a3q

總結概要

基於python也可以開發AndroidAPP,這需要使用到kivy庫來進行開發,再通過buildozer來編譯構建。這兩個庫的安裝和使用方式都相對比較簡單,我們推薦直接在本地的系統環境下直接部署使用,最大的困難其實在於部署的過程以及配置文件的修改,這也都是比較基礎的操作了。最後我們演示了使用文本框和按鈕事件,加上python的eval()函數和math數學倉庫,實現了一個可以在移動端調用math庫中的函數執行數學計算的簡單APP,並提供了apk下載網盤地址。

版權聲明

本文首發鏈接為://www.cnblogs.com/dechinphy/p/kivy.html
作者ID:DechinPhy
更多原著文章請參考://www.cnblogs.com/dechinphy/

參考鏈接

  1. //blog.csdn.net/hpwzjz/article/details/89703313
  2. //kivy.org/doc/stable/gettingstarted/examples.html
  3. //github.com/kivy/buildozer
  4. //zhuanlan.zhihu.com/p/83335242
  5. //zhuanlan.zhihu.com/p/33990951
  6. //www.srcmini.com/68022.html
  7. //blog.csdn.net/python__reported/article/details/108007036#t3
  8. //blog.csdn.net/weixin_42269667/article/details/106517353
  9. //blog.csdn.net/qq_37030400/article/details/107645903