IOS ANE的坑爹之路(二)

上回说到了坑爹的微信ANE,这回继续~

上文解决的问题是比较简单的,只是从我们的app中发消息到微信中,跑通了整个ANE的流程。但是实际应用中还会遇到如下的一些问题:

  1. 发送完消息后,能够回到应用中
  2. 接收回调完成的消息,进行处理
  3. objc端与air端事件传递、消息同步
  4. objc端调试不方便
  5. 使用原生控件

下面就一一的解决一下吧~

1、通过URL调用应用

原生的iOS应用要解决这个问题很简单,在Xcode中,选择你的工程设置项,选中“TARGETS”一栏,在“info”标签栏的“URL type“添加“URL scheme”即可。

实际上,Xcode是在info.plist里面添加了一段XML:

1
2
3
4
5
6
7
8
9
10
11
< key >CFBundleURLTypes</ key >
< array >
   < dict >
     < key >CFBundleURLName</ key >
     < string >weixin</ string >
     < key >CFBundleURLSchemes</ key >
     < array >
       < string >wxappid</ string >
     </ array >
   </ dict >
</ array >

上面的示例注册了一个名为wxappid的 URI 方案,从而允许应用程序由wxappid://形式的 URL 进行调用。

而air的程序是用flash builder创建的,打包后的info.plist由flash builder生成。在项目中的app.xml里面有个<iphone>的标签,可在此配置info.plist的内容,因此只需将上面的xml复制到app.xml的<iphone>标签中即可。

更多的配置选项可以参考这里~

通过自定义 URI 调用应用程序时,air的NativeApplication 对象会调一个 invoke 事件,链接的 URL(包括查询参数)放在 InvokeEvent 对象的 arguments 数组中,我们可以在applicationCompleteHandler如下调用:

1
2
3
4
5
6
7
NativeApplication.nativeApplication
     .addEventListener(InvokeEvent.INVOKE,
         function invokeHandler(event:InvokeEvent):void{
             if (event.arguments.length>0){
                 doSomething(event.arguments[0]);
             }
         });

2、处理微信的URL回调

微信的URL回调有两种:在微信中向应用请求消息、在应用发消息给微信后返回应用。

原生应用要触发这两个回调是在 application:openURL:sourceApplication:annotation: 方法中中调用WXApi handleOpenURL:delegate:,触发delegate的onReq或onResp方法。
然而air开发的应用无法调用此方法,因此可以利用上面的invoke事件通过ANE进行调用。

3、Objc与Air进行事件同步

delegate的onReq或onResp被触发后,往往是要让应用进行某些处理,因此还需要objc和air端进行消息同步,可调用air提供了的C语言接口FREDispatchStatusEventAsync进行处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//收到一个来自微信的请求,处理完后调用sendResp
-( void ) onReq:(BaseReq*)req {
   NSString * code = @ "onReq" ;
   NSString * level = @ "someReqData" ;
 
   FREDispatchStatusEventAsync(g_ctx,
         (constuint8_t *)[code UTF8String],
         (constuint8_t *)[level UTF8String]);
}
 
//发送一个sendReq后,收到微信的回应
-( void ) onResp:(BaseResp*)resp {
   NSString * code = @ "onResp" ;
   NSString * level = @ "someRespData" ;
 
   FREDispatchStatusEventAsync(g_ctx,
         (constuint8_t *)[code UTF8String],
         (constuint8_t *)[level UTF8String]);
}

上面两个方法是向air端发出事件,因此air端需要对事件进行监听,我们需要对之前的actionScript接口进行修改:

创建一个Weixin事件对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class WeixinApiEvent extends Event {
   public static const onReq:String = "onWXReq" ;
   public static const onResp:String = "onQXResp" ;
 
   public var data:String = null ;
 
   public function WeixinApiEvent(type:String,
                 data:String,
                 bubbles:Boolean= false ,
                 cancelable:Boolean= false ) {
     super (type, bubbles, cancelable);
     this .data = data;
   }
}

继承EventDispatcher,并监听StatusEvent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import flash.events.EventDispatcher;
import flash.events.StatusEvent;
 
