目录

一、APP代码书写

(一)单独在py中构建

(二)结合kv构建

二、Kivy打包

(一)、大致概述

(二)、Kivy打包Android的方式

(三)、开始打包

(四)、buildozer.spec详解

三、结语


之前简要介绍了Python的移动app开发框架Kivy的核心成员及主要原理和应用。从本篇开始会不定期发布Kivy开发代码和原理讲解。

依照开发界的惯例,先来个简单的Hello world起个好头。

一、APP代码书写

首先创建一个main.py文件,至于为什么命名为main是因为打包的时候Kivy框架会以main.py文件为核心进行打包而不是其他命名的文件。

(一)单独在py中构建

如果想直接在py文件中完成全部代码构成可以按照如下方式写代码:

from kivy.app import App# 引入App库,App库是Kivy开发的核心,必须引入from kivy.uix.button import Button# 引入Button(按钮)控件from kivy.uix.boxlayout import BoxLayout# 引入布局class IndexPage(BoxLayout):# 自定义根布局名称,并继承对应类型的布局def __init__(self, **kwargs):super().__init__(**kwargs)button = Button(text="Hello world")# 实例化Button控件,并修改text属性self.add_widget(button)# 通过add_widget函数将Button控件引入布局中class TestApp(App):# 单独构建App导入框架def build(self):return IndexPage()# 返回布局,相当于在软件中绘制布局及其中内容TestApp().run()# 运行软件

(二)结合kv构建

当然我们也可以把根布局下的所有控件写在单独的.kv文件中,首先还是创建一个main.py文件。

这次与之前有所不同了,我们只需要在py文件中声明清楚根布局就可以了,其余的都可以在kv文件内完成。在py中的代码如下:

from kivy.app import Appfrom kivy.uix.button import Buttonfrom kivy.uix.boxlayout import BoxLayoutclass IndexPage(BoxLayout):def __init__(self, **kwargs):super().__init__(**kwargs)class TestApp(App):def build(self):return IndexPage()TestApp().run()

接下来创建一个kv文件,注意kv文件的命名要与引入App的类本身的名称当中,App之前的字段相对应,但Kivy会自动小写化App之前的字段,如:以上代码中引入App库的类名称为TestApp,那么在命名kv文件的时候就要命名为test.kv。固我们需要创建一个test.kv文件,并在其中编写如下代码(注:Kivy本身具备kv语言,与Python有所不同但同样语法简单易懂):

:Button:text: 'Hello world'

注意:kv文件中要先确定父布局再在其下代码块中构建代码,其中根布局的声明较为特殊,如上代码中根布局名称为IndexPage便在kv文件中以:的形式声明根布局,另外根布局的名称是由py文件中引入布局的类名称决定的,如:以上py文件中引入BoxLayout布局的类名称为IndexPage则在kv文件中声明根布局也必须是否则Kivy无法找到对应的声明无法绘制出布局图形。py文件中不管引入什么布局,在kv文件中根布局的名称均由py文件中引入布局的类名称决定。

完成以上操作并运行就可以得到如图一个具备反馈按钮的窗口。

到这里算是写完一个最基础的App啦,接下来就是在Andorid手机上运行啦。

二、Kivy打包

在手机上运行有很多种方式,其中最简单的就是在谷歌应用市场下载Kivy Luncher软件在手机上直接运行App,但是想想在国内还想访问国外网站除非有企业通道不然别想,想了也很危险,况且,如果你真的用Kivy做出了一个APP项目到了发布的时候不可让别人再下载一个单独的软件来运行你的项目对吧?所以呢,我们就得通过打包的方法将我们写的代码打包成一个独立的APP。

(一)、大致概述

通过Kivy,我们可以打包Python代码为Windows、Andoid、IOS的可执行文件。当然我主要是针对Android打包,如果想了解其他的可以去看看官方文档。

(二)、Kivy打包Android的方式

Kivy打包Python代码主要有两种方式:通过Buildozer或者p4a(python-for-android),各有千秋,请自行决定,我这里主要是通过Buildozer完成打包,毕竟自动化环境搭建真的香。buildozer的虚拟机镜像已经给各位读者准备好啦(都是别人给搭建好的,咱拿来直接用,root密码:kivydev)

天翼云盘(不限速):https://cloud.189.cn/t/yqyQ3ueQBZVr (访问码:zbl4)

百度网盘:https://pan.baidu.com/s/1oycJ7Kn2NChq_5gSH8IXew?pwd=y5n9提取码:y5n9

下载好后直接解压就行,点击001后缀进入之后解压.ova后缀文件就行。解压之后自行导入ova虚拟机镜像进入VirtualBox,不会的可以点击这里。VirtualBox不会安装的可以点击这里。

(三)、开始打包

进入打包镜像,当然啦,第一步还是要挂载共享文件夹,如此可以更方便的将你写的Python代码移动到虚拟机镜像中。挂载不会的点击这里。

