作者:Panda Fang

出处:http://www.cnblogs.com/lonkiss/p/6492385.html

原创文章,转载请注明作者和出处,未经允许不可用于商业营利活动

去年到今年做了几个 iOS上的 AIR Native Extension (简称 ANE), 痛苦不堪。  ANE 的开发方式早已被前辈吐槽多多 效率低下 浪费生命 严重压低kpi 。体验过Unity的插件开发, 相比之下真的是爽快多了,效率飙升。

言归正传, 痛苦之一就是难以实现AppDelegate 生命周期。关于生命周期实现,其实Android上的 ane 也难搞。下次再写。如果在 xcode上做一个标准的 iOS App 写 AppDelegate 很方便, 填函数就行了。 但是在ANE上 没有暴露这些api给你实现。air 本身是运行在ios上的app ,adobe 实现它的时候自己使用了 delegate 但是却不暴露给我们使用。 我们使用adobe air sdk做依赖adobe 的框架, 束手束脚, 真的忍不住一边做一边骂adobe 。既然adobe air用了 那么我们就能靠hook了, 下面这篇文章非常值得看

打通Android、IOS、ANE制作流程 - 知其然知其所以然 - 博客频道 - CSDN.NET

接着我将引用这篇文章进行讲解

在xcode 中 新建一个 objective-c 文件 取名为 HookUtil  , xocde 将生成一个HookUtil.m文件 将文件里的代码删干净, 复制下面的代码粘贴进去。但下面的代码并不能解决问题,真正要知其所以然还是要坚持看完我最后是怎么解决的。

 //
// HookUtils.m
// ResearchMethodSwizzl
//
// Created by 薛旻 on 15/4/27.
// Copyright (c) 2015年 薛旻. All rights reserved.
// #import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <objc/runtime.h> @interface HookUtils : NSObject + (void)hookMehod:(SEL)oldSEL andDef:(SEL)defaultSEL andNew:(SEL)newSEL; @end @implementation HookUtils + (void)hookMehod:(SEL)oldSEL andDef:(SEL)defaultSEL andNew:(SEL)newSEL {
NSLog(@"hookMehod"); Class oldClass = objc_getClass([@"CTAppDelegate" UTF8String]); Class newClass = [HookUtils class]; //把方法加给原Class
class_addMethod(oldClass, newSEL, class_getMethodImplementation(newClass, newSEL), nil);
class_addMethod(oldClass, oldSEL, class_getMethodImplementation(newClass, defaultSEL),nil); Method oldMethod = class_getInstanceMethod(oldClass, oldSEL);
assert(oldMethod);
Method newMethod = class_getInstanceMethod(oldClass, newSEL);
assert(newMethod);
method_exchangeImplementations(oldMethod, newMethod); } + (void)load {
NSLog(@"load");
[self hookMehod:@selector(application:didFinishLaunchingWithOptions:) andDef:@selector(defaultApplication:didFinishLaunchingWithOptions:) andNew:@selector(hookedApplication:didFinishLaunchingWithOptions:)]; [self hookMehod:@selector(applicationWillEnterForeground:) andDef:@selector(defaultApplicationWillEnterForeground:) andNew:@selector(hookedApplicationWillEnterForeground:)];
} /*具体要走的代码*/
-(BOOL)hookedApplication:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)dic
{
NSLog(@"applicationDidFinishLaunching");
[self hookedApplication:application didFinishLaunchingWithOptions:dic];
return YES;
} - (void)hookedApplicationWillResignActive:(UIApplication *)application {
[self hookedApplicationWillResignActive:application];
} - (void)hookedApplicationDidEnterBackground:(UIApplication *)application {
[self hookedApplicationDidEnterBackground:application];
} - (void)hookedApplicationWillEnterForeground:(UIApplication *)application {
[self hookedApplicationWillEnterForeground:application];
} - (void)hookedApplicationDidBecomeActive:(UIApplication *)application {
[self hookedApplicationDidBecomeActive:application];
} - (void)hookedApplicationWillTerminate:(UIApplication *)application {
[self hookedApplicationWillTerminate:application];
} /*支付宝对应的方法*/
- (BOOL)hookedApplication:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
[self hookedApplication:application openURL:url sourceApplication:sourceApplication annotation:annotation];
return YES;
} -(BOOL)hookedApplication:(UIApplication*)application handleOpenURL:(NSURL*)url {
[self hookedApplication:application handleOpenURL:url];
return YES;
} #pragma 默认
/*default 默认不需要改动*/
- (BOOL)defaultApplication:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)dic { return YES;
} - (void)defaultApplicationWillResignActive:(UIApplication *)application {} - (void)defaultApplicationDidEnterBackground:(UIApplication *)application {} - (void)defaultApplicationWillEnterForeground:(UIApplication *)application {} - (void)defaultApplicationDidBecomeActive:(UIApplication *)application {} - (void)defaultApplicationWillTerminate:(UIApplication *)application {} - (BOOL)defaultApplication:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return YES;
} - (BOOL)defaultApplication:(UIApplication *)application handleOpenURL:(NSURL *)url {
return YES;
}
@end

