IOS 之Google Analytics SDK预研--项目代码值入

通过前面的两篇文章,我想大家入门应该是没什么问题的,下面将如实地讲解植入到代码中的方法与捷径。


从所周知,通常我们一个ViewController都是继承自UIViewController。这个相信大家都很清楚。便GA的SDK在跟踪页面的时候要求所有VIEWCONTROLLER继承于GAITrackedViewController,其实它与是继承自UIViewContoller。

好现在第一个问题摆在面前的是,我的项目起码有100多个ViewController,每一个都修改为继承GAITrackedViewController,这是一个量的问题。 

如果这个时候你就动手改了的话,哪后面的工作就有得你改了。

eg:

@interface goodsViewController : UIViewController
{
...
}
@end
修改后为:
@interface goodsViewController : GAITrackedViewContoller
{
...
}
@end

好,为了以后更好扩展,不建议各个ViewController直接继承GAITrackedViewController,此时我们同样可以由GAITrackedViewController 来派生一个子基类,然后在子基类中引入"GAITrackedViewController.h"即可,然后我们所有的ViewContoller继承些基类就省事多了。往后有些什么需要改动的全部的地方,想想是否可以使用基类来完成。

修改后如下:

#import "GAITrackedViewContoller.h"
@interface BaseViewController: GAITrackedViewContoller
{
...
}
@end

具体的ViewController

#import "BaseViewController.h"

@interface goodsViewController : BaseViewController
{
...
}
@end

好,按照上面把你的所有ViewController继承到了自己的基类,如果都改好后,哪么你的第一步植入GA SDK算完成了一半吧。


下面进行GA的SDK初始化,在官网中初始化动作,常常放在appdelegate中的

didFinishLaunchingWithOptions
方法中来实进行。如:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // Optional: automatically send uncaught exceptions to Google Analytics.
  [GAI sharedInstance].trackUncaughtExceptions = YES;
  // Optional: set Google Analytics dispatch interval to e.g. 20 seconds.
  [GAI sharedInstance].dispatchInterval = 20;
  // Optional: set debug to YES for extra debugging information.
  [GAI sharedInstance].debug = YES;
  // Create tracker instance.
  id<GAITracker> tracker = [[GAI sharedInstance] trackerWithTrackingId:@"UA-YOUR-TRACKING-ID"];

}
OK,有了这个初始化之后,就可以进行页面跟踪了。就这么简单,没什么含量嘛。呵呵,还没有的,如果你认为这样就OK,哪就大错特错了,因为GA还有一个跟踪对象,这个对象在每个ViewController中是不会被初始化的,因此必段在viewDidLoad中进行添加一句self.tracker = [[GAI shareInstance] defaultTracker];这句是必要的,但不一定放在这里初始化,不过放在这里是常常的动作。哪么这里又来问题了,前面刚修改完100多个ViewController的继承关系,这里又要在每个Controller中进行赋值,因此,是否可以在构造或父类中进行初始化呢,答安是可以的,但这里就要权衡一下选哪种方式了,如果你的代码都已写好了,并且在某些地方也做了调用,这里如果改为构造方式进行,哪就可审查代码,这也是耗时的工作,在这里建议大家使用在父类创建的构造中进行初始化。


为满足已有项目中改动最小的原则,于是我把GA SDK 的配置值单独作为一个单例类。假设为 GASDKSingle  ,然后在基类和应该用程序代理类中引用这个单例。即在appDelegate.m中

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

[单例类 initSDKValueOfConfig]; //在此方法中实现必要的配置数据即可。

....

}


 在基类中 使用这程方法的缺陷是如果使用NIB进行构造的话就不会调用到父类的此方法上。

@implement BaseViewController


- (id)init

{

self = [supper init];

if (self)

{

self.tracker = 单例配置类(GASDKSingle ).tracker; //哈哈,注意到了没有,在这里就配置好了。以后就不用在各个类中赋值了。

}

return self;

}


@end


以上是讲解过程,下面是我的一个具体单例类:

CGAConfig.h

//
//  CGAConfig.h
//  DemoTest
//
//  Created by  on 13-4-23.
//  Copyright (c) 2013年 __fengsh998__. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "GAI.h"
#import "GAITracker.h"

@interface CGAConfig : NSObject

@property (nonatomic,assign) id<GAITracker> tracker;//保存全局只有一个防止retain
@property (nonatomic,assign) NSTimeInterval dispatchInterval;
@property (nonatomic,assign) BOOL isDebug;
@property (nonatomic,assign) double SampleRate;
@property (nonatomic,assign) BOOL OptOut;
@property (nonatomic,assign) BOOL trackUncaughtExceptions;
@property (nonatomic,assign) BOOL Anonymize;
@property (nonatomic,assign) BOOL UseHttps;

+(CGAConfig*)ShareInstrance;
-(void)destroy;

@end

CGAConfig.m

//
//  CGAConfig.m
//  DemoTest
//
//  Created by  on 13-4-23.
//  Copyright (c) 2013年 __fengsh998__. All rights reserved.
//
//          Google Analytics config 
//
//

#import "CGAConfig.h"


static CGAConfig * gacfg = nil;


@implementation CGAConfig
@synthesize tracker = _tracker;
@synthesize dispatchInterval = _dispatchInterval;
@synthesize isDebug = _isDebug;
@synthesize SampleRate = _SampleRate;
@synthesize OptOut = _OptOut;
@synthesize trackUncaughtExceptions = _trackUncaughtExceptions;
@synthesize Anonymize = _Anonymize;
@synthesize UseHttps = _UseHttps;

/*
-(id)init
{
    [NSException raise:@"singlton not call init."
                format:@"Abort, retry, fail?"];
    return nil;
}
*/

-(void)InitDefaulteValue
{
    //add google analytics 
    [GAI sharedInstance].trackUncaughtExceptions = YES;
    //设置每隔多少时间向GA发送一次数据
    [GAI sharedInstance].dispatchInterval = 20;
    //设置打开SDK的调试信息开关
    [GAI sharedInstance].debug = YES;
    
    self.tracker = [[GAI sharedInstance] trackerWithTrackingId:@"UA-40231989-1"];
    //[self.tracker setSampleRate:50.0];//设置采样的速度
    
    //设置是否停止向GA发送数据
    //[[GAI sharedInstance] setOptOut:YES];
    //设置捕获tracker产生的异常,当为FALSE时不捕捉
    if ([GAI sharedInstance].trackUncaughtExceptions) {
        [[GAI sharedInstance]setTrackUncaughtExceptions:YES];
    }
    
    //黑认为false,设置是否Ni名访问GA
    //[self.tracker setAnonymize:YES];
    //设置是否使用https访问GA default = YES
    //[self.tracker setUseHttps:YES];
    //手动跟踪某个view
}

-(void)dealloc
{
    //防止自动释放时忘记nil
    [_tracker close];
    gacfg = nil;
    [super dealloc];
}

-(void)destroy
{
    if (gacfg) {
        [gacfg release];
    }
}


+(id) allocWithZone:(NSZone *)zone
{  
    @synchronized(self)
    {      
        if (!gacfg)
        {  
            gacfg = [super allocWithZone:zone];    
            return gacfg;     
        }
    }  
    return nil;
}
 

+(CGAConfig*)ShareInstrance
{
    @synchronized(self)
    {    
        if (!gacfg)
        {         
            gacfg = [[self alloc] init];
            [gacfg InitDefaulteValue];
        }  
    }
    
    return gacfg;
}

-(void)setDispatchInterval:(NSTimeInterval)dispatchInterval
{
    [GAI sharedInstance].dispatchInterval = dispatchInterval;
}

-(NSTimeInterval)setDispatchInterval
{
    return [GAI sharedInstance].dispatchInterval;
}

-(void)setIsDebug:(BOOL)isDebug
{
    [GAI sharedInstance].debug = isDebug;
}