在任意目录下创建一个项目打包文件夹,建议不要创建在系统自身的文件夹中(亲身试过,崩了QAQ)我是在/home/kivydev/下创建的PackFolder,同样,挂载文件也可以创建在这里。接下来,把通过共享文件夹分享过来的Python文件及kv文件复制进PackFolder。如图:

打开终端,通过cd进入到PackFolder中,执行kdpp go(等同于buildozer android debug)进行打包(kdpp是一个API工具用于对buildozer指令的集成),通过该指令可以生成一个debug版本APP以及一个buildozer.spec文件,kdpp还有如下指令:

kdpp clean# 清理打包环境,等同于buildozer android cleankdpp release# 执行打包命令,生成release版本APP等同于buildozer android releasekdpp go# 执行打包命令,生成debug版本APP等同于buildozer android debug

debug版本与release版本的区别在于,debug会生成日志而release类似于发行版,虽然可以通过修改buildozer.spec文件来生成日志,后续会讲。

打包完成在Terminal会产生如图反馈:

通过kdpp生成了一个位于bin的apk文件,如图:

然后就可以通过共享文件夹,将打包好的APK传送到Windows再传给手机就可以安装运行啦,效果如图:

(四)、buildozer.spec详解

通过kdppgo可以生成buildozer.spec文件,该文件是针对打包的一个集成声明文件,具体含义及其内容如下:

