ANE 在 Android 上的应用

http://blog.csdn.net/linxcool/article/details/7770179

概述

Adobe Air是利用Adobe公司的Flash技术开发的媒体播放平台。而Native Extension就是让AIR可以调用各个平台上的本地代码(native code, 如ios上的object-c,android上的java,desktop上的c++,c#等),从而完成对AIR中Actionscript API的自定义扩展。即可以让开发者通过编写基于平台的本地代码扩展ActionScript。从而完成一些原有Actionscript无法完成的功能。

Native Extension结构及原理

一个NativeExtension项目主要有两个部分组成:As 端的库项目和底层代码的实现项目。
下图是Android 上整个NativeExtension项目的体系结构。

ANE 在 Android 上的应用_第1张图片

AS库项目部分

ExtensionContext是其核心类,负责与Java代码的交互。ExtensionContext需要调用createExtensionContext方法创建和初始化Java端的本地代码。而是用call方法可以调用具体的Java代码并获得返回结果。同时Extension还会接受从java代码抛出的事件。

本地java项目部分

关键类 FREContext
关键接口 FREExtension、FREFunction

FREExtension是java端自定义代码的入口,需要重写createContext方法从而获得本地代码的上下文,即自己扩展的FREContext子类。
FREFunction是本地方法的具体实现,实例化后以键值对的形式存入FREContext,从而在AS端的ExtensionContext中调用的call方法中传入对应键值调起本地方法。

开发流程

项目分成三部分:Android项目,Flex Library库项目和Flex Mobile项目

Android项目

1、在Eclipse中新建Android项目,不必勾选创建Activity

2、将项目的类型设为Library型
properties -> Android -> 勾选 Is Libirary

3、导入Ane android jar包(FlashRuntimeExtensions.jar)

4、添加java本地实现

  1. public class SkyExtension implements FREExtension{  
  2.     @Override  
  3.     public FREContext createContext(String pType) {  
  4.         return new SkyContext();  
  5.     }  
  6.     @Override  
  7.     public void dispose() {}  
  8.     @Override  
  9.     public void initialize() {}  
  10. }  
public class SkyExtension implements FREExtension{
	@Override
	public FREContext createContext(String pType) {
		return new SkyContext();
	}
	@Override
	public void dispose() {}
	@Override
	public void initialize() {}
}
  1. public class SkyContext extends FREContext{  
  2.   
  3.     @Override  
  4.     public void dispose() {}  
  5.     @Override  
  6.     public Map<String, FREFunction> getFunctions() {  
  7.         HashMap<String, FREFunction> map = new HashMap<String, FREFunction>();  
  8.         map.put("keyA"new TestToastFunction());  
  9.         //可继续put其他function  
  10.         return map;  
  11.     }  
  12.   
  13. }  
public class SkyContext extends FREContext{

	@Override
	public void dispose() {}
	@Override
	public Map<String, FREFunction> getFunctions() {
		HashMap<String, FREFunction> map = new HashMap<String, FREFunction>();
		map.put("keyA", new TestToastFunction());
		//可继续put其他function
		return map;
	}

}
  1. public class TestToastFunction implements FREFunction{  
  2.     @Override  
  3.     public FREObject call(FREContext context, FREObject[] params) {  
  4.         Toast.makeText(context.getActivity(), "测试成功:android本地被调用", Toast.LENGTH_LONG).show();  
  5.         FREObject result=null;  
  6.         try {  
  7.             result = FREObject.newObject("这是可返回的值");  
  8.         } catch (Exception e) {  
  9.             e.printStackTrace();  
  10.         }  
  11.         return result;  
  12.     }  
  13.   
  14. }  
public class TestToastFunction implements FREFunction{
	@Override
	public FREObject call(FREContext context, FREObject[] params) {
		Toast.makeText(context.getActivity(), "测试成功:android本地被调用", Toast.LENGTH_LONG).show();
		FREObject result=null;
		try {
			result = FREObject.newObject("这是可返回的值");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

}

5、导出jar包(AneTestNative.jar)

 

Flex Library库项目

1、新建Flex Library项目,注意指定AIR3的SDK,并且勾选“包括Adobe AIR库”
2、在src下新建包,并添加as代码

  1. package com.linxcool.test  
  2. {  
  3.     import flash.external.ExtensionContext;  
  4.     public class HelloWorldExtension  
  5.     {  
  6.         public static const KEY:String = "keyA";//与java端中Map里的key一致  
  7.         public static const EXTENSION_ID:String = "extTest";//与extension.xml中的id标签一致  
  8.         private var extContext:ExtensionContext;  
  9.         public function HelloWorldExtension()  
  10.         {  
  11.   
  12.             //第二个为参数,会传入java代码中的FREExtension的createContext方法  
  13.             extContext = ExtensionContext.createExtensionContext(EXTENSION_ID,"");  
  14.         }  
  15.         public function hello(name:String):String{  
  16.             if(extContext){  
  17.                 return extContext.call(KEY,name) as String;  
  18.             }  
  19.             return "call failed";  
  20.         }  
  21.     }  
  22. }  
package com.linxcool.test
{
    import flash.external.ExtensionContext;
    public class HelloWorldExtension
    {
        public static const KEY:String = "keyA";//与java端中Map里的key一致
        public static const EXTENSION_ID:String = "extTest";//与extension.xml中的id标签一致
        private var extContext:ExtensionContext;
        public function HelloWorldExtension()
        {

            //第二个为参数,会传入java代码中的FREExtension的createContext方法
            extContext = ExtensionContext.createExtensionContext(EXTENSION_ID,"");
        }
        public function hello(name:String):String{
            if(extContext){
                return extContext.call(KEY,name) as String;
            }
            return "call failed";
        }
    }
}

3、在src下新建名为extension.xml的文件

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <extension xmlns="http://ns.adobe.com/air/extension/2.5">  
  3.     <id>extTest</id>  
  4.     <versionNumber>1</versionNumber>  
  5.     <platforms>  
  6.         <platform name="Android-ARM">  
  7.             <applicationDeployment>  
  8.                 <!--即为Android本地导出的jar包名-->  
  9.                 <nativeLibrary>AneTestNative.jar</nativeLibrary>  
  10.                 <!--即为Android本地FREExtension全路径-->  
  11.                 <initializer>com.linxcool.test.SkyExtension</initializer>  
  12.                 <finalizer>com.linxcool.test.SkyExtension</finalizer>  
  13.             </applicationDeployment>  
  14.          </platform>  
  15.     </platforms>  
  16. </extension>  
<?xml version="1.0" encoding="UTF-8"?>
<extension xmlns="http://ns.adobe.com/air/extension/2.5">
	<id>extTest</id>
	<versionNumber>1</versionNumber>
	<platforms>
		<platform name="Android-ARM">
			<applicationDeployment>
			    <!--即为Android本地导出的jar包名-->
			    <nativeLibrary>AneTestNative.jar</nativeLibrary>
			    <!--即为Android本地FREExtension全路径-->
			    <initializer>com.linxcool.test.SkyExtension</initializer>
			    <finalizer>com.linxcool.test.SkyExtension</finalizer>
			</applicationDeployment>
	     </platform>
	</platforms>
</extension>

4、生成ANE文件

 

随便新建一个目录作为工作目录(AneBuild),并为其建立子文件夹Android-ARM
将Flex Library项目中自动生成的.swc文件和extension.xml复制到AneBuild目录下
以ZIP方式解压.swc文件获取catalog.xml和library.swf文件并存到Android-ARM文件夹下
拷贝AneTestNative.jar到Android-ARM文件夹下
拷贝自己的签名文件.p12到AneBuild文件夹下

最终结果
AneBuild:Android-ARM文件夹、.swc文件、extension.xml、.p12文件
Android-ARM:catalog.xml、library.swf、AneTestNative.jar

使用命令提示符进入到AneBuild文件目录下,使用adt命令对上述文件打包

  1. "D:\develop\Adobe\Adobe Flash Builder 4.5\sdks\4.5.0-air3.0\bin\adt" -package -storetype PKCS12 -keystore linxcool.p12 -storepass 08002615 -target ane aneTest.ane extension.xml -swc *.swc -platform Android-ARM -C Android-ARM .  
"D:\develop\Adobe\Adobe Flash Builder 4.5\sdks\4.5.0-air3.0\bin\adt" -package -storetype PKCS12 -keystore linxcool.p12 -storepass 08002615 -target ane aneTest.ane extension.xml -swc *.swc -platform Android-ARM -C Android-ARM .

linxcool.p12:签名文件
08002615:签名密码
aneTest.ane:生成的ANE文件名

 

Flex Mobile项目

1、新建Flex Mobile项目
2、添加本地扩展添加上面所生成的ane包
3、编辑 app-xml文件添加android中所需的权限
4、调用Ane中的函数即可

附加

发现很多人在ANE打包过程中会有很多问题,我补充总结下:

1、若需要返回android端返回的数据

android端调用以下方法返回数据: FREContext.dispatchStatusEventAsync(标识, 内容); 

flash 注册监听返回返回的数据:ExtensionContext.addEventListener(StatusEvent.STATUS,onStatus);

2、生成的APK资源ID无法引用

注意布局文件需要文字国际化。

将android端需要的资源文件拷贝到上诉的Android-ARM文件夹下。

并在android的代码中映射ID关系,在调用界面前调用如下代码:

  1. public static void setResourctID(String rName,FREContext context) throws Exception{  
  2.     Class<?> R = Class.forName(rName);  
  3.     Class<?>[] clss = R.getDeclaredClasses();  
  4.     for (int i = 0; i < clss.length; i++) {  
  5.         Class<?> cls = clss[i];  
  6.         Field[] flds = cls.getDeclaredFields();  
  7.         for (int j = 0; j < flds.length; j++) {  
  8.             Field fld = flds[j];  
  9.             fld.setAccessible(true);  
  10.             Object obj = cls.newInstance();  
  11.             String name = cls.getSimpleName()+"."+fld.getName();  
  12.             int id = context.getResourceId(name);  
  13.             fld.set(obj, id);  
  14.         }  
  15.     }  
  16. }  
public static void setResourctID(String rName,FREContext context) throws Exception{
	Class<?> R = Class.forName(rName);
	Class<?>[] clss = R.getDeclaredClasses();
	for (int i = 0; i < clss.length; i++) {
		Class<?> cls = clss[i];
		Field[] flds = cls.getDeclaredFields();
		for (int j = 0; j < flds.length; j++) {
			Field fld = flds[j];
			fld.setAccessible(true);
			Object obj = cls.newInstance();
			String name = cls.getSimpleName()+"."+fld.getName();
			int id = context.getResourceId(name);
			fld.set(obj, id);
		}
	}
}


其中rName为android生成R.java文件的全类名(如com.linxcool.air.R),打包时请打入。

 

3、assets资源、.so文件 问题

最简单的方式,生成的apk包解压,拷贝assets文件及so文件到APK包的对应目录下,重新打包签名即可。

4、FlashBuilder工程中引用ANE时报错(扩展XML文件无效或不存在

不用理会。

5、打包的时候出现 Invalid swc file The extension NameSpace requires to SWF version to be 13 or lower

在AS库项目中右键属性 -> flex库编译器 ->附加库编译器参数 修改为-locale en_US -swf-version=13

 

其他一些ane打包so库的方法:

http://blog.csdn.net/rogiture/article/details/13986265

http://help.adobe.com/zh_CN/air/extensions/WSf268776665d7970d-2482335412ffea65006-8000.html

你可能感兴趣的:(ANE)