IOS ANE的坑爹之路(一)

最近由于项目需要,用到了些ANE(Air Native Extension)的东西,让Flash可以在iOS调用一些东西,实在太坑爹了,让我忍不住拿出来分享一下 (天呀,我同时再弄js、php、c++、objective-c、flash的东西,崩溃呀)。

ANE,顾名思义,也就是Flash Air的本地扩展。Air虽然可以实现跨平台,但是当需要调用一些平台特性的时候,必然还是会遇到瓶颈的,例如在iOS上无法直接调用音频、图像、支付等接口,这时候就需要ANE出场了。iOS平台的ANE可以用c/c++/oc开发,向Air端提供相应的接口。

现在很多iOS本身的特性都有官方的ANE支持了,但是很多时候开发者还是会需要一些特定的ANE,例如什么摄像、录音、文件处理等,本地接口的效率还是会比Air要高出很多的。本文就以Air调用现在iOS上非常火的微信的API为例,说说ANE的坑爹之路吧。

第一步:定义好ActionScript的接口

首先,打开你的flash builder,创建一个Flex库项目,开始定义你的ActionScript接口吧。我们调用微信API要干嘛呢?当然是发消息给朋友啦,不过发消息前要向微信注册我们的应用ID,因此这里要实现两个接口,代码见下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.rolfzhang.ane
{
   import flash.events.Event;
   import flash.external.ExtensionContext;
 
   public class WeixinApi
   {
     private static var extContext:ExtensionContext = null ;
     public static var isRegistered:Boolean = false ;
 
     public static var WXSceneSession:int = 0;
     public static var WXSceneTimeline:int = 1;
 
     //构造函数
     public function WeixinApi(appIdStr:String){
       initExtension();     
       this .registerApp(appIdStr);
     }
 
     private static function initExtension():void{
       if (!extContext) {
         //这里通过一个自定义的id去获取相应的Extension,
         //必须和objc端的配置文件一致
         extContext = ExtensionContext.createExtensionContext( "com.rolfzhang.ane.Weixin" , null );
       }
     }
 
     private function registerApp(appIdStr:String):Boolean {
       if (extContext && !isRegistered){
         //注册微信API,所有Extension方法都是通过call来调用
         isRegistered = extContext.call( "initWXApi" ,appIdStr);
       }
     }
 
     public function sendTextMessage(msg:String, scene:int):Boolean {
       if (!isRegistered) return false ;
       //发送消息啦,scene为0表示发送给朋友,1发到朋友圈
       return extContext.call( "sendTextMessage" ,msg,scene) as Boolean;
     }
   }
}

这一步不是很复杂,extContext调用的接口也就是objc要实现的方法,先定义接口在开发是比较好的实践。

把这段代码编译好,生成swc文件,后面会用到。

第二步:用objc去调用微信API

这一步网上说的一般都比较复杂,除了写objc,还要解压swc文件,又要用命令行打包神马的,烦死了……咱们还是用些先进点的工具来解决好了。我在Github上找到了一个ANE的XCode模板,把很多东西都做好了,我们只需要老老实实的写objc代码,而不用管那些繁琐的打包工作(安装方法请自行阅读README.md)。

接下来,创建XCode的ANE项目:

红线部分必须和ActionScript接口里面定义的是一样的 ,当然这个也可以在extension.xml配置文件里面修改。

然后我们需要到Air SDK的文件夹里面找一个FlashRuntimeExtensions.h文件,放入我们的项目中,这个是Adobe提供的iOS与Air交互的接口。

创建好的项目中主有以下一些文件:

  • objc代码:Weixin.h、Weixin.m
  • 配置文件:extension.xml、platformoptions.xml
  • 打包脚本:generateANE.sh

Weixin.h中模板帮我们定义好了两个宏,这样写代码的时候会方便很多:

1
2
#define ANE_FUNCTION(f) FREObject (f)(FREContext ctx, void *data, uint32_t argc, FREObject argv[])
#define MAP_FUNCTION(f, data) { (const uint8_t*)(#f), (data), &(f) }

