大型真人秀节目:buildozer 折腾记

先贴3个库的链接 : kivy, buildozer, p4a(python-for-android) 

buildozer 是 kivy 开发小组基于自家的 python-for-android 开发的傻瓜式 android 编译工具,用于将 python 项目编译成为 .apk 文件。

本文记录了整个折腾过程(不完全整理,非线性时间顺序),建议读完再操作,因为前面可能是我踩过的坑 ....  (时间是 2019年6月22日21:31:38 )

配置

     OS : UBUNTU 18.04 LTS (官方 buildozer 虚拟机 XUBUNTU 由于无法换到可以用的源,被替换了)

     python : python3

     buildozer : 0.39 ( 通过 812 ISSUE 升级到了 0.40.dev0)

     python-for-android: master

     kivy: 1.11.0

先按照官方步骤完成 buildozer 虚拟机的安装,buildozer 虚拟机安装的是 xubuntu 系统。

首先建议将 buildozer 使用开发分支重新安装,可以解决一个 'Buildozer' object has no attribute 'translate_target' 的问题。

pip install --upgrade https://github.com/kivy/buildozer/archive/4c2152b.zip

在 xubuntu 系统中切换至 项目目录,执行

buildozer init

一个名为 buildozer.spec 的文本文件会被自动生成,里面的内容将指导整个编译过程

大型真人秀节目:buildozer 折腾记_第1张图片

我这里的 main.py 内容很简单,只有一个按钮

from kivy.app import App
from kivy.uix.button import Button


class SimpleApp(App):

    def build(self):
        return Button(text='joke')

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

那么将问题简化为编译一个带有 kivy 的程序为 .apk 文件,不包含其他任何依赖

bin 和 build_area 目录分别是编译结果输出目录和编译中间目录,在 buildozer.spec 文件中分别指定到 bin_dir 和 build_dir

按照 README 中所说,从 https://www.crystax.net/en/download 下载了 ndk 并解压,对 buildozer.spec 做如下修改

# (str) Title of your application
title = SimpleAppTitle

# (str) Package name
package.name = SimpleApp

# (str) Package domain (needed for android/ios packaging)
package.domain = dav.test

...

# Require python3crystax:
requirements = python3crystax,kivy

# Point to the directory where you extracted the crystax-ndk:
android.ndk_path = /home/kivy/Desktop/Projects/android/android-ndk-r17c/

另外,你一定有需求的就是打开调试日志

# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
log_level = 2

于是就可以按照示例进行编译了,按如下即可,后面俩(deploy run)是部署和运行,需要连接 android 设备

buildozer android debug

那么发现下载过程非常慢,于是就去 p4a(python-for-android) 克隆库下来,指定到目录,同时指定为 master(master 会包含 python3 编译所遇到的一些已知问题的处理)

# (str) python-for-android git clone directory (if empty, it will be automatically cloned from github)
p4a.source_dir = /home/kivy/Desktop/Projects/python-for-android

# (str) python-for-android branch to use, defaults to master
p4a.branch = master

其他的包怎么办呢????我能有的思路就是自己通过比较快速的方法下载好包,替换到 buildozer 执行过程的目录中。那么问题就变成该怎么完成替换了(下载我已经解决好了 ^_^)

那么首先我们看日志

大型真人秀节目:buildozer 折腾记_第2张图片

这里有下载三个包:hostpython3,libffi,openssl,我们以 hostpython3 为例,红色方框标识出下载地址,

我们先想办法下下来(wget,迅雷,用VPS下,之类的,自己想办法咯 ....)

然后我们观察日志,看到一个 directory context,干啥的呢?通过终端切过去看了下已经跑过的部分,发现就是保存目标文件的位置。于是将下载好后复制到下面目录中

于是重新跑起来

buildozer android debug

结果不对,编译过程始终会跑到

同时也会把刚刚复制过去的包给删除后重新下载, WTF ??? 怎么办 ???只好去找找代码,看能不能发现些什么。于是先去 buildozer 代码中搜索了一把,没有对应日志的输出,于是只有开启思考人生模式

...

可能过去了10分钟

...

buildozer 只是简化了p4a 的操作过程,具体干活儿的其实是 p4a, 那么我又去 p4a 的代码里搜索了一把日志,发现了一些东西

大型真人秀节目:buildozer 折腾记_第3张图片

从代码中明确的看到,.mark文件就是个空文件,那我们也照猫画虎,创建一个名为 【.mark-<文件名>】 的空文件(用 touch),然后再把自行下载好的文件复制过来,就完成了该文件的替换

