高占江, 韩丹
(青岛科技大学(高密校区), 计算机系, 山东, 潍坊 261500)
移动应用开发已成为现代科技发展的重要领域,而AppInventor的出现为普通用户提供了一种简单、直观的方式来创建自己的移动应用。然而,虽然AppInventor提供了丰富的积木块用于实现各种功能,但其积木块的种类和数量仍然存在一定的限制。这意味着开发者在设计应用时可能会受到功能上的限制,无法实现一些个性化或复杂的功能。为了解决这个问题,本文提出一种创新的方法,即利用JavaReflector技术在AppInventor中调用Android-SDK的Java语言的API。通过这种方法,开发者可以直接阅读Java API文档和Android API文档,并在AppInventor中在不需要自己定制拓展组件的情况下调用Android-SDK所提供的API。这种技术为开发者提供了一个桥梁,能够将AppInventor与Android SDK中API无缝连接起来,从而实现功能的无限扩展。
本文详细介绍JavaReflector技术在AppInventor中的应用,探讨其实现的原理和方法,并通过一系列实验验证其可行性和有效性。我们相信,通过这种创新的方法,能够帮助开发者在AppInventor中实现更加丰富、个性化的功能,从而推动移动应用的发展和创新。
当今社会智能终端的应用无处不在,移动智能端操作系统Android占有了市场70%以上的份额是因为Android系统的App的开发吸引了更多开发者的眼球。
Android操作系统中编程方式很多,其中Google公司开发的AppInventor编程方式吸引了很多初学者,特别是中小学编程爱好者的目光。Google AppInventor[1]编程方式是一个完全在线的Android系统的App开发模式,它不需要开发者使用任何一种编程语言,只需要用一种类似积木式的搭建方式来开发自己的应用程序,这种方式让很多对编程望而却步的初学者兴趣倍增,除此之外,它支持乐高NXT机器人,对机器人开发者来说更是一大福音。
AppInventor中所有的组件都可以直接被拖曳使用,并且每个组件都将其属性和相关的事件被可视化处理,构造成了具有特殊接口的“积木”。开发者的需求是千变万化的,但AppInventor中每个组件提供的属性是有限的,每个组件的方法也是有限的,从这方面考虑,这种编程方式是非常受限的,对有过其他编程语言开发经验的开发者来说,使用Java语言编写Android App可以使用很多的类和对象,更有无数的方法和函数去调用,对比在AppInventor中可调用的类或者函数变得非常局限,这给这种开发方式一个启发。
本文在AppInventor中提供一种扩展功能的调用方式,允许在积木式的编程环境中调用Android SDK[2],实现与代码编程同样的功能效果。JavaReflector技术的作用是通过“积木块”调用Android系统底层接口,能够充分使用SDK提供的各种类、对象、成员变量属性和方法,即Android SDK提供的所有方法和接口都能够转化为“积木块”在AppInventor编程环境中被使用,扩充了开发的逻辑环境。
在Android的原生态编程环境中,使用Java语言编程是Android编程最常用的方式,“按钮”在代码编程中是调用底层Android SDK中的android.widget.Button[3]类,在Eclipse或AndroidStudio等代码开发环境中,可以直接使用类Button创建的对象调用其属性或方法实现相应的功能,如更改按钮显示的文本调用对象Button的setText()方法即可。在AppInventor中的“按钮”是一种可视化的组件,开发者直接拖曳到组件设计面板即可,想更改其文本可以直接使用其提供的块,如图1所示。
图1 更改按钮文本块
但AppInventor提供的类似这种事件块是很有限的,因为AppInventor中拖曳的“按钮”是类com.google.appinventor.components.runtime.Button,它是对Android SDK中提供的android.widget.Button类的封装,所以通过JavaReflector技术构建起这2个类之间的桥梁,就可以通过AppInventor中的“块”调用SDK中的属性和方法。在组件面板中拖入JavaReflector组件[4],通过图2的方法获取AppInventor中的“按钮1”所封装的SDK中的Button类的对象(Button类的实例)。
图2 获取按钮的内部实例
获得android.widget.Button类的实例之后,可以通过该实例调用其方法或属性实现相应的动作,例如在SDK中对按钮文本的更改使用的是public final void setText (CharSequence text)函数[5],要注意的是,在AppInventor块编程环境中,执行该函数的方法也是通过JavaReflector组件,如图3所示。
图3 JavaReflector组件执行SDK提供的方法
使用的组件块是InvokeMethod,第一个参数instance实例即获取的按钮的内部类android.widget.Button类的实例,第二个参数method就是该对象要调用的方法或者函数的名称,这里只写函数的名字和参数,函数的()由<>代替,并且参数只需要指明参数的类型。第三个参数是实参列表,首先使用创建列表块准备创建列表,每个参数作为“列表块”的一个元素拼接即可。该方法的含义就是更改按钮显示的文字,将图3所示的代码块拼接在按钮1的点击事件里面,当点击按钮时就会更改其显示的文本为“Hello”。
在AppInventor的块编程环境中,有很多组件是“不可见”组件,例如音乐播放器组件[6],下面以音乐播放器组件为例说明不可见组件调用SDK中函数的方式。通过“输出调试信息”块可以得到“音乐播放器”组件在AppInventor中的类com.google.appinventor.components.runtime.Player(以下简称Player类)[7],通过AppInventor的源代码分析可以得到这个类的定义中包含了SDK中播放的引擎类android.media.MediaPlayer(以下简称MediaPlayer类),真正实现歌曲播放暂停等功能的核心类就是android.media.MediaPlayer,所以问题的关键在于在AppInventor环境中获取不可见组件“音乐播放器”所对应的android.media.MediaPlayer类的实例对象,通过这个MediaPlayer类的实例对象就可以实现AppInventor环境中没有实现的“获取歌曲时长”“播放定位”块的功能,因为Player类封装了MediaPlayer类,首先获取Player类(不包括其父类)的所有字段(类的成员变量),如图4所示。
图4 获取类的所有字段
该方法是返回一个列表,因为只关心列表中的MediaPlayer类,所以需要从列表中查找出包含“MediaPlayer”的列表项,使用循环程序对列表中的每个项检索,可获得MediaPlayer类型的字段,如图5所示。
图5 检索字段列表中指定类型的字段
输出该列表项信息如下:
private android,media,MediaPlayer com,google,appinventor,components,runtime,Player.I;[8]
得到了需要的MediaPlayer类的字段。下面就是要获得这个字段的实例(对象),从输出信息可以看出AppInventor对类的变量名称(类的对象/实例)进行了加密处理,所以不能直接获得这个实例,还需要通过JavaReflector技术来获取。JavaReflector组件提供了获取对象内部字段值的块,如图6所示。
图6 获取对象的字段的值(实例/对象)
运行之后输出信息:android.media.MediaPlayer@2e7129f5[9],说明获取了内存中的具体对象,并且是SDK中的android.media.MediaPlayer类型,说明这个对象就是App-Inventor环境中不可见组件“音频播放器1”所封装的An-droid SDK中的MediaPlayer实例。有了这个对象之后,App-Inventor中“音频播放器1”组件未提供的方法,可以通过MediaPlayer类的实例调用其函数来实现。
3.2.1 获取歌曲总时长
在Android SDK中通过调用MediaPlayer对象的getDuration()]方法可以获得当前播放歌曲的总时间长度,使用刚刚获得的MediaPlayer实例来实现如图7所示。
图7 JavaReflector执行无参函数
图7中的instance参数为执行函数的实例(对象),就是获取的MediaPlayer类(已经赋值给全局变量),method参数为执行的函数名称,因为该函数不需要参数,所以直接给定函数名称即可,参数列表为空列表即可。
3.2.2 定位播放位置
定位播放位置的函数为seekTo(int msec)[10],该函数接收一个int类型参数,使用JavaReflector组件的InvokeMethod执行该函数即可,如图8所示。
图8 JavaReflector定位播放位置
需要强调的是,参数的形式为<>,内部仅需要放置各形参的类型,使用上类似于Java语言中的泛型,在参数列表中设置实参。
AppInventor编程环境是一种全新的开发模式,它注重中文思维的编程模式,抛弃了复杂的编程语言的束缚,让编程变得自由,但这种环境在App开发中还有很多局限性,很多SDK中实现的功能它无法实现,为了弥补不足,JavaReflector技术搭建起了两者的桥梁,本文详细阐述了JavaReflector技术在AppInventor编程环境中扩展功能的使用方式,从原理上剖析了它在获得核心类实例的思路以及JavaReflector执行其函数的方式。