关于这个HookUtils做几点说明: 
① HookUtils是IOS的Hook机制的实现,所以适用于所有IOS的开发,这里只是针对Air应用做了一些处理。 
① Hook机制中需要获取应用的实现了生命周期的类名,这样才能Hook处理,如果你是Xcode工程开发的代码那你会很方便的找到这个类名,这适用于IOS原生,Unity以及Cocos引擎,因为它们都会使用Xcode开发工具。但是,Air开发是在Flash Builder上,并不直接涉及到Xcode工程,通过代码打印Air应用的生命周期类,找到了Air的类名CTAppDelegate,于是代码中设置为,其他引擎自行修改,当然,你也可以通过配置文件(Info.plist)获取,这样代码就不需要修改了

 Class oldClass = objc_getClass([@"CTAppDelegate" UTF8String]);

③ 你需要在hooked**方法中实现你的具体代码,最后在+ (void)load()方法中调用头文件定义的方法(void)hookMehod:(SEL)oldSEL andDef:(SEL)defaultSEL andNew:(SEL)newSEL;来达到Hook的目的

上面是引用那篇博客的,我加好代码后就疑问了, 那哪里来调用它呢。 问了有经验的iOS开发者才明白 其实并不用在别的函数里面来调用这个HookUtil里的函数, 这个类方法 load就是入口, 只要声明为类方法并起名load会被系统自动调用。 制作好ane 后在demo中测试,原本可以跑起来的demo自从加了HookUtil反而启动就闪退了,通过观察log发现 hookMethod执行了,果然是系统自动调用这些代码, ane 还没在demo中通过按钮触发实例化呢

于是增加log 最后定位到在34行  assert(oldMethod);  这行挂掉,原来 oldMethod是null ,但是看半天没看出来哪里错了, 后来怀疑25行  oldClass   会不会也是null 呢, 于是加了日志  NSLog(@"oldclass %@", oldClass);  果然 也是null , 这时候回顾那篇博客,也许不是CTAppDelegate 这个名字呢? 那篇博客说通过代码打印Air应用的生命周期类,找到了Air的类名CTAppDelegate。 于是在 hookMethod里面打印

    id delegate = [UIApplication sharedApplication].delegate;
NSLog(@"delegate %@", delegate);

然而还是null ,然后又想啊, 会不会是时机太早啊。 于是放在了 ane的一个api方法里面在 应用层demo中通过按钮触发,

 FREObject initSDK(FREContext ctx, void *data, uint32_t argc, FREObject argv[])
{
id delegate = [UIApplication sharedApplication].delegate;
NSLog(@"------------delegate %@", delegate);
}

果然不再是null 了, 打印出来的名字也不是CTAppDelegate,而是 CTAppController 我的 airsdk 是21 ,adobe adobe 又改名字了。  把25行代码中的CTAppDelegate 改成 CTAppController 之后测试, delegate中的函数得到正确调用, 实现生命周期delegate就此解决