事实上,完全可以将 packages 文件夹(如下)备份下来,在清理后拷贝回来重新进行编译。

.buildozer/android/platform/build/packages/

高高兴兴的再次开启编译流程

buildozer android debug

我以为只要下载了 android-sdk 就够了,然而事情并没有那么简单,我发现还缺组件,由于自动下载过程中报了错,我误以为是 p4a 的问题,于是再次开启DIY下载模式。在查找 android-sdk 下载方法过程中,发现原来的 android 命令并不推荐使用了,所以使用了推荐 sdkmanager ,切换到 android-sdk/tools/bin 目录下,使用以下命令安装组件

./sdkmanager "platform-tools" "platforms;android-27"
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
	at com.android.repository.api.SchemaModule$SchemaModuleVersion.(SchemaModule.java:156)
	at com.android.repository.api.SchemaModule.(SchemaModule.java:75)
	at com.android.sdklib.repository.AndroidSdkHandler.(AndroidSdkHandler.java:81)
	at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:73)
	at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:48)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
	... 5 more

所以是为什么呢???先看了下那么多的  java 日志,就看了下我安装的 java,发现是11的版本

dav@ubuntu:~/Desktop/Projects/android/android-sdk/tools/bin$ java --version
openjdk 11.0.3 2019-04-16
OpenJDK Runtime Environment (build 11.0.3+7-Ubuntu-1ubuntu218.04.1)
OpenJDK 64-Bit Server VM (build 11.0.3+7-Ubuntu-1ubuntu218.04.1, mixed mode)

于是根据错误日志找到一个相关问题 Failed to install android-sdk: “java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema” ,文中提到将 java 版本回退到8就好了,那我重新安装好8以后确认下

dav@ubuntu:~/Desktop/Projects/android/android-sdk/tools/bin$ java --version
Unrecognized option: --version
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

咦???于是通过 apt 直接查看安装情况【后面发现尴尬的是 java -version 可以执行,version前面一个杠】


dav@ubuntu:~/Desktop/Projects/android/android-sdk/tools/bin$ apt list --installed *jdk*
Listing... Done
openjdk-8-dbg/bionic-updates,bionic-security,now 8u212-b03-0ubuntu1.18.04.1 amd64 [installed]
openjdk-8-demo/bionic-updates,bionic-security,now 8u212-b03-0ubuntu1.18.04.1 amd64 [installed]
openjdk-8-doc/bionic-updates,bionic-updates,bionic-security,bionic-security,now 8u212-b03-0ubuntu1.18.04.1 all [installed]
openjdk-8-jdk/bionic-updates,bionic-security,now 8u212-b03-0ubuntu1.18.04.1 amd64 [installed]
openjdk-8-jdk-headless/bionic-updates,bionic-security,now 8u212-b03-0ubuntu1.18.04.1 amd64 [installed]
openjdk-8-jre/bionic-updates,bionic-security,now 8u212-b03-0ubuntu1.18.04.1 amd64 [installed]
openjdk-8-jre-dcevm/bionic,now 8u112-2 amd64 [installed]
openjdk-8-jre-headless/bionic-updates,bionic-security,now 8u212-b03-0ubuntu1.18.04.1 amd64 [installed]
openjdk-8-jre-zero/bionic-updates,bionic-security,now 8u212-b03-0ubuntu1.18.04.1 amd64 [installed]
openjdk-8-source/bionic-updates,bionic-updates,bionic-security,bionic-security,now 8u212-b03-0ubuntu1.18.04.1 all [installed]

这次懒得自己去下载了,干脆直接继续吧

buildozer android debug

从日志和 android-sdk 目录可以看到 android-sdk 的 build-tools,platforms,platform-tools,licenses,以及 tools 被相应的安装和升级,然而好景不长,这时候遇到了一个惊天错误

[ERROR]: The python3crystax recipe can only be built when using the CrystaX NDK. Exiting.

我 ......... 细心的读者肯定记得,前面官网 MASTER 分支上的 README 分明让我们去下载了 crystaX NDK, 并且在 buildozer.spec 文件中指定了 android.ndk_path,同时还将默认的

requirements = python3,kivy    ==> 修改为 ==> requirements = python3crystax,kivy

于是我们再一次来到了 buildozer 的 ISSUE界面, 发现了这么一个问题 The python3crystax recipe can only be built when using the CrystaX NDK. Exiting. 

那么 kivy 的老板们亲切的提示了 

大型真人秀节目:buildozer 折腾记_第4张图片

