耐着性子钻研了一下sl4a与QPython之类,取得了些经验,汇报如下:
本文使用的apk安装包如下: QPython: QPython70.apk;sl4a+Python:sl4a_r6.apk;PythonForAndroid_r4.apk。安装与使用方法十分简单,网上参考很多,本文不再重复安装方法与HelloWorld之类。
I. sl4a+Python
1. 重要参考资料:
(1)(2) ;(3) 如何使用Webview:
2. 以下一例,演示如何通过sl4a api取得Gps与罗盘信息,相关技术资料详见详见参考资料(2)中LocationFacade;SensorManagerFacade章节
# -*- coding: utf-8 -*-import androidimport timefrom math import radiansdroid = android.Android()droid.startSensingTimed(1, 250)droid.startLocating()while 1: gpsdata = droid.readLocation().result s6data = droid.sensorsReadOrientation().result if len(gpsdata)>0: print gpsdata['gps']['bearing'] #取得Gps导向(bearing)(角度) if len(s6data)>0: print s6data[0] #取得罗盘方位角(azimuth)(弧度) time.sleep(0.5)droid.stopLocating()droid.stopSensing()
3. 关于使用webview做UI,请参考资料(1)与(3),如下提供一个例子(简单指北针),演示Python后端如何与Webview通信,不过此例仅含Python向Webview单向发送数据:webview作为前端,用svg做了一个简单的指北针,每0.5秒根据Python后端读取的方位角数据更新一次。
import androidimport timefrom math import radiansdroid = android.Android()droid.webViewShow('file:///sdcard/sl4a/scripts/compassSVGDrawing.html')droid.startSensingTimed(1, 250)while 1: s6data = droid.sensorsReadOrientation().result if len(s6data)>0: try: az = s6data[0] droid.eventPost('dataout', str(az)) except: pass time.sleep(0.5)droid.stopSensing()# compassSVGDrawing.html'''
4. SL4A与蓝牙
手头有个蓝牙GPS,就拿来操练了一下,尝试了一下读取蓝牙设备,没想到在我的华硕FonePad上实验很顺利,效果相当不错。
import androidimport timedroid = android.Android()droid.toggleBluetoothState(True)result = droid.bluetoothConnect('00001101-0000-1000-8000-00805F9B34FB', '00:02:76:C9:92:44')#SSP之默认UUID与蓝牙设备物理地址print repr(result)if result: while True: message = droid.bluetoothReadLine().result print messagedroid.toggleBluetoothState(False)
II. Qpython
QPython安装仅需一个apk,界面也比sl4a丰富一些,内容已然相当成熟,已经整合了不少好东西,我尝试了其中的androidhelper(基于sl4a)、kivy(出色的图形库)、bottle(精悍的web架构)。
1. 先详细说说QPython与sl4a+Python方案的区别:
(1)QPython整合了sl4a api,如下是QPython调用sl4a api的代码:
import androidhelperdroid = androidhelper.Android()
(2)需强调的一点,QPython目前没有实现sl4a与webview的内在通信机制(上文中的指北针代码不适用于QPython),我认为这是个不足,不过QPython能够制作功能相当的web app,且可以使用kivy制作精良的图形界面、游戏之类的,这是其优势所在。
(3)QPython内置了bottle web架构,也可以从QPypi安装其他一些流行的web工具,对于制作web app、服务器之类而言肯定更有优势。
(4) 两者对webview的调用功能有别,细节尚不清楚,兼容性有差异,在我的平板上,QPython在支持svg方面与sla4相比较表现出一些差异,不支持 width ="100%"这样的设置,使用sl4a时却支持。若使用sl4a调用Webview显示含canvas的网页,其画质十分粗糙。
2. kivy
据我的感受,QPython中的kivy真是个好东西,做出来的界面很漂亮,很稳定,就是貌似不太好学。鉴于我还没有一知半解,贴几个对我有所启发的代码和我自己做的一个例子,均在Android设备上测试通过:
(1) 使用StackLayout:
注意#1,这部分使用的语言是kivy语言,对kivy核心元素,即widget,安排布局、设定属性。注意如下代码中<ScreenUI>(#2、#4),其性质是一个用户定义的widget,继承StackLayout,如果无需对StackLayout 编程,则不需要在kivy语言中与Python中专门定义<ScreenUI>,使用StackLayout就可以。ScreenUI这个widget也就成为了一个root,可以用来控制widget的行为与属性(#3、#5)。
from kivy.app import Appfrom kivy.uix.boxlayout import BoxLayoutfrom kivy.uix.label import Labelfrom kivy.lang import Builderfrom kivy.uix.textinput import TextInputfrom kivy.uix.stacklayout import StackLayoutfrom kivy.uix.button import ButtonBuilder.load_string(""" #1: #2 orientation: 'lr-bt' Button: text: root.text #3 size: 100, 100 size_hint: None, None Button: text: 'Button 2' size_hint: None, None size: 200, 100""")class ScreenUI(StackLayout): #4 text = "Button 1" #5class WidgetApp(App): def build(self): app = ScreenUI() return appif __name__ == '__main__': WidgetApp().run()
(2) 旋转图片:尝试旋转三张重叠图片,角度可控,将角度显示在一个标签
from kivy.app import Appfrom kivy.uix.image import Imagefrom kivy.lang import Builderfrom kivy.properties import NumericPropertyfrom kivy.uix.floatlayout import FloatLayoutBuilder.load_string('''[Title@Label] pos_hint: {'center_x': .5, 'y': .3} text: ctx.text font_size: 16: FloatLayout: Title: text: root.message Image: source: 'kivy.png' canvas.before: PushMatrix Rotate: angle: root.angle origin: self.center canvas.after: PopMatrix Image: source: 'Red.png' canvas.before: PushMatrix Rotate: angle: root.angle origin: self.center canvas.after: PopMatrix Image: source: 'tinyCompass.png' canvas.before: PushMatrix Rotate: angle: root.angle origin: self.center canvas.after: PopMatrix''')class RotationWid(FloatLayout): angle = NumericProperty(-45) message = '45 degrees' class RotationApp(App): def build(self): return RotationWid()RotationApp().run()
(3)通过旋转图片实现的指北针
from kivy.app import Appfrom kivy.uix.image import Imagefrom kivy.clock import Clockfrom kivy.lang import Builderfrom kivy.properties import NumericPropertyfrom math import piimport androidhelperimport timedroid = androidhelper.Android()droid.startSensingTimed(1, 250)Builder.load_string(''': source: 'Red.png' size: 256,256 canvas.before: PushMatrix Rotate: angle: root.angle origin: self.center canvas.after: PopMatrix''')class RotateCompass(Image): angle = NumericProperty(0) def __init__(self, **kwargs): super(RotateCompass,self).__init__(**kwargs) Clock.schedule_interval(self.my_callback, 1) #clock时间处理,周期为1秒,动作定义在my_callback中,周期性给angle赋值 def my_callback(self,dt): s6data = droid.sensorsReadOrientation().result if len(s6data)>0: self.angle = 180 * s6data[0] / pi class RotationApp(App): def build(self): return RotateCompass()RotationApp().run()droid.stopSensing()
3. QPython Web App
QPython只给了一个简单的例子,资料少的可怜。尝试了一下,也整出一罗盘来。用XMLHttpRequest与长轮询(long polling)这个解决方法实现网页客户端与服务器的通信。
#qpy:webapp:Compass_Long_Polling #qpy:fullscreen#qpy://localhost:8080/ #此行必须"""This is a sample for qpython webapp"""from bottle import route, runimport androidhelperimport signal, osimport timecode = ''''''droid = androidhelper.Android()droid.startSensingTimed(1, 250)@route('/')def index(): return code@route('/azimuth')def azimuth(): time.sleep(0.3) s6data = droid.sensorsReadOrientation().result if len(s6data)>0: return str(s6data[0])@route("/shutdown")def shutdown(): droid.stopSensing() os.kill(os.getpid(), signal.SIGTERM)run(host='localhost', port=8080)
4. jQuery Mobile
尝试了一下jQuery Mobile,也就是拷贝到某个子目录后观察了一下例子,在QPython中使用没问题,暂没用它干什么,不多说了。