你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS開辟中完成hook新聞機制的辦法探討

iOS開辟中完成hook新聞機制的辦法探討

編輯:IOS開發綜合

Method Swizzling 道理

在Objective-C中挪用一個辦法,實際上是向一個對象發送新聞,查找新聞的獨一根據是selector的名字。應用Objective-C的靜態特征,可以完成在運轉時掉包selector對應的辦法完成,到達給辦法掛鉤的目標。
每一個類都有一個辦法列表,寄存著selector的名字和辦法完成的映照關系。IMP有點相似函數指針,指向詳細的Method完成。

我們可以應用 method_exchangeImplementations 來交流2個辦法中的IMP,
我們可以應用 class_replaceMethod 來修正類,
我們可以應用 method_setImplementation 來直接設置某個辦法的IMP,
……
歸根結柢,都是掉包了selector的IMP,以下圖所示:

Method Swizzling 理論


舉個例子好了,我想鉤一下NSArray的lastObject 辦法,只需兩個步調。
第一步:給NSArray加一個我本身的lastObject


#import "NSArray+Swizzle.h" 
 
 
@implementation NSArray (Swizzle) 
 
 
- (id)myLastObject 

    id ret = [self myLastObject]; 
    NSLog(@"**********  myLastObject *********** "); 
    return ret; 

@end 

乍一看,這不遞歸了麼?別忘卻這是我們預備更換IMP的selector,[self myLastObject] 將會履行真的 [self lastObject] 。

第二步:更換IMP


#import  
#import "NSArray+Swizzle.h" 
 
 
int main(int argc, char *argv[]) 

    @autoreleasepool { 
         
        Method ori_Method =  class_getInstanceMethod([NSArray class], @selector(lastObject)); 
        Method my_Method = class_getInstanceMethod([NSArray class], @selector(myLastObject)); 
        method_exchangeImplementations(ori_Method, my_Method); 
         
        NSArray *array = @[@"0",@"1",@"2",@"3"]; 
        NSString *string = [array lastObject]; 
        NSLog(@"TEST RESULT : %@",string);  
          
        return 0; 
    } 


掌握台輸入Log:
2013-07-18 16:26:12.585 Hook[1740:c07] **********  myLastObject ***********  
2013-07-18 16:26:12.589 Hook[1740:c07] TEST RESULT : 3 


成果很讓人欣喜,是否是不由得想給UIWebView的loadRequest: 加 TODO 了呢?

示例

有了這個道理,接上去讓我們來看一個實例:
上面先直接上源碼:
 


//
//  TestHookObject.m
//  TestHookMessage
//
//  Created by mapleCao on 13-2-28.
//  Copyright (c) 2013年 mapleCao. All rights reserved.
//

#import "TestHookObject.h"
#import <objc/objc.h>
#import <objc/runtime.h>

@implementation TestHookObject

// this method will just excute once
+ (void)initialize
{
    // 獲得到UIWindow中sendEvent對應的method
    Method sendEvent = class_getInstanceMethod([UIWindow class], @selector(sendEvent:));
    Method sendEventMySelf = class_getInstanceMethod([self class], @selector(sendEventHooked:));
   
    // 將目的函數的原完成綁定到sendEventOriginalImplemention辦法上
    IMP sendEventImp = method_getImplementation(sendEvent);
    class_addMethod([UIWindow class], @selector(sendEventOriginal:), sendEventImp, method_getTypeEncoding(sendEvent));
   
    // 然後用我們本身的函數的完成,調換目的函數對應的完成
    IMP sendEventMySelfImp = method_getImplementation(sendEventMySelf);
    class_replaceMethod([UIWindow class], @selector(sendEvent:), sendEventMySelfImp, method_getTypeEncoding(sendEvent));
}

/*
 * 截獲到window的sendEvent
 * 我們可以先處置完今後,再持續挪用正常處置流程
 */
- (void)sendEventHooked:(UIEvent *)event
{
    // do something what ever you want
    NSLog(@"haha, this is my self sendEventMethod!!!!!!!");
   
    // invoke original implemention
    [self performSelector:@selector(sendEventOriginal:) withObject:event];
}

@end


  上面我們來逐行剖析一下下面的代碼:
 
  起首我們來看19行,這一行重要目標是獲得到UIWindow原生的sendEvent的Method(一個構造體,用來對辦法停止描寫),接著第20行是獲得到我們本身界說的類中的sendEvent的Method(這兩個辦法的簽名必需一樣,不然運轉時報錯)。第23行我們經由過程UIWindow原生的sendEvent的Method獲得到對應的IMP(一個函數指針),第24行應用運轉時API Class_addMethod給UIWindow類添加了一個叫sendEventOriginal的辦法,該辦法應用UIWindow原生的sendEvent的完成,而且有著雷同的辦法簽名(必需雷同,不然運轉時報錯)。27行是獲得我們自界說類中的sendEventMySelf的IMP,28行是症結的一行,這一行的重要目標是為UIWindow原生的sendEvent指定一個新的完成,我們看到我們將該完成指定到了我們本身界說的sendEventMySelf上。到了這兒我們就完成了移花接木,年夜功樂成。
 
  履行下面這些行今後,我們就勝利的將UIWindow的sendEvent重定向到了我們本身的寫的sendEventMySelf的完成,然後將其本來的完成重定向到了我們給它新添加的辦法sendEventOriginal中。而sendEventMySelf中,我們起首可以對這個新聞停止我們想要的處置,然後再經由過程41行挪用sendEventOriginal辦法轉到正常的履行流程。
 
  這塊兒你能夠有個迷惑 “我們自界說類中明明是沒有sendEventOriginal辦法的啊?”
 
  為何履行起來不報錯,並且還會正常履行?由於sendEventMySelf是UIWindow的sendEvent重定向過去的,所以在運轉時該辦法中的self代表的就是UIWindow的實例,而不再是TestHookObject的實例了。加上sendEventOriginal是我們經由過程運轉時添加到UIWindow的實例辦法,所以可以正常挪用。固然假如直接經由過程上面這類方法挪用也是可以的,只不外編譯器會提醒正告(編譯器沒那末智能),是以我們采取了performSelector的挪用方法。
 
[self sendEventOriginal:event];
  以上就是Hook的完成,應用時我們只須要讓TestHookObject類履行一次初始話操作便可以了,履行完今後。UIWindow的sendEvent新聞就會會hook到我們的sendEventMySelf中了。
 
  上面是挪用代碼:
 
 
 


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    self.viewController = [[[TestHookViewController alloc] initWithNibName:@"TestHookViewController" bundle:nil] autorelease];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
   
   
    //hook UIWindow‘s SendEvent method
    TestHookObject *hookSendEvent = [[TestHookObject alloc] init];
    [hookSendEvent release];
   
    UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    btn.center = CGPointMake(160, 240);
    btn.backgroundColor = [UIColor redColor];
    [btn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventAllEvents];
    [self.window addSubview:btn];
    [btn release];
   
    return YES;
}

代碼中我們還專門添加了一個button來驗證,hook完今後新聞能否正常傳遞。經歷證新聞流轉完整正常。

【iOS開辟中完成hook新聞機制的辦法探討】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved