python3使用kivy生成安卓程序

技术背景

虽然现在苹果占据了很大一部分的市场,但是从销量数据来看,安卓还是占据了人口的高地。这里我们介绍一个用python的kivy+buildozer来进行安卓APP开发的简单教程,从整个过程中来看,环境部署这一块所需的工作量是非常大的,可能这就是从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 https://mirrors.cloud.tencent.com/pypi/simple 
Looking in indexes: https://mirrors.cloud.tencent.com/pypi/simple
Collecting kivy
  Downloading https://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 https://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 https://mirrors.cloud.tencent.com/pypi/packages/7d/68/decaee596ff8168a39432eb3949fc7c0be952ebb9467806823bffc165d48/kivy-garden-0.1.4.tar.gz (6.8 kB)
Collecting docutils
  Downloading https://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 https://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 https://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 https://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 https://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 https://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 https://mirrors.cloud.tencent.com/pypi/simple
Looking in indexes: https://mirrors.cloud.tencent.com/pypi/simple
Collecting buildozer
  Downloading https://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 https://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 https://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 https://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 https://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 https://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 https://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 https://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 https://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 https://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 'https://github.com/kivy/python-for-android.git/': GnuTLS recv error (-54): Error in the pull function.
# Command failed: git clone -b master --single-branch https://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

实际上这就是网络的问题,如果你能上谷歌,那么你就同时解决了这个问题。如果网络不行的话,即使在官方商店里面可以看到也是下载安装不了的:

adb日志定位apk问题

假定你已经解决了上述提到了访问谷歌网站的问题,那么环境依赖的问题基本上就已经解决了,只需要注意jdk跟gradle的版本配套关系即可,这里我们本地使用的是jdk-8,同样的也可以使用yaourt来进行安装。最后就还有可能出现,部署到安卓设备上面之后,app闪退的问题。首先我们如果执行buildozer androiid debug deploy run,并且同时保障安卓手机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 (https://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中非常常用的一个库,这里我们计划将其打包到一个安卓的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文件也已经传到百度网盘上面以供分享,感兴趣的朋友可以下载使用:
链接: https://pan.baidu.com/s/1M0mKFFuJw3Z-giA04mmTTg 提取码:4a3q

总结概要

基于python也可以开发安卓APP,这需要使用到kivy库来进行开发,再通过buildozer来编译构建。这两个库的安装和使用方式都相对比较简单,我们推荐直接在本地的系统环境下直接部署使用,最大的困难其实在于部署的过程以及配置文件的修改,这也都是比较基础的操作了。最后我们演示了使用文本框和按钮事件,加上python的eval()函数和math数学仓库,实现了一个可以在移动端调用math库中的函数执行数学计算的简单APP,并提供了apk下载网盘地址。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/kivy.html
作者ID:DechinPhy
更多原著文章请参考:https://www.cnblogs.com/dechinphy/

参考链接

  1. https://blog.csdn.net/hpwzjz/article/details/89703313
  2. https://kivy.org/doc/stable/gettingstarted/examples.html
  3. https://github.com/kivy/buildozer
  4. https://zhuanlan.zhihu.com/p/83335242
  5. https://zhuanlan.zhihu.com/p/33990951
  6. http://www.srcmini.com/68022.html
  7. https://blog.csdn.net/python__reported/article/details/108007036#t3
  8. https://blog.csdn.net/weixin_42269667/article/details/106517353
  9. https://blog.csdn.net/qq_37030400/article/details/107645903
posted @ 2021-04-07 15:44  DECHIN  阅读(10764)  评论(0编辑  收藏  举报