zoukankan      html  css  js  c++  java
  • AIR Native Extension for iOS 接入第三方sdk 如何实现 AppDelegate 生命周期

       

    作者: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文件 将文件里的代码删干净, 复制下面的代码粘贴进去。但下面的代码并不能解决问题,真正要知其所以然还是要坚持看完我最后是怎么解决的。

      1 //
      2 //  HookUtils.m
      3 //  ResearchMethodSwizzl
      4 //
      5 //  Created by 薛旻 on 15/4/27.
      6 //  Copyright (c) 2015年 薛旻. All rights reserved.
      7 //
      8 
      9 #import <Foundation/Foundation.h>
     10 #import <UIKit/UIKit.h>
     11 #import <objc/runtime.h>
     12 
     13 
     14 @interface HookUtils : NSObject
     15 
     16 + (void)hookMehod:(SEL)oldSEL andDef:(SEL)defaultSEL andNew:(SEL)newSEL;
     17 
     18 @end
     19 
     20 @implementation HookUtils
     21 
     22 + (void)hookMehod:(SEL)oldSEL andDef:(SEL)defaultSEL andNew:(SEL)newSEL {
     23     NSLog(@"hookMehod");
     24 
     25     Class oldClass = objc_getClass([@"CTAppDelegate" UTF8String]);
     26 
     27     Class newClass = [HookUtils class];
     28 
     29     //把方法加给原Class
     30     class_addMethod(oldClass, newSEL, class_getMethodImplementation(newClass, newSEL), nil);
     31     class_addMethod(oldClass, oldSEL, class_getMethodImplementation(newClass, defaultSEL),nil);
     32 
     33     Method oldMethod = class_getInstanceMethod(oldClass, oldSEL);
     34     assert(oldMethod);
     35     Method newMethod = class_getInstanceMethod(oldClass, newSEL);
     36     assert(newMethod);
     37     method_exchangeImplementations(oldMethod, newMethod);
     38 
     39 }
     40 
     41 + (void)load {
     42     NSLog(@"load");
     43     [self hookMehod:@selector(application:didFinishLaunchingWithOptions:) andDef:@selector(defaultApplication:didFinishLaunchingWithOptions:) andNew:@selector(hookedApplication:didFinishLaunchingWithOptions:)];
     44 
     45     [self hookMehod:@selector(applicationWillEnterForeground:) andDef:@selector(defaultApplicationWillEnterForeground:) andNew:@selector(hookedApplicationWillEnterForeground:)];
     46 }
     47 
     48 
     49 /*具体要走的代码*/
     50 -(BOOL)hookedApplication:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)dic
     51 {
     52     NSLog(@"applicationDidFinishLaunching");
     53     [self hookedApplication:application didFinishLaunchingWithOptions:dic];
     54     return YES;
     55 }
     56 
     57 - (void)hookedApplicationWillResignActive:(UIApplication *)application {
     58     [self hookedApplicationWillResignActive:application];
     59 }
     60 
     61 - (void)hookedApplicationDidEnterBackground:(UIApplication *)application {
     62     [self hookedApplicationDidEnterBackground:application];
     63 }
     64 
     65 - (void)hookedApplicationWillEnterForeground:(UIApplication *)application {
     66     [self hookedApplicationWillEnterForeground:application];
     67 }
     68 
     69 - (void)hookedApplicationDidBecomeActive:(UIApplication *)application {
     70     [self hookedApplicationDidBecomeActive:application];
     71 }
     72 
     73 - (void)hookedApplicationWillTerminate:(UIApplication *)application {
     74     [self hookedApplicationWillTerminate:application];
     75 }
     76 
     77 /*支付宝对应的方法*/
     78 - (BOOL)hookedApplication:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
     79     [self hookedApplication:application openURL:url sourceApplication:sourceApplication annotation:annotation];
     80     return YES;
     81 }
     82 
     83 
     84 
     85 -(BOOL)hookedApplication:(UIApplication*)application handleOpenURL:(NSURL*)url {
     86     [self hookedApplication:application handleOpenURL:url];
     87     return YES;
     88 }
     89 
     90 
     91 #pragma 默认
     92 /*default 默认不需要改动*/
     93 - (BOOL)defaultApplication:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)dic { return YES;
     94 }
     95 
     96 - (void)defaultApplicationWillResignActive:(UIApplication *)application {}
     97 
     98 - (void)defaultApplicationDidEnterBackground:(UIApplication *)application {}
     99 
    100 - (void)defaultApplicationWillEnterForeground:(UIApplication *)application {}
    101 
    102 - (void)defaultApplicationDidBecomeActive:(UIApplication *)application {}
    103 
    104 - (void)defaultApplicationWillTerminate:(UIApplication *)application {}
    105 
    106 - (BOOL)defaultApplication:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
    107     return YES;
    108 }
    109 
    110 - (BOOL)defaultApplication:(UIApplication *)application handleOpenURL:(NSURL *)url {
    111     return YES;
    112 }
    113 @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里面打印  

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

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

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

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

  • 相关阅读:
    极客时间课程《数据结构与算法之美》笔记09
    Java 学习笔记02
    极客时间课程《数据结构与算法之美》笔记05
    极客时间课程《数据结构与算法之美》笔记04
    极客时间课程《数据结构与算法之美》笔记03
    极客时间课程《数据结构与算法之美》笔记02
    极客时间课程《数据结构与算法之美》01
    spring data jpa 通过对象传参
    生成流水号
    Java 为实体类动态添加属性
  • 原文地址:https://www.cnblogs.com/lonkiss/p/6492385.html
Copyright © 2011-2022 走看看