IOS App Code-free intrusion Method hook
The study of continuing OBJECTIVE-C runtime
Recent company projects are doing user behavior analysis
So app-side in some pages to switch, interactive operation of the need to send a message to the statistical system
In dozens of controller projects, adding code one by one is completely impossible, and maintenance is also laborious
But what needs to be dealt with here is Controller, which can be implemented in the following ways
1. Using object inheritance in Objective-c
Inheritance is very common in object-oriented development, and there is a Baseviewcontroller in project engineering like we do now,
All new Viewcontroller inherit Baseviewcontroller, which can be called by their subclasses by adding some common methods \ properties to Baseviewcontroller
This is a major way to unify all the view controller styles in our engineering.
2. Using category and runtime to implement method hooks
The hook scheme has the advantage of avoiding code intrusion and achieving wider versatility. By swizzling we can combine the original method with the method that we are adding,
That is, do not need to add code in the original project, but also to achieve global coverage
Comparison of two scenarios:
It is more accurate to inherit from the parent class than to hook because the pages that need to be counted are the controllers that inherit from the parent class, and others like Uinavigationcontroller, The uialertcontroller of the system will not be strayed into the statistic data.
The above mentioned hook scheme is through hook Uiviewcontroller viewdidload/viewdidappear and other methods, and these methods in fact each controller will call, then there will be the wrong controller Also appear here (as mentioned above Uinavigationcontroller and Uialertcontroller). But the hook scheme a better feature is no code intrusion, without modifying the project code to complete the work.
Considering that the behavioral analysis statistic system is likely to be used by other projects in the company, the hook scheme is used here. Then there will inevitably be statistical statistics of the situation, and then analysis.
Since we use the hook scheme, we have to use the runtime swizzling
First, create a new Uiviewcontroller category
Implementing swizzling Code
+ (void) load{
[super load];
Static dispatch_once_t Oncetoken;
Dispatch_once (&oncetoken, ^{
//If you want to open controller statistics, open the following line of code
__gbh_tracer_swizzlemethod ([self class] , @selector (viewdidappear:), @selector (__gbh_tracer_viewdidappear:));}
Well, see here everyone will find that this is called a C method, but how does this C method come true? Look down.
void __gbh_tracer_swizzlemethod (class class, Sel originalselector, sel swizzledselector) {method
Originalmethod = Class_getinstancemethod (class, originalselector);
Method Swizzledmethod = Class_getinstancemethod (class, swizzledselector);
BOOL Didaddmethod =
Class_addmethod (class,
originalselector,
method_getimplementation (Swizzledmethod ),
method_gettypeencoding (Swizzledmethod));
if (didaddmethod) {
Class_replacemethod (class,
swizzledselector,
method_getimplementation ( Originalmethod),
method_gettypeencoding (Originalmethod));
else {
method_exchangeimplementations (Originalmethod, Swizzledmethod);
}
}
This is a standard swizzling writing, of course, GitHub above also have about swizzling Open Source Library, use up also conveniently here don't say more
Look back to the first piece of code, red Viewdidappear is about to be my hook method, __gbh_tracer_viewdidappear is the way I need to implement
-(void) __gbh_tracer_viewdidappear: (BOOL) animated{
[self __gbh_tracer_viewdidappear:animated];//As the method has been exchanged, What is called here is actually Viewdidappear: Method
//Set controller Nsarray that does not allow sending data
*filter = @[@ "Uinavigationcontroller", @ " Uitabbarcontroller "];
NSString *classname = Nsstringfromclass (self.class);
if ([filter containsobject:classname]) return; If the controller is not allowed to send log in the list, then can not continue to go down if
([Self.title iskindofclass:[nsstring class]] && Self.title.length > 0) {//title only meets my requirements//
send log here
}
}
Well, just said that there are some controller I do not send data, there are double judgments, one is added to the blacklist, the other is to determine whether the controller Title property is empty
The above judgment basically can satisfy me this behavior analysis statistic system's demand, if still need what judgment also can continue to add
I just need to add this category to the project, the Viewdidappear will be hook out, can do whatever it wants.
Additional requirements also mention the need to send an INIT message once the application is started
Hook? OK, but I'm more inclined to use category+nsnotification because there are already uiapplicationdidfinishlaunchingnotification in the system
This kind of notice can be used directly
@implementation uiapplication (gbhtracer)
+ (void) load{
[super load];
Static dispatch_once_t Oncetoken;
Dispatch_once (&oncetoken, ^{//Only once can be done
[[Nsnotificationcenter defaultcenter]addobserver:self selector:@ Selector (__gbh_tracer_applicationdidfinishlaunching:) Name:uiapplicationdidfinishlaunchingnotification object: Nil]
;} + (void) __gbh_tracer_applicationdidfinishlaunching: (nsnotification *) noti{
//When the application starts to do whatever it wants!
}
@end
Well.. Our behavioral analysis and statistic system is not in the original project. A header file does not call any one method to achieve statistical results.
But like what the operation response time of the statistics, still need you reader in response to call the appropriate method
Thank you for reading, I hope to help you, thank you for your support for this site!