Skip to content

Commit

Permalink
Release 1.4.1
Browse files Browse the repository at this point in the history
1. Bug fixed for VTrack
  • Loading branch information
Yuhan ZOU committed Apr 27, 2016
1 parent 8ebc7a6 commit 44b6124
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 78 deletions.
2 changes: 1 addition & 1 deletion SensorsAnalyticsSDK/SensorsAnalyticsSDK.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "SensorsAnalyticsSDK"
s.version = "1.4.0"
s.version = "1.4.1"
s.summary = "The offical iOS SDK of Sensors Analytics."
s.homepage = "http://www.sensorsdata.cn"
s.source = { :git => 'https://github.com/sensorsdata/sa-sdk-ios.git', :tag => "v#{s.version}" }
Expand Down
39 changes: 29 additions & 10 deletions SensorsAnalyticsSDK/SensorsAnalyticsSDK/SensorsAnalyticsSDK.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ typedef NS_ENUM(NSInteger, SensorsAnalyticsDebugMode) {
* @discussion
* propertyDict是一个Map。
* 其中的key是Property的名称,必须是<code>NSString</code>
* Valie则是Property的内容,只支持 <code>NSString</code>,<code>NSNumber</code>,<code>NSSet</code>,<code>NSDate</code>这些类型
* value则是Property的内容,只支持 <code>NSString</code>,<code>NSNumber</code>,<code>NSSet</code>,<code>NSDate</code>这些类型
* 特别的,<code>NSSet</code>类型的value中目前只支持其中的元素是<code>NSString</code>
*
* @param event event的名称
Expand Down Expand Up @@ -234,6 +234,34 @@ typedef NS_ENUM(NSInteger, SensorsAnalyticsDebugMode) {

- (void)trackSignUp:(NSString *)newDistinctId;

/**
* @abstract
* 用于在 App 首次启动时追踪渠道来源,并设置追踪渠道事件的属性。SDK会将渠道值填入事件属性 $ios_install_source 中
*
* @discussion
* propertyDict是一个Map。
* 其中的key是Property的名称,必须是<code>NSString</code>
* value则是Property的内容,只支持 <code>NSString</code>,<code>NSNumber</code>,<code>NSSet</code>,<code>NSDate</code>这些类型
* 特别的,<code>NSSet</code>类型的value中目前只支持其中的元素是<code>NSString</code>
*
* 这个接口是一个较为复杂的功能,请在使用前先阅读相关说明: http://www.sensorsdata.cn/manual/ios_sdk.html,并在必要时联系我们的技术支持人员。
*
* @param event event的名称
* @param propertieDict event的属性
*/
- (void)trackInstallation:(NSString *)event withProperties:(NSDictionary *)propertyDict;

/**
* @abstract
* 用于在 App 首次启动时追踪渠道来源,SDK会将渠道值填入事件属性 $ios_install_source 中
*
* @discussion
* 这个接口是一个较为复杂的功能,请在使用前先阅读相关说明: http://www.sensorsdata.cn/manual/ios_sdk.html,并在必要时联系我们的技术支持人员。
*
* @param event event的名称
*/
- (void)trackInstallation:(NSString *)event;

/**
* @abstract
* 用来设置每个事件都带有的一些公共属性
Expand Down Expand Up @@ -377,15 +405,6 @@ typedef NS_ENUM(NSInteger, SensorsAnalyticsDebugMode) {
*/
- (void)setOnce:(NSString *) profile to:(id)content;

/**
* @abstract
* 用于在 App 初始化时,追踪渠道来源
*
* @discussion
* 这个接口是一个较为复杂的功能,请在使用前先阅读相关说明: http://www.sensorsdata.cn/manual/ios_sdk.html,并在必要时联系我们的技术支持人员。
*/
- (void)setInstallSourceAutomatically;

/**
* @abstract
* 删除某个Profile的全部内容
Expand Down
168 changes: 101 additions & 67 deletions SensorsAnalyticsSDK/SensorsAnalyticsSDK/SensorsAnalyticsSDK.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#import "SASwizzler.h"
#import "SensorsAnalyticsSDK.h"

#define VERSION @"1.4.0"
#define VERSION @"1.4.1"

@implementation SensorsAnalyticsDebugException

Expand Down Expand Up @@ -55,6 +55,8 @@ @interface SensorsAnalyticsSDK()
@property (nonatomic, strong) id abtestDesignerConnection;
@property (atomic, strong) NSSet *eventBindings;

@property (assign, nonatomic) BOOL safariRequestInProgress;

// 用于 SafariViewController
@property (strong, nonatomic) UIWindow *secondWindow;

Expand Down Expand Up @@ -203,6 +205,7 @@ - (instancetype)initWithServerURL:(NSString *)serverURL

self.checkForEventBindingsOnActive = YES;
self.flushBeforeEnterBackground = NO;
self.safariRequestInProgress = NO;

self.messageQueue = [[MessageQueueBySqlite alloc] initWithFilePath:[self filePathForData:@"message"]];
if (self.messageQueue == nil) {
Expand Down Expand Up @@ -280,7 +283,6 @@ - (void)flush {
CFSTR("!*'();:@&=+$,/?%#[]"),
kCFStringEncodingUTF8));

SADebug(@"POST content : %@", jsonString);
NSString *postBody = [NSString stringWithFormat:@"gzip=1&data_list=%@", b64String];

NSURL *URL = [NSURL URLWithString:self.serverURL];
Expand Down Expand Up @@ -361,75 +363,89 @@ - (void)flush {

// 使用 SFSafariViewController 发送数据 (>= iOS 9.0)
BOOL (^flushBySafariVC)(NSArray *) = ^(NSArray *recordArray) {
if (self.safariRequestInProgress) {
return NO;
}

self.safariRequestInProgress = YES;

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
Class SFSafariViewControllerClass = NSClassFromString(@"SFSafariViewController");
if (!SFSafariViewControllerClass) {
SAError(@"Cannot use cookie-based installation tracking. Please import the SafariService.framework.");
self.safariRequestInProgress = NO;
return YES;
}

for (id record in recordArray) {
// 1. 使用gzip进行压缩
NSData *zippedData = [LFCGzipUtility gzipData:[(NSString *)record dataUsingEncoding:NSUTF8StringEncoding]];
// 2. base64
NSString *b64String = [zippedData sa_base64EncodedString];
b64String = (id)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)b64String,
NULL,
CFSTR("!*'();:@&=+$,/?%#[]"),
kCFStringEncodingUTF8));
// 1. 先完成这一系列Json字符串的拼接
NSString *jsonString = [NSString stringWithFormat:@"[%@]",[recordArray componentsJoinedByString:@","]];
// 2. 使用gzip进行压缩
NSData *zippedData = [LFCGzipUtility gzipData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
// 3. base64
NSString *b64String = [zippedData sa_base64EncodedString];
b64String = (id)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)b64String,
NULL,
CFSTR("!*'();:@&=+$,/?%#[]"),
kCFStringEncodingUTF8));

NSURL *url = [NSURL URLWithString:self.serverURL];
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:YES];
if (components.query.length > 0) {
NSString *urlQuery = [[NSString alloc] initWithFormat:@"%@&gzip=1&data_list=%@", components.percentEncodedQuery, b64String];
components.percentEncodedQuery = urlQuery;
} else {
NSString *urlQuery = [[NSString alloc] initWithFormat:@"gzip=1&data_list=%@", b64String];
components.percentEncodedQuery = urlQuery;
}

// Must be on next run loop to avoid a warning
dispatch_async(dispatch_get_main_queue(), ^{

NSURL *url = [NSURL URLWithString:self.serverURL];
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:YES];
if (components.query.length > 0) {
NSString *urlQuery = [[NSString alloc] initWithFormat:@"%@&gzip=1&data=%@", components.percentEncodedQuery, b64String];
components.percentEncodedQuery = urlQuery;
} else {
NSString *urlQuery = [[NSString alloc] initWithFormat:@"gzip=1&data=%@", b64String];
components.percentEncodedQuery = urlQuery;
}

// Must be on next run loop to avoid a warning
dispatch_async(dispatch_get_main_queue(), ^{
UIViewController *safController = [[SFSafariViewControllerClass alloc] initWithURL:[components URL]];

UIViewController *safController = [[SFSafariViewControllerClass alloc] initWithURL:[components URL]];

UIViewController *windowRootController = [[UIViewController alloc] init];

self.secondWindow = [[UIWindow alloc] initWithFrame:[[[[UIApplication sharedApplication] delegate] window] bounds]];
self.secondWindow.rootViewController = windowRootController;
self.secondWindow.windowLevel = UIWindowLevelNormal - 1;
[self.secondWindow setHidden:NO];
[self.secondWindow setAlpha:0];
UIViewController *windowRootController = [[UIViewController alloc] init];

self.secondWindow = [[UIWindow alloc] initWithFrame:[[[[UIApplication sharedApplication] delegate] window] bounds]];
self.secondWindow.rootViewController = windowRootController;
self.secondWindow.windowLevel = UIWindowLevelNormal - 1;
[self.secondWindow setHidden:NO];
[self.secondWindow setAlpha:0];

// Add the safari view controller using view controller containment
[windowRootController addChildViewController:safController];
[windowRootController.view addSubview:safController.view];
[safController didMoveToParentViewController:windowRootController];
// Add the safari view controller using view controller containment
[windowRootController addChildViewController:safController];
[windowRootController.view addSubview:safController.view];
[safController didMoveToParentViewController:windowRootController];

// Give a little bit of time for safari to load the request.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// Remove the safari view controller from view controller containment
[safController willMoveToParentViewController:nil];
[safController.view removeFromSuperview];
[safController removeFromParentViewController];

// Give a little bit of time for safari to load the request.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// Remove the safari view controller from view controller containment
[safController willMoveToParentViewController:nil];
[safController.view removeFromSuperview];
[safController removeFromParentViewController];

// Remove the window and release it's strong reference. This is important to ensure that
// applications using view controller based status bar appearance are restored.
[self.secondWindow removeFromSuperview];
self.secondWindow = nil;
});
// Remove the window and release it's strong reference. This is important to ensure that
// applications using view controller based status bar appearance are restored.
[self.secondWindow removeFromSuperview];
self.secondWindow = nil;

self.safariRequestInProgress = NO;
});
}

if (_debugMode != SensorsAnalyticsDebugOff) {
SALog(@"%@ The validation in DEBUG mode is unavailable while using track_installtion. Please check the result with 'debug_data_viewer'.", self);
SALog(@"%@ 使用 track_installation 时无法直接获得 Debug 模式数据校验结果,请登录 Sensors Analytics 并进入 '数据接入辅助工具' 查看校验结果。", self);
}
});
#else
// DO NOTHING
#endif
return YES;
};

dispatch_async(self.serialQueue, ^{
[self flushByType:@"Post" withSize:(_debugMode == SensorsAnalyticsDebugOff ? 50 : 1) andFlushMethod:flushByPost];
[self flushByType:@"SFSafariViewController" withSize:1 andFlushMethod:flushBySafariVC];
[self flushByType:@"SFSafariViewController" withSize:(_debugMode == SensorsAnalyticsDebugOff ? 50 : 1) andFlushMethod:flushBySafariVC];

if (![self.messageQueue vacuum]) {
@throw [NSException exceptionWithName:@"SqliteException"
Expand All @@ -455,7 +471,7 @@ - (NSString *)filePathForData:(NSString *)data {
return filepath;
}

- (void)enqueueWithType:(NSString *)type andEvent:(NSDictionary *)e andFlushMethod:(NSString *)flushMethod {
- (void)enqueueWithType:(NSString *)type andEvent:(NSDictionary *)e {
NSMutableDictionary *event = [[NSMutableDictionary alloc] initWithDictionary:e];
NSMutableDictionary *properties = [[NSMutableDictionary alloc] initWithDictionary:[event objectForKey:@"properties"]];

Expand All @@ -472,6 +488,11 @@ - (void)enqueueWithType:(NSString *)type andEvent:(NSDictionary *)e andFlushMeth
[event setObject:properties forKey:@"properties"];
}

NSString *flushMethod = @"Post";
if ([properties objectForKey:@"$ios_install_source"]) {
flushMethod = @"SFSafariViewController";
}

[self.messageQueue addObejct:event withType:flushMethod];

if (_debugMode != SensorsAnalyticsDebugOff) {
Expand Down Expand Up @@ -523,8 +544,7 @@ - (void)track:(NSString *)event withProperties:(NSDictionary *)propertieDict wit
}
}

// UInt64 timeStamp = [[self class] getCurrentTime];
UInt64 timeStamp = 1461294882355;
UInt64 timeStamp = [[self class] getCurrentTime];

dispatch_async(self.serialQueue, ^{
NSMutableDictionary *p = [NSMutableDictionary dictionary];
Expand Down Expand Up @@ -576,12 +596,7 @@ - (void)track:(NSString *)event withProperties:(NSDictionary *)propertieDict wit
@"type": type};
}

NSString *flushMethod = @"Post";
if ([type isEqualToString:@"profile_set_once"] && event && [event isEqualToString:@"$ios_install_source"]) {
flushMethod = @"SFSafariViewController";
}

[self enqueueWithType:type andEvent:[e copy] andFlushMethod:flushMethod];
[self enqueueWithType:type andEvent:[e copy]];
});
}

Expand Down Expand Up @@ -625,6 +640,29 @@ - (void)trackSignUp:(NSString *)newDistinctId {
[self trackSignUp:newDistinctId withProperties:nil];
}

- (void)trackInstallation:(NSString *)event withProperties:(NSDictionary *)propertyDict {
// 追踪渠道是特殊功能,需要同时发送 track 和 profile_set_once

// 先发送 track
NSMutableDictionary *eventProperties;
if (propertyDict == nil) {
eventProperties = [[NSMutableDictionary alloc] init];
} else {
eventProperties = [[NSMutableDictionary alloc] initWithDictionary:propertyDict];
}

[eventProperties setValue:@"NULL" forKey:@"$ios_install_source"];
[self track:event withProperties:eventProperties withType:@"track"];

// 再发送 profile_set_once
NSDictionary *profiles = @{@"$ios_install_source" : @"NULL"};
[self track:nil withProperties:profiles withType:@"profile_set_once"];
}

- (void)trackInstallation:(NSString *)event {
[self trackInstallation:event withProperties:nil];
}

- (void)identify:(NSString *)distinctId {
if (distinctId == nil || distinctId.length == 0) {
SAError(@"%@ cannot identify blank distinct id: %@", self, distinctId);
Expand Down Expand Up @@ -1213,7 +1251,7 @@ - (void)connectToVTrackDesigner:(BOOL)reconnect {
[connection sendMessage:message];
};

[SASwizzler swizzleSelector:@selector(enqueueWithType:andEvent:andFlushMethod:)
[SASwizzler swizzleSelector:@selector(enqueueWithType:andEvent:)
onClass:[SensorsAnalyticsSDK class]
withBlock:block
named:@"track_properties"];
Expand All @@ -1233,7 +1271,7 @@ - (void)connectToVTrackDesigner:(BOOL)reconnect {

[strongSelf executeEventBindings:strongSelf.eventBindings];

[SASwizzler unswizzleSelector:@selector(enqueueWithType:andEvent:andFlushMethod:)
[SASwizzler unswizzleSelector:@selector(enqueueWithType:andEvent:)
onClass:[SensorsAnalyticsSDK class]
named:@"track_properties"];
}
Expand Down Expand Up @@ -1290,10 +1328,6 @@ - (void)setOnce:(NSString *) profile to:(id)content {
[_sdk track:nil withProperties:@{profile: content} withType:@"profile_set_once"];
}

- (void)setInstallSourceAutomatically {
[_sdk track:@"$ios_install_source" withProperties:@{@"$ios_install_source" : @"NULL"} withType:@"profile_set_once"];
}

- (void)unset:(NSString *) profile {
[_sdk track:nil withProperties:@{profile: @""} withType:@"profile_unset"];
}
Expand Down

0 comments on commit 44b6124

Please sign in to comment.