-(BOOL)getIsDebug
{
    return [GAI sharedInstance].debug;
}

-(void)setSampleRate:(double)SampleRate
{
    [self.tracker setSampleRate:SampleRate];
}

-(double)getSampleRate
{
    return self.tracker.sampleRate;
}

-(void)setOptOut:(BOOL)OptOut
{
    [[GAI sharedInstance] setOptOut:OptOut];
}

-(BOOL)getOptOut
{
    return [GAI sharedInstance].optOut;
}

-(void)setTrackUncaughtExceptions:(BOOL)trackUncaughtExceptions
{
    [[GAI sharedInstance] setTrackUncaughtExceptions:trackUncaughtExceptions];
}

-(BOOL)getTrackUncaughtExceptions
{
    return [GAI sharedInstance].trackUncaughtExceptions;
}

-(void)setAnonymize:(BOOL)Anonymize
{
    [self.tracker setAnonymize:Anonymize];
}

-(BOOL)getAnonymize
{
    return self.tracker.anonymize;
}

-(void)setUseHttps:(BOOL)UseHttps
{
    [self.tracker setUseHttps:UseHttps];
}

-(BOOL)getUseHttps
{
    return self.tracker.useHttps;
}


@end

在此也贴一下我的父类的DEMO实现。

头文件

#import <UIKit/UIKit.h>
#import "GAITrackedViewController.h"

@interface CPrjBaseViewController : GAITrackedViewController

@end

实现文件

#import <UIKit/UIKit.h>
#import "GAITrackedViewController.h"

@interface CPrjBaseViewController : GAITrackedViewController

@end

#import "CPrjBaseViewController.h"
#import "CGAConfig.h"

@implementation CPrjBaseViewController

-(id)init
{
    self = [super init];
    if (self) {
        
        //add code here.
        self.tracker = [CGAConfig ShareInstrance].tracker;
    }
    
    return self;
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
        //add code here.
        self.tracker = [CGAConfig ShareInstrance].tracker;
    }
    return self;
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
    
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
}
*/

/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
    [super viewDidLoad];
}
*/

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    //self.trackedViewName = @"";
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end


以上OK之后,整个项目的植入准备工作已完成,就可以进行相关的跟踪了。


另:附两个研究要点,一监听所有TOUCH事件,进行捕捉,捕捉后统一区分进行发送,这样就减少了每个事件的地方写一次发送事件的代码,当然这个也是具体项目来使用的。拦截代码如下:

- (void)sendEventHooked:(UIEvent *)event {
    
    //在这里做你想做的事情吧
    NSLog(@"截获事件:%@", [event description]);
    
    
    UIView *obj = [[[event allTouches]anyObject] view];
    if ([obj isKindOfClass:[UIButton class]]) 
    {
        NSLog(@"OK ,button %@",[(UIButton *)obj titleLabel].text); //在这里可以做好多事情的。哈哈。
    }
 
    //执行原来的消息传递流程
    
    [self performSelector:@selector(sendEventOriginal:)withObject:event];
    
}


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  
    //拦截事件消息
    Method sendEvent =class_getInstanceMethod([UIWindow class],@selector(sendEvent:));
    Method sendEventMySelf =class_getInstanceMethod([self class], @selector(sendEventHooked:));
    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));

    
    
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        self.viewController = [[[CViewController alloc] initWithNibName:@"CViewController_iPhone" bundle:nil] autorelease];
    } else {
        self.viewController = [[[CViewController alloc] initWithNibName:@"CViewController_iPad" bundle:nil] autorelease];
    }
    
    //ak
   // self.viewController.tracker = self.tracker;
    
    self.Navigater = [[UINavigationController alloc]init];
    [self.Navigater pushViewController:self.viewController animated:NO];
    
    self.window.rootViewController = self.Navigater;//self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}


第二种就是使用全局宏进行配置,利用调试开关控制跟踪输出。



同时整个SDK的授根协议为GNU GPL v2 因此对商用的用户需要特别注意。

最好,完工。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

边缘998

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值