1 原理
1.1 什么是ANE
ANE,全名Adobe Air Native Extension, 中文就是Adobe Air本地扩展。
1.1.1 什么是Adobe Air
学习新知识的一个有效途径当然是从它的出处入手。下面链接就是Adobe官方对于Adobe Air的介绍,如果你已经是Adobe Air开发人员了,那我觉得你可以跳过。
Adobe air官方文档介绍
Adobe air开发人员中心
总结一下Adobe Air:
① 是一个跨操作系统的运行时(类似于java运行时)
② 你可以通过运行时将你开发的Air应用(游戏)部署到桌面或移动设备上
③ 运行基于swf构建的应用(适用于桌面、移动设备)。即通过ActionScript3.0(Adobe官方发布的语言)开发的应用。
④ 运行基于html构建的应用(只适用于桌面)。
本文只涉及移动设备,桌面设备可举一反三
1.1.2 什么是本地扩展(Native Extension)
你通过Adobe Air开发工具开发了一款Air应用,该应用必然运行在桌面或移动设备上,那么这些设备在Air应用看来就是一个本地设备,也就是基础。
那什么是扩展?比如移动设备有音量控制的功能,然而Air应用本身却无法控制移动设备的本地功能,为了使用移动设备的音量控制功能,air应用就需要音量控制功能的本地扩展来帮助完成。类似这样的需求会有很多,而且不同的应用想要的效果也不尽相同。于是Adobe的工程师们基于这样的需求提供了一套解决办法。你只需要按照他们规定的步骤去做,你就能够让你的Air应用像原生的应用一样控制和使用移动设备的功能了。这套解决办法就是ANE(本地扩展),它能够将你的air应用的能力扩展到本地设备上。
当然互联网中也存在着很多大牛实现的一些ANE。奉行不重复造轮子和节省成本的原则,如果他人提供的ANE能够满足需求,那就首选已有的ANE。不过,你想制作定制你自己的功能的ANE,可以按照下文操作。
PS:ANE虽然在Adobe Air应用(游戏)开发中被称为高级部分,它绝没有你想象的那么困难。或许你不懂ActionScript,也不了解安卓,也不怎么知道IOS。没关系,只要你懂得一门面向对象编程语言,那么以下内容对你来说没有障碍。语法这个东西,懂一门你可触类旁通(只要你愿意)。只要你能理解代码逻辑,之后你可以再深入学习。至于安卓和IOS的信息,我会在文中与ANE相关的内容处做简要说明,可以根据我提供的链接深入学习。
1.2 ANE调用原理(ANE怎么起作用的)
ANE调用原理图
说明几点ANE调用原理图:
① 建立Air应用与本地设备的联系的关键就是ane文件
② ANE内部核心1是ActionScript库(swc文件)。它建立Air应用与本地代码的联系
③ ANE内部核心2是本地代码。也就是Android-java类库/Object-C类库。它建立ActionScript库与本地设备的联系
④ 他们的联系遵循着一种规范
本文围绕着ANE展开的,如果你想深入学习其他相关知识,可以看看一下链接。
官方相关知识内容
Adobe ActionScript 3.0 * 使用本手册
ActionScript 3.0 API
面向 ActionScript 开发人员的 Adobe AIR 教程
官方安卓开发培训内容(需要翻墙)
安卓开发培训内容(不需要翻墙)
官方IOS开发教学内容(纯英文good luck)
OK,原理应该很好理解,那具体是怎么做的呢?遵循的规范又是什么?看第二部分实现。
2 实现
2.1 准备制作ANE的材料
通过第一部分ANE原理的描述,我们应该可以看出下一步要做的工作:
①制作一个ActionScript库
②制作一个Android(或IOS)本地代码库。
当然还有一些细节需要我们在下面的制作过程中完善。
2.1.1 实现ActionScript类库
① 创建一个ActionScript库项目,选择图一还是图二根据你的情况来定,他们只是提供的部分库不一样,对于我们的例子来说不影响。
创建名为MySWCLib的项目
再创建一个名为EntryPoint的ActionScript类,我们以这个作为扩展的入口,包名com.xuemin.myswclib
OK,工程创建结束。
代码有以下三点:
① 继承EventDispatcher
public class EntryPoint extends EventDispatcher
EventDispatcher是可调度事件的所有类的基类,事件模型的重要组成部分)暂时不懂没关系
② 创造一个ExtensionContext
ExtensionContext.createExtensionContext(EXTENSION_ID, "");
通过ExtensionContext来访问本地代码
可以通过它的call()方法来调用本地方法
EXTENSION_ID:是我们创建的扩展的唯一标识
③ 给ExtensionContext添加事件监听
extensionContext.addEventListener(StatusEvent.STATUS, onStatus);
异步的本地代码结果会传递到该监听中
PS:如果在你的项目中没有找到ExtensionContext类的话,看看项目的配置是否勾选了包括Adobe AIR库,看下图
OK,经过以上步骤,我们的代码大致应该是这样的
package com.xuemin.myswclib
{
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;
public static const EXTENSION_ID:String = "com.xuemin.myane"; // 我们编写的ane的唯一标识
public function EntryPoint()
{
extensionContext = ExtensionContext.createExtensionContext(EXTENSION_ID, ""); // 创建一个与本地代码调用的ExtensionContext
extensionContext.addEventListener(StatusEvent.STATUS, onStatus); // 添加回调事件返回监听
}
public static function getInstance():EntryPoint { //类单例方式实现
if(instance == null)
instance = new EntryPoint();
return instance;
}
protected function onStatus(event:StatusEvent):void { // 本地代码的回调会返回到该方法
}
}
}
好,这就是一个ActionScript库的基本结构,下面具体描述与本地代码交互。上面叙述了通过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;
}
① call()方法中的第一个参数是本地代码中函数名称,它可以不是本地方法实际的名称,但是必须是约定好的,也就是ActionScript与本地代码中的名称要相同
② call()方法除了第一个之后是一个参数列表,参数可以是ActionScript中的原始数据类型或其ActionScript类对象
通过上面的代码,你可以简单的调用一个本地方法,并向本地方法传递参数,然后再获得本地方法处理后的结果。但是实际的应用情境明显要复杂很多,当你调用一个本地方法后,你不希望air应用停在那里,而是可以继续进行其他工作,当本地方法处理好之后再把结果回调给你,很明显上面的方法的返回结果是无法满足这个需求的。
这个时候就用到了上面addEventListener方法的监听了。它可以获取本地代码发送回来的数据。返回的结果中我们最常用到两个参数code和level
code:作为回调的标识
level:传递的内容
设置监听和监听收到的内容代码大致如下:
// 添加回调事件返回监听
extensionContext.addEventListener(StatusEvent.STATUS, onStatus);
protected function onStatus(event:StatusEvent):void {
// 本地代码的回调会返回到该方法
this.dispatchEvent(event)
if(event.code == "nativeCallbackSuccess") { //本地回调成功的信息
trace(event.level); // 将回调信息打印
} else if(event.code == "nativeCallbackFailed") { //本地回调失败的信息
trace(event.level); // 将回调信息打印
}
}
当然,例子代码中仅仅是将返回的level数据打印了出来,你完全可以再创建一个ActionScript接口,然后将event.level的数据处理完后通过接口回调给air应用。
OK,ActionScript库的编写就这么多了。总结一下吧
① 创建ExtensionContext,这是ActionScript与本地代码的桥梁
② 调用call()方法来调用本地方法,其中参数是方法名并且要保持一致
③ 异步的回调方式,ActionScript会在addEventListener方法添加的监听中获得返回的数据
代码如下:
package com.xuemin.myswclib
{
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;
public static const EXTENSION_ID:String = "com.xuemin.myane"; // 我们编写的ane的唯一标识
public function EntryPoint()
{
extensionContext = ExtensionContext.createExtensionContext(EXTENSION_ID, ""); // 创建一个与本地代码调用的ExtensionContext
extensionContext.addEventListener(StatusEvent.STATUS, onStatus); // 添加回调事件返回监听
}
public static function getInstance():EntryPoint {
//类单例方式实现
if(instance == null)
instance = new EntryPoint();
return instance;
}
protected function onStatus(event:StatusEvent):void {
// 本地代码的回调会返回到该方法
this.dispatchEvent(event)
if(event.code == "nativeCallbackSuccess") { //本地回调成功的信息
trace(event.level); // 将回调信息打印
} else if(event.code =