public class WeixinApi extends EventDispatcher {
   ...
   public function WeixinApi(appIdStr:String) {
     super ();
     this .registerApp(appIdStr);
     if (isRegistered){
       //监听StatusEvent
       extContext.addEventListener(StatusEvent.STATUS,onStatus);
     }
   }
   ...
   public function onStatus(e:StatusEvent):void {
     //将事件封装并转发给应用
     dispatchEvent( new WeixinApiEvent(e.code,e.level));
   }
}

重新打包ANE后,即可在应用中对微信的回调事件进行监听了,如:

1
2
3
4
5
6
7
function applicationCompleteHandler(event:FlexEvent):void {
   ...
   wxApi = new WeixinApi( "weixinApi" );
   wxApi.addEventListener(WeixinApiEvent.onReq,dosomething);
   wxApi.addEventListener(WeixinApiEvent.onResp,dosomething);
   ...
}

4、原生控件调用及辅助调试

ANE的调试一直是很纠结的,代码分布在3个地方,并且air端不支持alert,安装到iOS设备上也看不到trace信息,出错了也不知错在哪,纠结~~~~ air端可以通过try/catch捕获错误信息,将debug信息输出到一个textField里面,但对于objc端就无能为力了。

好在可以通过ANE调用objc的原生控件,这样就可以将objc端的调试信息展示出来了。AIR应用是在一个标准的window对象里运行的,你可以通过下面的方法获得这个window对象:

1
[UIApplication sharedApplication].keyWindow

得到window对象后你可以给它添加subviews来显示原生的view对象。

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
UILabel* nativeLogLabel;
NSString * logInfo = @ "-- start loging --" ;
 
//air无法alert,那就直接调用原生的alert吧~
void nativeAlert(NSString * title, NSString * message) {
UIAlertView *alert = [[UIAlertViewalloc] initWithTitle:title
   message:message
   delegate:nil
   cancelButtonTitle:@ "OK"
   otherButtonTitles:nil, nil];
   [alert show];
   [alert release];
}
//在界面中显示logArea
void showLogArea( float x, float y, float width, float height) {
   if (!nativeLogLabel){
     nativeLogLabel = [[UILabelalloc] initWithFrame:CGRectMake(x, y, width, height)];
     nativeLogLabel.font = [UIFontsystemFontOfSize:11];
     nativeLogLabel.lineBreakMode = UILineBreakModeWordWrap;
     nativeLogLabel.numberOfLines = 0;
   }
   nativeLogLabel.frame = CGRectMake(x, y, width, height);
   nativeLogLabel.text = logInfo;
   [[[UIApplicationsharedApplication] keyWindow] addSubview:nativeLogLabel];
}
//添加log信息
void addLogContent(NSString * log ){
   logInfo = [NSStringstringWithFormat:@ "%@\n%@" , log ,logInfo];
   if (nativeLogLabel){
     nativeLogLabel.text = logInfo;
   }
}

通过定义ANE_FUNCTION的方式将这三个方法暴露出去后,即可在air和objc端调用统一的调试信息输出接口,找bug总算容易多了~

5、其他经验

个人总结的一些经验:

  • ANE的相关资料比较少,最好的办法就是多看Adobe提供的文档~ ;
  • 使用(一)中提到的xcode模板,它帮你写好了各种方法定义、宏、配置、批处理文件,不然你的开发会成倍的复杂;
  • 将FlashRuntimeExtensions.h中常用的方法进行封装,诸如从FREObject里面获取数据等;
  • 用一个objc对象封装所有的业务逻辑,而不是将所有逻辑都写在ANE_FUNCTION里面;

比较常见的错误:

  • air端try/catch捕获异常 argument error #3500 -- objc忘了将方法添加到functionsToSet 中;
  • 调用ANE方法直接闪退 -- objc中有错误的内存引用,好好研究下什么retain、release的吧;
  • 发布AIR应用的时候,指明需要引用的iOS SDK地址,不然有些时候会出错。在Flash Builder里,在“构建打包>本机扩展”面板中可以进行设置;

另外推荐一篇文章:《20条开发AIR Native Extension的建议

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值