创建名为MyNativeLib的项目再创建一个名为EntryPoint的ActionScript类,我们以这个作为扩展的入口,
包名com.booyue.myane,OK,工程创建结束。
代码有以下三点:
① 继承EventDispatcher
public class EntryPoint extends EventDispatcher
EventDispatcher是可调度事件的所有类的基类,事件模型的重要组成部分)暂时不懂没关系
② 创造一个ExtensionContext
ExtensionContext.createExtensionContext(EXTENSION_ID, “”);
通过ExtensionContext来访问本地代码
可以通过它的call()方法来调用本地方法
EXTENSION_ID:是我们创建的扩展的唯一标识
③ 给ExtensionContext添加事件监听
extensionContext.addEventListener(StatusEvent.STATUS, onStatus);
异步的本地代码结果会传递到该监听中
具体代码如下:
package com.booyue.myane
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.StatusEvent;
import flash.external.ExtensionContext;
public class EntryPoint extends EventDispatcher{
private static var instance:EntryPoint;
private static var extensionContext:ExtensionContext;
// 我们编写的ane的唯一标识
public static const EXTENSION_ID:String = "com.booyue.myane";
public function EntryPoint(){
// 创建一个与本地代码调用的ExtensionContext
extensionContext = ExtensionContext.createExtensionContext(EXTENSION_ID, "");
extensionContext.addEventListener(StatusEvent.STATUS, onStatus); // 添加回调事件返回监听
}
public static function getInstance():EntryPoint { //类单例方式实现
if(instance == null)
instance = new EntryPoint();
return instance;
}
//本地代码的回调会返回到该方法
protected function onStatus(event:StatusEvent):void{
//event.level回调内容 event.code区分回调的类别
//dispatchEvent(new KeyValueEvent(KeyValueEvent.ASR_RESULT,event.level+"=="+event.type+"=="+event.code,false,false));
if(event.code == "notifyKeyValueChange"){
dispatchEvent(new KeyValueEvent(KeyValueEvent.RESULT,event.level,false,false));//向flash分发事件
}else if(event.code == "notifyAsrCallback"){
dispatchEvent(newKeyValueEvent(KeyValueEvent.ASR_RESULT,event.level,false,false));
}
}
}
}
}
下面叙述了通过ExtensionContext来访问本地代码,通过它的call()方法来调用本地方法,具体代码如下:
public static function getNativeData():String {
var params1:int = 3;
var params2:String = "paramsString";
if(extensionContext != null)
return extensionContext.call("getNativeData",params1,params2) as String;
else
return null;
}
由于这套规范必然是Adobe的工程师们设计的,所以我们得通过他们提供的入口和规范来实现我们想要的功
能,因此我们需要Adobe提供的java库了,路径在/AirSDK根目录/lib/android/FlashRuntimeExtensions.jar
将FlashRuntimeExtensions.jar添加到你的安卓工程中
air_sdk下载链接
① 实现FREExtension接口
FREExtension是扩展的入口,需要返回一个FREContext的对象,通过接口定义的createContext可以获得本地代码的连接器(上下文)
public class NativeExtension implements FREExtension{
private static final String TAG = "NativeExtension";
public static FREContext extensionContext;
public static Context appContext;
public static void notifyKeyValueChange(String str) {
LogManager.d("notifyKeyValueChange");
if(extensionContext != null){
extensionContext.dispatchStatusEventAsync("notifyKeyValueChange", str);
Log.d(TAG, "dispatchStatusEventAsync");
}
}
public static void notifyAsrCallback(String str) {
LogManager.d("notifyAsrCallback");
if(extensionContext != null){
extensionContext.dispatchStatusEventAsync("notifyAsrCallback", str);
Log.d(TAG, "dispatchStatusEventAsync");
}
}
/**
* 需要返回一个FREContext对象
*/
@Override
public FREContext createContext(String s){
Log.d(TAG, "createcontext begin");
return new NativeContext();
}
/***
* Extension结束后的操作
*/
@Override
public void dispose() {
appContext = null;
extensionContext = null;
Log.d(TAG, "dispose begin");
}
/**
* Extension初始化的操作
*/
@Override
public void initialize() {
Log.d(TAG, "Extension initialized");
}
}
② 实现FREContext对象。
该对象就是本地代码的连接器(上下文),通过该对象的getFunctions()返回给ActionScript能够调用到的方法集合,该方法集合都是FREFunction的子类
public class NativeContext extends FREContext{
private static final String TAG = "NativeContext";
/**
* 返回一个包含FREFunction的map集合
*
* @return
*/
@Override
public Map getFunctions() {
Log.d(TAG, "getFunctions begin");
Map map = new HashMap();
map.put("init", new InitFunction());//注册滑块监听
map.put("writePassInfo", new InitFunction());//写入过关信息
map.put("record", new InitFunction());//开始录音
map.put("play", new InitFunction());// 播放录音
Log.d(TAG, "createcontext success");
return map;
}
@Override
public void dispose() {
// TODO Auto-generated method stub
Log.d(TAG,"Context disposed");
}
}
把FREContext传递给Extension
@Override
public FREContext createContext(String arg0) { //需要返回一个FREContext对象
NativeContext context = new NativeContext();
return context;
}
③ 实现FREFunction接口
该接口定义了一个方法,叫做call,是不是很熟悉,对,这个call方法与ActionScript中的ExtensionContext的call方法是对应的,这也是它们沟通的最后一步
public class GetNativeDataFunction implements FREFunction{
@Override
public FREObject call(FREContext arg0, FREObject[] arg1) {
return null;
}
}
注意几点:
① 参数一arg0,也就是FREContext对象。它有一些实用的方法,如获取Activity,Activity在Android中是一个很重要的组件,它负责与用户交互,可以加载UI并且根据不同情况有对应的生命周期方法。
Activity activity = arg0.getActivity();
FREFunction的代码如下:
public class GetNativeDataFunction implements FREFunction{
@Override
public FREObject call(FREContext arg0, FREObject[] arg1) {
Activity activity = arg0.getActivity();
Log.i("ANE", activity.getPackageName()); // 使用安卓的日志方法打印出应用的包名
int params1 = 0;
String params2 = null;
try {
params1 = arg1[0].getAsInt(); // 获取第一个参数
params2 = arg1[1].getAsString(); // 获取第二个参数
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (FRETypeMismatchException e) {
e.printStackTrace();
} catch (FREInvalidObjectException e) {
e.printStackTrace();
} catch (FREWrongThreadException e) {
e.printStackTrace();
}
FREObject freObject = null;
try {
String nativeData = params1 + params2; //将参数1与参数2拼接
freObject = FREObject.newObject(nativeData);
} catch (FREWrongThreadException e) {
e.printStackTrace();
}
return freObject; //返回结果
}
}
将FreFunction添加到FreContext
@Override
public Map<String, FREFunction> getFunctions() { // 需要返回一个包含FREFunction的Map集合
Map<String, FREFunction> map = new HashMap<String, FREFunction>();
map.put("getNativeData", new GetNativeDataFunction());
return map;
}
② 关于安卓的生命周期的处理
了解点安卓的同学应该知道,常常会用到Activity的生命周期的方法,那在本地代码中如何处理?Adobe工程师设计了一个Activity的包装类AndroidActivityWrapper,通过给包装类注册监听来监听安卓Activity的变化。
你会发现在扩展的jar包并没有这个类,那是因为扩展还是上面一层,而安卓的Activity涉及到了设备代码,所以它自然而然处在了Air的Runtime中,所以你还需要一个runtime的jar包。在路径/Air_SDK根目录/lib/android/lib/runtimeClasses.jar
导入runtimeClasses.jar,OK,可以找到AndroidActivityWrapper类了
同样我们监听还需要在runtime中的StateChangeCallback接口和ActivityResultCallback接口
注意一点:反编译runtimeClasses.jar看AndroidActivityWrapper类中StateChangeCallback接口和ActivityResultCallback接口时,发现这两个接口时protected的,也就是说,如果要实现这两个接口就需要与AndroidActivityWrapper在同一个包下,即在com.adobe.air包下。
static abstract interface ActivityResultCallback{
public abstract void onActivityResult(int paramInt1, int paramInt2, Intent paramIntent);
}
static abstract interface StateChangeCallback {
public abstract void onActivityStateChanged(AndroidActivityWrapper.ActivityState paramActivityState);
public abstract void onConfigurationChanged(Configuration paramConfiguration);
}
所以,按照以下实现思路操作:
在com.adobe.air包路径下创建新接口继承ActivityResultCallback和StateChangeCallback,但是把权限放大到public
于是在com.adobe.air下先创建抽象接口,继承ActivityResultCallback和StateChangeCallback,代码如下:
package com.adobe.air;
import com.adobe.air.AndroidActivityWrapper.ActivityResultCallback;
import com.adobe.air.AndroidActivityWrapper.StateChangeCallback;
public abstract interface LifeCycle extends ActivityResultCallback, StateChangeCallback{}
通过上面的方法,在我们自己的代码中就可以处理生命周期了
于是再改造一下NativeContext类,实现我们自己的LifeCycle接口
在构造函数中添加监听,在dispose方法中移除监听
public class NativeContext extends FREContext implements LifeCycle{
private AndroidActivityWrapper activityWrapper;
public NativeContext() {
activityWrapper = AndroidActivityWrapper.GetAndroidActivityWrapper(); //ActivityWrapper
activityWrapper.addActivityResultListener(this); // 监听onActivityResult方法
activityWrapper.addActivityStateChangeListner(this); // 监听生命周期方法
}
@Override
public void dispose() { // Context结束后的操作
if(activityWrapper != null)
activityWrapper.removeActivityResultListener(this);
activityWrapper.removeActivityStateChangeListner(this);
}
@Override
public Map getFunctions() { // 需要返回一个包含FREFunction的Map集合
Map map = new HashMap();
map.put("getNativeData", new GetNativeDataFunction());
return map;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { // onActivityResult方法
}
@Override
public void onActivityStateChanged(ActivityState state) { // 生命周期变化
}
@Override
public void onConfigurationChanged(Configuration config) {
}
}
其中生命周期的对应关系如下:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { // onActivityResult方法
Log.i(“ANE”, “onActivityResult”);
}
@Override
public void onActivityStateChanged(ActivityState state) { // 生命周期变化
switch (state) {
case RESUMED: // 生命周期onResume
Log.i(“ANE”, “onResume”);
break;
case STARTED: // 生命周期onStart
Log.i(“ANE”, “onStart”);
break;
case RESTARTED: // 生命周期onRestart
Log.i(“ANE”, “onRestart”);
break;
case PAUSED: // 生命周期onPause
Log.i(“ANE”, “onPause”);
break;
case STOPPED: // 生命周期onStop
Log.i(“ANE”, “onStop”);
break;
case DESTROYED: // 生命周期onDestory
Log.i(“ANE”, “onDestory”);
break;
}
}
以上就是安卓本地代码的处理了,总结一下
① 核心类FREExtension,FREContext,FREFunction
② 通过FREContext连通,call方法调用
③ 异步回调可以通过FREContext的dispatchStatusEventAsync处理
④ 生命周期的实现需要点技巧
进过上面操作代码逻辑层面已经处理完了,废话不说,通过上面的东西,制作可用的ANE
2.2.1 准备资源
以下是一个ANE打包的资源清单,只需要Android或者IOS的同学可自由组合,后面分别介绍它们
Android本地代码库——jar包(Android需要)
IOS本地代码库——IOS静态库文件(IOS需要)
ActionScript库——SWC文件(必须)
library.swf(必须)
extension.xml(必须,Android与IOS配置不同)
platformoptions.xml (IOS可能需要)
第三方库文件 (IOS可能需要)
1 Android本地代码库——jar包
先将android本地代码导出jar包,右键Eclipse工程,Export
2 ActionScript库——SWC文件(必须)
swc文件将改为rar文件,在解压就生成swf和catelog.xml文件
4.extension.xml文件
<extension xmlns="http://ns.adobe.com/air/extension/3.5">
<id>com.booyue.myaneid>
<versionNumber>1versionNumber>
<platforms>
<platform name="default">
<applicationDeployment>
applicationDeployment>
platform>
<platform name="Android-ARM">
<applicationDeployment>
<nativeLibrary>MyNativeLib.jarnativeLibrary>
<initializer>com.xuemin.mynativelib.NativeExtensioninitializer>
applicationDeployment>
platform>
<platform name="iPhone-ARM">
<applicationDeployment>
<nativeLibrary>libMyNativeLib.anativeLibrary>
<initializer>ExtensionInitializerinitializer>
<finalizer>ExtensionFinalizerfinalizer>
applicationDeployment>
platform>
platforms>
extension>
通过adb命令
adt -package -target ane L1FlashAndroidLib.ane extension.xml -swc L1FlashLib.swc -platform Android-ARM L1NativeLib1.jar library.swf -platform default library.swf
备注:希望对于想学习ane开发的同学有帮助。