[app]# (str) app应用名title = My Application# (str) 包名结尾package.name = myapp# (str) 包名开头,如果打包release apk必须把test改成其他任意字符串package.domain = org.test# (str) main.py所在目录,默认是spec所在目录source.dir = .# (list) 打包进apk的文件source.include_exts = py,png,jpg,kv,atlas# (list) 打包进apk的文件#source.include_patterns = assets/*,images/*.png# (list) 不打包进apk的文件#source.exclude_exts = spec# (list) 不打包进apk的目录,默认是tests和bin#source.exclude_dirs = tests, bin# (list) 不打包进apk的文件#source.exclude_patterns = license,images/*/*.jpg# (str) app版本version = 0.1# (str) Application versioning (method 2)# version.regex = __version__ = ['"](.*)['"]# version.filename = %(source.dir)s/main.py# (list) 通称 requirements,打包第三方库时必须添加到这里# comma separated e.g. requirements = sqlite3,kivyrequirements = python3,kivy# (str) 第三方库源代码所在目录,如果指定了,打包时就会直接使用这个源代码,不会再去下载。# Sets custom source for any requirements with recipes# requirements.source.kivy = ../../kivy# (list) Garden requirements,如果你用到kivy.graden的库就需要添加到这里#garden_requirements =# (str) app启动时的画面图片(闪屏)路径,默认是kivy图标#presplash.filename = %(source.dir)s/data/presplash.png# (str) app图标路径#icon.filename = %(source.dir)s/data/icon.png# (str) app显示方向,默认是竖屏 (one of landscape, sensorLandscape, portrait or all)orientation = portrait# (list) service服务列表#services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY## OSX Specific### author = © Copyright Info# change the major version of python used by the apposx.python_version = 3# Kivy version to useosx.kivy_version = 1.9.1## Android specific## (bool) app是否全屏,默认否fullscreen = 0# (string) 闪屏的背景色# Supported formats are: #RRGGBB #AARRGGBB or one of the following names:# red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray,# darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy,# olive, purple, silver, teal.#android.presplash_color = #FFFFFF# (list) Permissions app权限配置#android.permissions = INTERNET# (int) Target Android API, 目标api levelandroid.api = 27# (int) Minimum API ,app能支持的最低api levelandroid.minapi = 21# (int) Android SDK 版本#android.sdk = 27# (str) Android NDK 版本android.ndk = 19c# (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi.android.ndk_api = 21# (bool) Use --private data storage (True) or --dir public storage (False)#android.private_storage = True# (str) Android NDK 路径android.ndk_path = /home/kivydev/andr/android-ndk-r19c# (str) Android SDK 路径android.sdk_path = /home/kivydev/andr/android-sdk-linux# (str) ANT directory 路径android.ant_path = /home/kivydev/andr/apache-ant-1.9.4# (bool) 是否跳过Android sdk 升级,默认否# android.skip_update = False# (bool) 升级sdk过程中会询问同意接受sdk license,默认是提示你选择,改为True则是默认同意接受# android.accept_sdk_license = False# (str) app 入口类,一般不修改#android.entrypoint = org.renpy.android.PythonActivity# (str) app主题类型,一般不修改# android.apptheme = "@android:style/Theme.NoTitleBar"# (list) 白名单#android.whitelist =# (str) 白名单文件路径#android.whitelist_src =# (str) 黑名单文件路径#android.blacklist_src =# (list) 自定义jar添加到这里,供jnius调用,支持通配符# OUYA-ODK/libs/*.jar#android.add_jars = foo.jar,bar.jar,path/to/more/*.jar# (list) 自定义java文件添加到这里#android.add_src =# (list) aar文件添加到这里#android.add_aars =# (list) Gradle dependencies to add (currently works only with sdl2_gradle# bootstrap)#android.gradle_dependencies =# (list) add java compile options# this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option# see https://developer.android.com/studio/write/java8-support for further information# android.add_compile_options = "sourceCompatibility = 1.8", "targetCompatibility = 1.8"# (list) Gradle repositories to add {can be necessary for some android.gradle_dependencies}# please enclose in double quotes # e.g. android.gradle_repositories = "maven { url 'https://kotlin.bintray.com/ktor' }"#android.add_gradle_repositories =# (list) packaging options to add # see https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html# can be necessary to solve conflicts in gradle_dependencies# please enclose in double quotes # e.g. android.add_packaging_options = "exclude 'META-INF/common.kotlin_module'", "exclude 'META-INF/*.kotlin_module'"#android.add_gradle_repositories =# (list) 增加java activity到manifest#android.add_activites = com.example.ExampleActivity# (str) OUYA Console category. Should be one of GAME or APP# If you leave this blank, OUYA support will not be enabled#android.ouya.category = GAME# (str) Filename of OUYA Console icon. It must be a 732x412 png image.#android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png# (str) XML file to include as an intent filters intag#android.manifest.intent_filters =# (str) launchMode to set for the main activity#android.manifest.launch_mode = standard# (list) Android additional libraries to copy into libs/armeabi#android.add_libs_armeabi = libs/android/*.so#android.add_libs_armeabi_v7a = libs/android-v7/*.so#android.add_libs_arm64_v8a = libs/android-v8/*.so#android.add_libs_x86 = libs/android-x86/*.so#android.add_libs_mips = libs/android-mips/*.so# (bool) Indicate whether the screen should stay on# Don't forget to add the WAKE_LOCK permission if you set this to True#android.wakelock = False# (list) Android application meta-data to set (key=value format)#android.meta_data =# (list) Android library project to add (will be added in the# project.properties automatically.)#android.library_references =# (list) Android shared libraries which will be added to AndroidManifest.xml using  tag#android.uses_library =# (str) Android logcat filters to use#android.logcat_filters = *:S python:D# (bool) Copy library instead of making a libpymodules.so#android.copy_libs = 1# (str) app架构,支持: armeabi-v7a, arm64-v8a, x86, x86_64android.arch = armeabi-v7a## Python for android (p4a) specific## (str) python-for-android fork to use, defaults to upstream (kivy)#p4a.fork = kivy# (str) 使用的p4a分支#p4a.branch = master# (str) p4a源代码路径,默认从网络下载#p4a.source_dir = # (str) recipes路径#p4a.local_recipes =# (str) Filename to the hook for p4a#p4a.hook =# (str) Bootstrap to use for android builds# p4a.bootstrap = sdl2# (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask)#p4a.port =## iOS specific## (str) Path to a custom kivy-ios folder#ios.kivy_ios_dir = ../kivy-ios# Alternately, specify the URL and branch of a git checkout:ios.kivy_ios_url = https://github.com/kivy/kivy-iosios.kivy_ios_branch = master# Another platform dependency: ios-deploy# Uncomment to use a custom checkout#ios.ios_deploy_dir = ../ios_deploy# Or specify URL and branchios.ios_deploy_url = https://github.com/phonegap/ios-deployios.ios_deploy_branch = 1.7.0# (str) Name of the certificate to use for signing the debug version# Get a list of available identities: buildozer ios list_identities#ios.codesign.debug = "iPhone Developer:   ()"# (str) Name of the certificate to use for signing the release version#ios.codesign.release = %(ios.codesign.debug)s[buildozer]# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))log_level = 2# (int) Display warning if buildozer is run as root (0 = False, 1 = True)warn_on_root = 1# (str) .buildozer文件路径build_dir = /home/kivydev/test/.buildozer# (str) Path to build output (i.e. .apk, .ipa) storage# bin_dir = ./bin#-----------------------------------------------------------------------------#List as sections##You can define all the "list" as [section:key].#Each line will be considered as a option to the list.#Let's take [app] / source.exclude_patterns.#Instead of doing:##[app]#source.exclude_patterns = license,data/audio/*.wav,data/images/original/*##This can be translated into:##[app:source.exclude_patterns]#license#data/audio/*.wav#data/images/original/*##-----------------------------------------------------------------------------#Profiles##You can extend section / key with a profile#For example, you want to deploy a demo version of your application without#HD content. You could first change the title to add "(demo)" in the name#and extend the excluded directories to remove the HD content.##[app@demo]#title = My Application (demo)##[app:source.exclude_patterns@demo]#images/hd/*##Then, invoke the command line with the "demo" profile:##buildozer --profile demo android debug

三、结语

上面就是关于Python运用Kivy开发基础APP以及打包的全过程,后面大部分的教程中提到的Kivy构建的代码打包也可以参考这个打包方法,后期可能会针对打包过程及软件运行过程产生的问题及解决方法进行整合。

温馨提示:建议不要随便乱动镜像中的任何配置,会崩,崩了我也不会修,听镜像作者说当初搭建这玩意废了老大的劲儿,所以不要修改已有配置。

感谢大家的阅读,祝大家心想事成,步步高升哈!