使用Python3.6搭建安卓App


[TOC]

安装依赖库

Win10

  1. pip install docutils pygments pypiwin32 kivy.deps.sdl2 kivy.deps.glew kivy.deps.gstreamer –extra-index-url https://kivy.org/downloads/packages/simple/
  2. pip install kivy

    成功之后 运行

    kivy ``` 会有
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    ![enter description here](/images/使用Python3.6搭建安卓App/test_import_kivy.png)
    ### 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 效果图为:
test_run_app_on_win
点击”Hello,kivy”字样会变颜色, 如下:
test_run_app_on_win_click
按F1会出现属性菜单, 如下:
test_run_app_on_win_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 os
import time
import logging
from kivy.logger import Logger
Logger.setLevel(logging.TRACE)
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button

Builder.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相应的日志输出:

  1. ImportError,no module named XXX

    在buildozer.spec中增添相应的python库, 如下

    1
    2
    3

    2. 无法调用摄像头或者闪退,这是因为没有给apk相应的权限,需要在buildozer.spec中修改
    > ```android.permissions = INTERNET, CAMERA, CHANGE_WIFI_STATE