使用Python3.6搭建安卓App
[TOC]
安装依赖库 Win10
pip install docutils pygments pypiwin32 kivy.deps.sdl2 kivy.deps.glew kivy.deps.gstreamer –extra-index-url https://kivy.org/downloads/packages/simple/
pip install kivy
成功之后 运行 kivy ``` 会有 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  ### Linux ## 准备py文件 新建一个app.py文件, 内容为 ``` python from kivy.app import App from kivy.uix.button import Button class TestApp(App): def build(self): return Button(text='Hello,kivy') TestApp().run()
在win10下测试代码 打开win cmd, 运行 python app.py 效果图为: 点击”Hello,kivy”字样会变颜色, 如下: 按F1会出现属性菜单, 如下:
部署与安装 在Linux(虚拟机也可)安装buildozer
git clone https://github.com/kivy/buildozer.git pip install .
运行 init```生成buildozer.spec配置文件,修改其中的某些必要字段: 1 2 3 4 5 6 7 8 9 10 11 > title, package.name, package.domain, version 执行```buildozer -v android debug```在./bin目录下生成apk文件 > 注:第一次编译时需要翻墙下载必要的工具,自备梯子且时间较久。 ## 问题 > 等待很久:更新android SDK的问题,需要翻墙或者修改代理 - 修改anaconda目录下的buildozer/targets/android.py,找到_android_list_sdk(), _android_update_sdk() - 修改其中的cmd为加上``` --proxy-host mirrors.neusoft.edu.cn --proxy-port 80 -s```即可加入代理更新SDK > 无法在bin目录下生成apk:需要解决gradle的问题 - 修改anaconda目录下的buildozer/targets/android.py, 找到```build_package```函数,并在```copyfile```之前修改变量```is_gradle_build = False
Aidi cannot be excuted
执行yum apt-get install lib32z1``` 1 2 3 4 5 6 7 8 9 10 ## 应用 与win10上模拟的结果一致。 ## 调试 - 在main.py中设置日志级别 ``` python import logging from kivy.logger import Logger Logger.setLevel(logging.TRACE)
安装adb工具,连接电脑并打开开发者模式,然后输入logcat | grep python```找到输出日志中的```I/python```开头的标识符 1 2 3 4 5 6 7 8 9 10 11 12 ## 总结 ``` flow start=>start end=>end op0=>operation: 下载依赖项 op1=>operation: 修改android.py中的list和update代理服务,从而使得SDK能够正常更新 op2=>operation: 修改android.py中的is_gradle_build=False从而使得生成的apk能够被相应的拷贝到bin输出目录下 op3=>operation: 安装apk到手机调试 start->op0->op1->op2->op3->end
例子 调用摄像头 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 import osimport timeimport loggingfrom kivy.logger import LoggerLogger.setLevel(logging.TRACE) from kivy.app import Appfrom kivy.lang import Builderfrom kivy.uix.boxlayout import BoxLayoutfrom kivy.uix.button import ButtonBuilder.load_string(''' <CameraClick>: orientation: 'vertical' Camera: id: camera index: 0 resolution: (1280, 720) play: False process: False ToggleButton: text: 'Play' on_press: root.play() size_hint_y: None height: '48dp' ToggleButton: text: 'Run' if (camera.process is False) else 'Stop' on_press: root.process() size_hint_y: None height: '48dp' ToggleButton: text: 'Overturn' on_press: root.overturn() size_hint_y: None height: '48dp' Button: text: 'Capture' size_hint_y: None height: '48dp' on_press: root.capture() ''' )class CameraClick (BoxLayout) : ''' ''' def __init__ (self) : ''' ''' self._print('Start Here' ) super(CameraClick, self).__init__() return def _print (self, inputs = '' ) : ''' ''' ctx = '[*] ' for i in range(50 ): ctx += '* ' logging.info(ctx) for i in range(5 ): if i == 2 : logging.info('[*]' + '\t\t\t\t' + inputs + ' ' + time.strftime('%Y/%m/%d %H:%M:%S' )) else : logging.info('[*]' ) ctx = '[*] ' for i in range(50 ): ctx += '* ' logging.info(ctx) return def __del__ (self) : ''' ''' self._print('End Here' ) return def play (self) : ''' ''' camera = self.ids['camera' ] camera.play = not camera.play logging.info('[* << Press >> *]' ) return def process (self) : ''' ''' camera = self.ids['camera' ] if camera.play is True : camera.process = not camera.process else : camera.process = False logging.info('[* << Process >> *]' ) return def overturn (self) : ''' ''' camera = self.ids['camera' ] camera.index = 1 - camera.index logging.info('[* << Overturn >> *]' ) return def capture (self) : ''' ''' camera = self.ids['camera' ] timestr = time.strftime('%Y%m%d_%H%M%S' ) camera.export_to_png('/sdcard/app_lamia/images/IMG_{}.jpg' .format(timestr)) logging.info('[* << Captured >> *]' ) return class TestCameta (App) : def build (self) : return CameraClick() TestCameta().run()
实际编译之后会出现如下问题,若程序闪退需打开abd并grep python相应的日志输出:
ImportError,no module named XXX
在buildozer.spec中增添相应的python库, 如下
1 2 3 2. 无法调用摄像头或者闪退,这是因为没有给apk相应的权限,需要在buildozer.spec中修改 > ```android.permissions = INTERNET, CAMERA, CHANGE_WIFI_STATE