时间是 2019.2.2 ,那么我们用的 master 应该就是符合他的描述了,再次回到 README.md,却发现了 deprecated 字样。

大型真人秀节目:buildozer 折腾记_第5张图片

于是我们将 buildozer.spec 中的 requirements 修改回来,同时注释掉 ndk_path,  buildozer 会自动下载 android-ndk (非 crystaX 版本)

# Require python3crystax:
requirements = python3,kivy

# (str) Android NDK directory (if empty, it will be automatically downloaded.)
# android.ndk_path = /home/kivy/Desktop/Projects/android/android-ndk/

再次开启编译过程

buildozer android debug

结果遇到了下面的问题

[INFO]:    -> running patch -t -d /home/dav/Desktop/...(and 245 more)
Exception in thread background thread for pid 37261:                           
Traceback (most recent call last):
  File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.7/threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
  File "/home/dav/.local/share/virtualenvs/build_area-AnJkn9zu/lib/python3.7/site-packages/sh.py", line 1540, in wrap
    fn(*args, **kwargs)
  File "/home/dav/.local/share/virtualenvs/build_area-AnJkn9zu/lib/python3.7/site-packages/sh.py", line 2459, in background_thread
    handle_exit_code(exit_code)
  File "/home/dav/.local/share/virtualenvs/build_area-AnJkn9zu/lib/python3.7/site-packages/sh.py", line 2157, in fn
    return self.command.handle_command_exit_code(exit_code)
  File "/home/dav/.local/share/virtualenvs/build_area-AnJkn9zu/lib/python3.7/site-packages/sh.py", line 815, in handle_command_exit_code
    raise exc
sh.ErrorReturnCode_1: 

  RAN: /usr/bin/patch -t -d /home/dav/Desktop/workspace/build_area/buildozer_projects/test/.buildozer/android/platform/build/build/bootstrap_builds/sdl2-python3/jni/SDL2_image -p1 -i /home/dav/Desktop/workspace/python-for-android/pythonforandroid/recipes/sdl2_image/toggle_jpg_png_webp.patch

  STDOUT:
can't find file to patch at input line 3
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|--- SDL2_image-2.0.4/Android.mk.orig	2018-10-31 15:58:52.000000000 +0100
|+++ SDL2_image-2.0.4/Android.mk	2019-02-07 23:51:51.740299680 +0100
--------------------------
No file to patch.  Skipping patch.
1 out of 1 hunk ignored


  STDERR:

看样子最后执行的命令是 patch 命令,于是去研究了一下 patch 究竟是干什么的,做了下面的简单的实验

dav@ubuntu:~/Desktop/workspace/test$ cat a
test
just
finer
dav@ubuntu:~/Desktop/workspace/test$ cat b 
tester
just
fine
dav@ubuntu:~/Desktop/workspace/test$ cat c
test
just
finer
dav@ubuntu:~/Desktop/workspace/test$ diff a b > d
dav@ubuntu:~/Desktop/workspace/test$ cat d
1c1
< test
---
> tester
3c3
< finer
---
> fine

dav@ubuntu:~/Desktop/workspace/test$ patch c d
patching file c
dav@ubuntu:~/Desktop/workspace/test$ cat c
tester
just
fine

那么很明确了,应该就是将补丁文件中的更新同步到本地文件的,那么我搜遍了我可以找到的地方,只有一个 ISSUE 最为接近:Problems in patching files during building for android_new,然而作者已经明确表明是因为自己的错误修改造成的,那么我只好去 buildozer 的界面提交了一个新的 ISSUE,问题待解决 ....

 

【2019/06/25】

THX to AndreMiras,

大型真人秀节目:buildozer 折腾记_第6张图片

根据他提供的建议,我们工作目录中 .buildozer 文件夹下的所有文件删除,重新开始编译