并且已经定义好了4个接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//as端首次调用createExtensionContext时进行初始化
//必须和extension.xml里面配置一致
void WeixinExtInitializer( void ** extDataToSet, FREContextInitializer* ctxInitializerToSet, FREContextFinalizer* ctxFinalizerToSet);
 
//extension被最终释放时调用,做一些clean up的工作
void WeixinExtFinalizer( void * extData);
 
//ExtensionContext初始化,
//接口配置,获取全局context,对象初始化
void ContextInitializer( void * extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet);
 
//context被释放,做一些clean up的工作
void ContextFinalizer(FREContext ctx);
 
//我们要实现的方法
ANE_FUNCTION(initWXApi);
ANE_FUNCTION(sendTextMessage);

我们接下来的工作主要就是写实现各个ANE_FUNCTION,然后在ContextInitializer里面配置上去。在此之前,当然还要把微信的SDK给放进来啦,具体步骤我就不详诉了,请参考微信官方文档。上代码啦:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
void ContextInitializer( void * extData, const uint8_t* ctxType, FREContext ctx,
         uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet)
{
   static FRENamedFunction func[] =
   { //这里配置as能调用的方法
     MAP_FUNCTION(initWXApi, NULL),
     MAP_FUNCTION(sendTextMessage, NULL)
   };
 
   *numFunctionsToTest = sizeof (func) / sizeof (FRENamedFunction);
   *functionsToSet = func;
}
 
ANE_FUNCTION(initWXApi)
{
   //argv是as端传过来的参数,
   //类型是FREObject,需要一些转换才能被调用
   NSString * apiId = getStringFromFREObject(argv[0]);
   //向微信注册AppID
   BOOL success = [WXApi registerApp:appId];
   //返回参数需要是FREObject类型
   return createFREBool(success);
}
 
ANE_FUNCTION(sendTextMessage)
{
   //获取参数
   NSString * msg = getStringFromFREObject(argv[0]);
   int32_t scene;
   FREGetObjectAsInt32(argv[1], &scene);
   //发消息
   SendMessageToWXReq* req = [[[SendMessageToWXReq alloc] init]autorelease];
   req.bText = YES;
   req.text = msg;
   req.scene = scene;
   BOOL success = [WXApi sendReq:req];
   return createFREBool(success);
}
 
//将FREObject转成NSString
NSString * getStringFromFREObject(FREObject obj)
{
   uint32_t length;
   const uint8_t *value;
   FREGetObjectAsUTF8(obj, &length, &value);
   return [NSString stringWithUTF8String:( const char *)value];
}
//将BOOL转成FREObject
FREObject createFREBool( BOOL value)
{
   FREObject fo;
   FRENewObjectFromBool(value, &fo);
   return fo;
}

OK,写好代码只好当然是编译,然后ANE打包啦。什么,你要用终端写命令行?有了XCode的模板就不用这么麻烦了,选择Weixin.ane那个target,Command+B~ 一个微信的ANE就被build出来了。

第三步:调用ANE

这里就只是简单的测试ANE啦,不过比较纠结的是,目前无法在桌面端的模拟器里面进行测试,必须要打包成ipa传到iOS设备中运行。目前Flash Builder无法像XCode那样断点调试,而且代码分布在三个地方(as接口/objc/项目代码),真是错在哪都不知道,写错个字母也够你找几个小时了,很多的时间都浪费在些小问题上了。据说flash builder 4.7会支持联机调试,那样应该就会好很多。

ANE的调用很简单啦,创建一个Flex手机项目,选择iOS平台,然后在“项目属性>构建路径>本机扩展”里面添加ANE文件(XCode生成的ANE,XCode里面 右键>show in Finder 就找到了)。最后,还要检查下“构建打包”里面,这个ANE后面有没打上勾,没打上就勾上去。然后就import那个as库,调用相应的代码就行了。

iOS应用打包还需要提供证书和配置文件,怎么取得这个就自行研究吧。

 

以上的代码只是示例而已,源码不便提供,有什么问题请留言。接下来还会写一下ANE的应用回调、事件处理及一些经验和注意事项,敬请期待。

 

========

老实说这种混合体还是挺恶心的,Air基本只能做界面和交互功能,感觉还没有js+phonegap强大……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值