preface
- A burial site is a specific process to collect some information in the application, used to track the status of the application to use, as now the Internet is more and more convenient, and accurate analysis of user data into a new trend, user time spent on this page, click on the button, browse the content, the mobile phone models, such as network environment, and so on can be statistics
To do data analysis is nothing more than two kinds, one is the server through the interface call statistics, the other is the front-end buried statistics, of course, the front-end buried statistics can be more accurate statistics of more data information ~
Buried point solutions
It can be divided into three kinds: code burial point, visual burial point and no burial point
The first: code burial point
It is very simple to do a good job of burying point processing in the controller and button events that need to statistic the burying point
The second: visual burial point
Each event is identified according to its identity, and reference points are taken for the specified event. The event identification and parameter information are written in the configuration table, and the buried point statistics can be realized by dynamically delivering the configuration table
Third: no buried point
No buried point means that when the developer integrates the collection SDK, the SDK directly starts to capture and monitor all of the user’s behavior in the application, and reports all of it, without requiring the developer to add additional code
To introduce these three kinds of information, there are a lot of online materials, interested friends can search to see,
Meituan point evaluation front-end non-trace buried practice
Actual processing
Statistics on user browsing pages
The following is a very simple statistics user browse buried point method, in fact, using Runtime exchange viewDidLoad method
+ (void)load{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ kMethodSwizzling(self.class, @selector(viewDidLoad), @selector(kj_viewDidLoad)); }); } - (void)kj_viewDidLoad{ [self kj_viewDidLoad]; NSString *clazz = NSStringFromClass([self class]); NSDictionary *dict = @{ @"userid":KJHookInfo.shared.userid, @"viewController":clazz }; NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key"); //TODO: upload data}Copy the code
Statistics specified pages
As an update, browse through the specified controller buried, and dynamically return the interface controller that you want to count, store it in hookViewControllers, and then count it
- (void)kj_viewDidLoad{ [self kj_viewDidLoad]; NSString *clazz = NSStringFromClass([self class]); BOOL isHook = ({ BOOL isHook = NO; for (NSString *name in KJHookInfo.shared.hookViewControllers) { if ([name isEqualToString:clazz]) { isHook = YES; break; } } isHook; }); if (isHook) { NSDictionary *dict = @{ @"userid":KJHookInfo.shared.userid, @"viewController":clazz }; NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key"); //TODO: upload data}}Copy the code
The user page browsing duration was calculated
So one more thing to do is to look at how long you stay on a page and to deal with a buried point is simply to swap viewWillAppear: and viewDidDisappear:
+ (void)load{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ kMethodSwizzling(self.class, @selector(viewWillAppear:), @selector(kj_viewWillAppear:)); kMethodSwizzling(self.class, @selector(viewDidDisappear:), @selector(kj_viewDidDisappear:)); }); } - (void)kj_viewWillAppear:(BOOL)animated{ [self kj_viewWillAppear: animated]; Kjhookinfo.shared. time = CFAbsoluteTimeGetCurrent(); } - (void)kj_viewDidDisappear:(BOOL)animated{ [self kj_viewDidDisappear: animated]; NSString *clazz = NSStringFromClass([self class]); BOOL isHook = ({ BOOL isHook = NO; for (NSString *name in KJHookInfo.shared.hookViewControllers) { if ([name isEqualToString:clazz]) { isHook = YES; break; } } isHook; }); if (isHook) { NSTimeInterval time = CFAbsoluteTimeGetCurrent() - KJHookInfo.shared.time; NSDictionary *dict = @{ @"userid":KJHookInfo.shared.userid, @"time":time, @"viewController":clazz }; NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key"); //TODO: upload data}}Copy the code
User click Event
Most clickable UI controls are based on UIControl, and the core is an interactive method called sendAction:to:forEvent:, which provides a button that counts to a specific page
@implementation UIControl (KJHook) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ kMethodSwizzling(self.class, @selector(sendAction:to:forEvent:), @selector(kj_sendAction:to:forEvent:)); }); } - (void)kj_sendAction:(SEL)action to:(nullable id)target forEvent:(nullable UIEvent *)event { [self kj_sendAction:action to:target forEvent:event]; _weakself; kGCD_async(^{ if ([NSStringFromClass(weakself.class) isEqualToString:@"UIButton"]) { void (^kDealButton)(NSString *) = ^(NSString *clazz){ NSDictionary *dict = @{ @"userid":@"userid", @"centerX":[NSString stringWithFormat:@"%.2f",weakself.centerX], @"centerY":[NSString stringWithFormat:@"%.2f",weakself.centerY], @"viewController":clazz }; NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key"); NSLog(@"%@",parameter); //TODO: upload data}; kGCD_main(^{ kDealButton(NSStringFromClass([[target viewController] class])); }); }}); } @endCopy the code
Here, if you want to be more accurate, you can also give each button a tag value, of course, this project is relatively large, this is just to provide ideas, how to do the actual situation shall be subject to
It is worth mentioning here that, when exchanging methods, make sure to query globally for name conflicts (whether there are duplicate method names), otherwise it may appear that the method you buried is not executed at all. You can refer to my other article about Category introduction on the use of iOS Category Category and tool encapsulation
Burial point follow-up processing
Uploading Interface Data
Usually, after we bury the point, the method is to call a specified interface of the server, but there is a defect is that the traffic will be very large in the peak time, there is the possibility of exceeding the scope of the server
Image access statistics
Let’s start by introducing the structure of a url link, https://upload-images.jianshu.io/upload_images/1933747-82138031f05852ab.gif? tR8XBkv3BaBjjEeck9VbeiZauP73MdXWlhvmUq+BAFY=
Scheme: HTTPS host: upload-images.jianshu. IO path: /upload_images/1933747-82138031f05852ab.gif Query: tR8XBkv3BaBjjEeck9VbeiZauP73MdXWlhvmUq+BAFY=Copy the code
To access an image, you only need scheme:// + host + path
But the following format consists of scheme:// + host + path +? + query is also accessible
Therefore, we can put the buried point information in the query, and then get the contents of the buried point quickly and simply by counting the access records of the image
- Bandwidth considerations: Images can also be used
1 pixel
So it doesn’t take up much bandwidth on the server - Security considerations: We can also encrypt the required parameters
NSDictionary *dict = @{@"app":@"appname"};
NSString *parameter = dict.jsonString.kj_aesEncryptKey(@"key");
Copy the code
It is also available at https://upload-images.jianshu.io/upload_images/1933747-82138031f05852ab.gif? tR8XBkv3BaBjjEeck9VbeiZauP73MdXWlhvmUq+BAFY=
Subsequent thinking
We all know that the accessed images are data data, so can we also hide the data we want to give back to the client in data and parse it?
So what’s the best way to bury it? Thank you for sharing