rm .buildozer/* -vrf
buildozer --verbose android debug

终于跑过了 patch 的问题。回过头来看,根据描述,应该是因为下载过程中异常中断导致压缩包数据不全,解压后文件丢失,重新下载后解决问题。

继续,我们又遇到了“新朋友”

[INFO]:    Building pyjnius for armeabi-v7a
[INFO]:    jnius apparently isn't already in site-packages
[INFO]:    Cythonizing anything necessary in pyjnius
[INFO]:    -> directory context /home/dav/Desktop/workspace/build_area/buildozer_projects/test/.buildozer/android/platform/build/build/other_builds/pyjnius-python3-sdl2/armeabi-v7a__ndk_target_21/pyjnius
[INFO]:    -> running python -c import sys; print(sys.path)
[INFO]:    Trying first build of pyjnius to get cython files: this is expected to fail
[INFO]:    -> running python setup.py build_ext -v

...

  RAN: /home/dav/Desktop/workspace/build_area/buildozer_projects/test/.buildozer/android/platform/build/build/other_builds/hostpython3/desktop/hostpython3/native-build/python setup.py build_ext -v

  STDOUT:
/home/dav/Desktop/workspace/build_area/buildozer_projects/test/.buildozer/android/platform/build/build/other_builds/hostpython3/desktop/hostpython3/Lib/distutils/dist.py:274: UserWarning: Unknown distribution option: 'install_requires'
  warnings.warn(msg)
running build_ext
building 'jnius' extension
creating build
creating build/temp.linux-x86_64-3.7
creating build/temp.linux-x86_64-3.7/jnius
arm-linux-androideabi-gcc -DANDROID -fomit-frame-pointer -D__ANDROID_API__=21 -mandroid -isystem /home/dav/Desktop/workspace/android/android-ndk-r17c/sysroot/usr/include/arm-linux-androideabi -I/home/dav/Desktop/workspace/android/android-ndk-r17c/sysroot/usr/include/arm-linux-androideabi -isysroot /home/dav/Desktop/workspace/android/android-ndk-r17c/sysroot -I/home/dav/Desktop/workspace/build_area/buildozer_projects/test/.buildozer/android/platform/build/build/python-installs/SimpleApp/include/python3.7 -DNDEBUG -g -fwrapv -O3 -Wall -DANDROID -fomit-frame-pointer -D__ANDROID_API__=21 -mandroid -isystem /home/dav/Desktop/workspace/android/android-ndk-r17c/sysroot/usr/include/arm-linux-androideabi -I/home/dav/Desktop/workspace/android/android-ndk-r17c/sysroot/usr/include/arm-linux-androideabi -isysroot /home/dav/Desktop/workspace/android/android-ndk-r17c/sysroot -I/home/dav/Desktop/workspace/build_area/buildozer_projects/test/.buildozer/android/platform/build/build/python-installs/SimpleApp/include/python3.7 -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -mthumb -I/home/dav/Desktop/workspace/build_area/buildozer_projects/test/.buildozer/android/platform/build/build/other_builds/python3-libffi-openssl-sqlite3/armeabi-v7a__ndk_target_21/python3/Include -fPIC -I/home/dav/Desktop/workspace/build_area/buildozer_projects/test/.buildozer/android/platform/build/build/other_builds/hostpython3/desktop/hostpython3/Include -I/home/dav/Desktop/workspace/build_area/buildozer_projects/test/.buildozer/android/platform/build/build/other_builds/hostpython3/desktop/hostpython3/native-build -c jnius/jnius.c -o build/temp.linux-x86_64-3.7/jnius/jnius.o
arm-linux-androideabi-gcc: error: jnius/jnius.c: No such file or directory
arm-linux-androideabi-gcc: fatal error: no input files
compilation terminated.
error: command 'arm-linux-androideabi-gcc' failed with exit status 1


  STDERR:

最核心的错误描述在于

arm-linux-androideabi-gcc: error: jnius/jnius.c: No such file or directory

那么顺着这个问题找下去,发现一个相关的 ISSUE :jnius/jnius.c: No such file or directory

大型真人秀节目:buildozer 折腾记_第7张图片

按照 deusyss 的提示 在系统中安装 cython 安装

sudo apt install cython -y

然后再在 python 内安装

pip install cython

再次开启编译

buildozer --verbose android debug

然后就看到了一条非常养眼的文字

大型真人秀节目:buildozer 折腾记_第8张图片

于是,故事结束的好突然,so sad ....

 

【2019/07/26】

那么我们回头再看一下需要做的东西,其实就只剩下

1. 安装一个适当版本的 buildozer   =>  0.40.dev0

2. 初始化

buildozer init

3. 修改编译基本参数

# (str) Title of your application
title = SimpleAppTitle

# (str) Package name
package.name = SimpleApp

# (str) Package domain (needed for android/ios packaging)
package.domain = dav.test

...

# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
log_level = 2

4. 解决一些依赖包/库问题 (大部分的都已经通过 buildozer 解决了), 如 openJDK

面临最大的挑战就是网络问题,目前我实践下来最好的结果就是直接在外面的 VPS 上面编译,网络会稳定不少

 

你可能感兴趣的:(Android,Python,kivy,Linux,kivy,android,buildozer,编译)