AIR Native Extension for iOS 接入第三方sdk 如何实现 AppDelegate 生命周期的更多相关文章

  1. iOS系列 基础篇 03 探究应用生命周期

    iOS系列 基础篇 03 探究应用生命周期 目录: 1. 非运行状态 - 应用启动场景 2. 点击Home键 - 应用退出场景 3. 挂起重新运行场景 4. 内存清除 - 应用终止场景 5. 结尾 本 ...

  2. iOS系列 基础篇 04 探究视图生命周期

    iOS系列 基础篇 04 探究视图生命周期 视图是应用的一个重要的组成部份,功能的实现与其息息相关,而视图控制器控制着视图,其重要性在整个应用中不言而喻. 以视图的四种状态为基础,我们来系统了解一下视 ...

  3. QF——iOS程序运行原理(APP的生命周期)

    iOS程序的运行原理: main.m: 1. main.m 主函数是所有程序的入口函数. 2. 在main函数里是UIApplicationMain函数,开启了一个无限循环,以监听该应用. 该UIAp ...

  4. iOS程序执行顺序和UIViewController 的生命周期(整理)

    说明:此文是自己的总结笔记,主要参考: iOS程序的启动执行顺序 AppDelegate 及 UIViewController 的生命周期 UIView的生命周期 言叶之庭.jpeg 一. iOS程序 ...

  5. Xamarin.ios引用第三方SDK

    引言 诚然,Xamarin是个优秀的跨平台解决方案,但毕竟还是不能将Native中所有的方法都直接实现.诸如各种第三方库,也都只有java/oc原生版本的SDK,无法直接拿过来直接使用.但,不能直接拿 ...

  6. IOS第12天(3,UIViewController的生命周期)

    #import "HMViewController.h" @interface HMViewController () @property(nonatomic,strong)NSA ...

  7. iOS viewController 和 view 的创建消失生命周期总结

    控制器创建的生命周期 1. 如果从stroryBoard 中产生一个controller,那么会先调用initWithCoder:, awakeFromNib, loadView,viewDidLoa ...

  8. ios --也是在B页面的生命周期设置如下代码。方法一是直接关闭和激活侧滑手势,方法二则是B遵循协议UIGestureRecognizerDelegate,设置侧滑交互代理,重写手势方法。

    @property (weak, nonatomic) id<UIGestureRecognizerDelegate> restoreInteractivePopGestureDelega ...

  9. IOS storyboard(控件器的 生命周期)

    @interface NJTwoViewController () @end @implementation NJTwoViewController // 当控制器的view加载完毕就调用 - (vo ...

随机推荐

  1. freemarker ! 用法

    ${(user.name)!""} 请注意,是打了()的 也就是它会先判断user是不是为null 在判断user.name 是不是为null

  2. 1.Ioc&DI和Spring

    1.面向对象回顾和案例 面向对象程序设计:1 2 3 4 案例分析: 需求分析: 报表功能:     报表服务类,检索数据,并生成图标     报表生成器类,生成不同格式的报表文件,例如PDF格式.H ...

  3. ubuntu同时装有MXNet和Caffe框架

    我阐述一下我遇到的问题:因为之前装过caffe,最近装了MXNet.MXNet可以运行,但import caffe就不行了,找不到模块. 那应该怎么处理呢??? 参考了一下这个网站:https://i ...

  4. Nohup后台运行程序

    场景:我现在需要跑脚本批量处理一些数据,但是我又不想盯着控制台看这个脚本的输出结果,想把这些输出结果记录到一个日志文件里面 方案:可以使用 Linux 的 nohup 命令,把进程挂起,后台执行 用法 ...

  5. 学习ssm

    1.安装配置maven (1)在http://maven.apache.org/download.cgi下载apach-maven-3.5.4-bin.zip (2)将apach-maven-3.5. ...

  6. VMware Workstation 12.5.9 Pro虚拟机软件中文版

    更新为 VMware Workstation 12.5.9 pro版.VMware虚拟机软件无疑是windows系统下最强大好用的虚拟机软件.最新的VMware Workstation 12 Pro ...

  7. $('#').formValidation校验网址

    $('#addCarouselInfoForm').formValidation({ message: '格式不正确', //不忽略隐藏域验证 excluded: [], icon: { valid: ...

  8. Linux下Tomcat启动关闭命令

    1.首先,进入Tomcat下的bin目录 cd /usr/local/tomcat/bin 2.查看Tomcat是否以关闭 ps -ef|grep tomcat 如果显示以下信息,说明Tomcat还没 ...

  9. Mybatis学习笔记5 - 参数处理

    1.单个参数:mybatis不会做特殊处理,#{参数名}:取出参数值. 2.多个参数:mybatis会做特殊处理. 多个参数会被封装成 一个map, key:param1...paramN,或者参数的 ...

  10. 多线程编程_控制并发线程数的Semaphore

    简介 Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源.很多年以来,我都觉得从字面上很难理解Semaphore所表达的含义,只能把它比作是 ...