From e557de12ed1d293573a900ba3ec29d0953012b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=B4=8B=E6=B4=8B?= Date: Wed, 28 Sep 2022 17:16:11 +0800 Subject: [PATCH] Release 0.2.3 --- Example/Example-iOS/AppDelegate.m | 4 +- .../Example-iOS/Base.lproj/Main.storyboard | 148 ++++++++++-------- Example/Example-iOS/ViewController.m | 124 +++++++++------ Example/Example-macOS/AppDelegate.m | 3 +- Example/Example.xcodeproj/project.pbxproj | 32 ++-- .../DataManger/SABTestTriggerIdentifier.h | 14 +- .../DataManger/SABTestTriggerIdentifier.m | 50 +++++- SensorsABTest/SABConstants.h | 3 + SensorsABTest/SABConstants.m | 4 +- SensorsABTest/SABManager.m | 67 ++++++-- SensorsABTesting.podspec | 2 +- 11 files changed, 305 insertions(+), 146 deletions(-) diff --git a/Example/Example-iOS/AppDelegate.m b/Example/Example-iOS/AppDelegate.m index b797ab5..130c777 100644 --- a/Example/Example-iOS/AppDelegate.m +++ b/Example/Example-iOS/AppDelegate.m @@ -23,7 +23,7 @@ #import /// 测试环境,获取试验地址 -static NSString* kSABResultsTestURL = @"http://abtesting.saas.debugbox.sensorsdata.cn/api/v2/abtest/online/results?project-key=438B9364C98D54371751BA82F6484A1A03A5155E"; +static NSString* kSABResultsTestURL = @"http://10.129.138.19:8202/api/v2/abtest/online/results?project-key=4D3483ECF05968FC4522BB2B52CB3B1CCA1D3FCA"; // 测试环境,数据接收地址 static NSString* kSABTestServerURL = @"http://10.130.6.4:8106/sa?project=default"; @@ -53,7 +53,7 @@ - (void)startSensorsAnalyticsSDKWithConfigOptions:(NSDictionary *)launchOptions options.enableVisualizedAutoTrack = YES; options.enableJavaScriptBridge = YES; options.enableLog = YES; - options.flushNetworkPolicy = SensorsAnalyticsNetworkTypeALL; + options.flushNetworkPolicy = SensorsAnalyticsNetworkTypeNONE; [SensorsAnalyticsSDK startWithConfigOptions:options]; } diff --git a/Example/Example-iOS/Base.lproj/Main.storyboard b/Example/Example-iOS/Base.lproj/Main.storyboard index 395d92d..96c1b0c 100644 --- a/Example/Example-iOS/Base.lproj/Main.storyboard +++ b/Example/Example-iOS/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -35,11 +35,11 @@ - - + + - + - + @@ -80,7 +80,7 @@ - + @@ -102,7 +102,7 @@ - + @@ -127,15 +127,15 @@ - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/Example-iOS/ViewController.m b/Example/Example-iOS/ViewController.m index e5cab74..3c432f6 100644 --- a/Example/Example-iOS/ViewController.m +++ b/Example/Example-iOS/ViewController.m @@ -48,157 +48,191 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath case 0: { // INTEGER id result = [[SensorsABTest sharedInstance] fetchCacheABTestWithParamName:@"color1" defaultValue:@(1111)]; NSLog(@"fetchCacheABTest,paramName:%@ - result:%@\n", @"color1", result); - - id result2 = [[SensorsABTest sharedInstance] fetchCacheABTestWithParamName:@"102" defaultValue:@(1111)]; - NSLog(@"fetchCacheABTest,paramName:%@ - result:%@\n", @"102", result2); + + // id result2 = [[SensorsABTest sharedInstance] fetchCacheABTestWithParamName:@"102" defaultValue:@(1111)]; + // NSLog(@"fetchCacheABTest,paramName:%@ - result:%@\n", @"102", result2); } - break; - + break; + case 1: { // BOOLEAN id result = [[SensorsABTest sharedInstance] fetchCacheABTestWithParamName:@"16" defaultValue:@(NO)]; NSLog(@"fetchCacheABTest,paramName:%@ - result:%@\n", @"16", result); } - break; - + break; + case 2: { // STRING id result = [[SensorsABTest sharedInstance] fetchCacheABTestWithParamName:@"hef_tes" defaultValue:@"默认值字符串"]; NSLog(@"fetchCacheABTest,paramName:%@ - result:%@\n", @"hef_tes", result); } - break; - + break; + case 3: { // JSON id result = [[SensorsABTest sharedInstance] fetchCacheABTestWithParamName:@"color4" defaultValue:@{}]; NSLog(@"fetchCacheABTest,paramName:%@ - result:%@\n", @"color4", result); } - break; - + break; + default: break; } } - break; + break; case 1: { // asyncFetch switch (row) { case 0: { // INTEGER [[SensorsABTest sharedInstance] asyncFetchABTestWithParamName:@"color1" defaultValue:@(1111) completionHandler:^(id _Nullable result) { NSLog(@"asyncFetchABTest,paramName:%@ - result:%@\n", @"color1", result); }]; - + [[SensorsABTest sharedInstance] asyncFetchABTestWithParamName:@"19" defaultValue:@(1111) completionHandler:^(id _Nullable result) { NSLog(@"asyncFetchABTest,paramName:%@ - result:%@\n", @"19", result); }]; } - break; - + break; + case 1: { // BOOLEAN [[SensorsABTest sharedInstance] asyncFetchABTestWithParamName:@"color3" defaultValue:@(NO) completionHandler:^(id _Nullable result) { NSLog(@"asyncFetchABTest,paramName:%@ - result:%@\n", @"color3", result); }]; } - break; - + break; + case 2: { // STRING [[SensorsABTest sharedInstance] asyncFetchABTestWithParamName:@"color2" defaultValue:@"默认值字符串" completionHandler:^(id _Nullable result) { NSLog(@"asyncFetchABTest,paramName:%@ - result:%@\n", @"color2", result); }]; } - break; - + break; + case 3: { // JSON [[SensorsABTest sharedInstance] asyncFetchABTestWithParamName:@"color4" defaultValue:@{} completionHandler:^(id _Nullable result) { NSLog(@"asyncFetchABTest,paramName:%@ - result:%@\n", @"color4", result); }]; } - break; - + break; + default: break; } } - break; + break; case 2: { // fastFetch switch (row) { // 试验 Id case 0: { // INTEGER [[SensorsABTest sharedInstance] fastFetchABTestWithParamName:@"color1" defaultValue:@(1111) completionHandler:^(id _Nullable result) { NSLog(@"fastFetchABTest,paramName:%@ - result:%@\n", @"color1", result); }]; - + [[SensorsABTest sharedInstance] fastFetchABTestWithParamName:@"21" defaultValue:@(1111) completionHandler:^(id _Nullable result) { NSLog(@"asyncFetchABTest,paramName:%@ - result:%@\n", @"21", result); }]; } - break; - + break; + case 1: { // BOOLEAN [[SensorsABTest sharedInstance] fastFetchABTestWithParamName:@"color3" defaultValue:@(NO) completionHandler:^(id _Nullable result) { NSLog(@"fastFetchABTest,paramName:%@ - result:%@\n", @"color3", result); }]; } - break; - + break; + case 2: { // STRING [[SensorsABTest sharedInstance] fastFetchABTestWithParamName:@"color2" defaultValue:@"默认值字符串" completionHandler:^(id _Nullable result) { NSLog(@"fastFetchABTest,paramName:%@ - result:%@\n", @"color2", result); }]; } - break; - + break; + case 3: { // JSON [[SensorsABTest sharedInstance] fastFetchABTestWithParamName:@"color4" defaultValue:@{} completionHandler:^(id _Nullable result) { NSLog(@"fastFetchABTest,paramName:%@ - result:%@\n", @"color4", result); }]; } - break; - + break; + default: break; } } - break; + break; case 3: { // other switch (row) { // case 0: { // flush [[SensorsAnalyticsSDK sharedInstance] flush]; } - break; - + break; + case 1: { // go webView WKWebViewController *webViewVC = [[WKWebViewController alloc] init]; [self.navigationController pushViewController:webViewVC animated:YES]; } - break; + break; default: break; } } - break; + break; case 4: { // login、logout、identify 、resetAnonymousId switch (row) { case 0: { // login [[SensorsAnalyticsSDK sharedInstance] login:@"login_test_20201217" withProperties:@{ @"name": @"batest_relod_login" }]; } - break; - + break; + case 1: { // logout [[SensorsAnalyticsSDK sharedInstance] logout]; } - break; - + break; + case 2: { // identify [[SensorsAnalyticsSDK sharedInstance] identify:@"abtest_relod_identify_1234567"]; } - break; - + break; + case 3: { // resetAnonymousId [[SensorsAnalyticsSDK sharedInstance] resetAnonymousId]; } - break; - + break; + + default: + break; + } + } + // other + case 5: { + switch (row) { + case 0: { + + dispatch_queue_t serialQueue1 = dispatch_queue_create([@"test1" UTF8String], DISPATCH_QUEUE_SERIAL); + dispatch_queue_t serialQueue2 = dispatch_queue_create([@"test2" UTF8String], DISPATCH_QUEUE_SERIAL); + dispatch_queue_t serialQueue3 = dispatch_queue_create([@"test3" UTF8String], DISPATCH_QUEUE_SERIAL); + + for (NSInteger index = 0; index < 1000; index ++) { + dispatch_async(serialQueue1, ^{ + id result = [[SensorsABTest sharedInstance] fetchCacheABTestWithParamName:@"index_cqs" defaultValue:@(1111)]; + NSLog(@"fetchCacheABTest1,paramName:%@ - result:%@\n", @"index_cqs", result); + + }); + + dispatch_async(serialQueue2, ^{ + id result = [[SensorsABTest sharedInstance] fetchCacheABTestWithParamName:@"index_cqs" defaultValue:@(2222)]; + NSLog(@"fetchCacheABTest2,paramName:%@ - result:%@\n", @"index_cqs", result); + + }); + + dispatch_async(serialQueue3, ^{ + id result = [[SensorsABTest sharedInstance] fetchCacheABTestWithParamName:@"index_cqs" defaultValue:@(3333)]; + NSLog(@"fetchCacheABTest3,paramName:%@ - result:%@\n", @"index_cqs", result); + + }); + } + } + break; + default: break; } } - default: break; } diff --git a/Example/Example-macOS/AppDelegate.m b/Example/Example-macOS/AppDelegate.m index adc5fdd..3d34a23 100644 --- a/Example/Example-macOS/AppDelegate.m +++ b/Example/Example-macOS/AppDelegate.m @@ -26,8 +26,7 @@ static NSString *const SADefaultServerURL = @"http://10.130.6.4:8106/sa?project=default"; /// 测试环境,获取试验地址 -static NSString* kSABResultsTestURL = @"http://abtesting.saas.debugbox.sensorsdata.cn/api/v2/abtest/online/results?project-key=438B9364C98D54371751BA82F6484A1A03A5155E"; - +static NSString* kSABResultsTestURL = @"http://10.129.138.19:8202/api/v2/abtest/online/results?project-key=4D3483ECF05968FC4522BB2B52CB3B1CCA1D3FCA"; @interface AppDelegate () diff --git a/Example/Example.xcodeproj/project.pbxproj b/Example/Example.xcodeproj/project.pbxproj index fa668dd..71aea79 100644 --- a/Example/Example.xcodeproj/project.pbxproj +++ b/Example/Example.xcodeproj/project.pbxproj @@ -176,7 +176,7 @@ 4D15CF0F24EE82E0003D2748 /* Sources */, 4D15CF1024EE82E0003D2748 /* Frameworks */, 4D15CF1124EE82E0003D2748 /* Resources */, - A6AE11C787B8DAA4FFF5F17D /* [CP] Embed Pods Frameworks */, + 14DF99B3C634F552E75DA55C /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -266,43 +266,43 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 6E9611FFCDFF273D57F24B02 /* [CP] Check Pods Manifest.lock */ = { + 14DF99B3C634F552E75DA55C /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Example-iOS/Pods-Example-iOS-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Example-iOS-checkManifestLockResult.txt", + "${PODS_ROOT}/Target Support Files/Pods-Example-iOS/Pods-Example-iOS-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Example-iOS/Pods-Example-iOS-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - A6AE11C787B8DAA4FFF5F17D /* [CP] Embed Pods Frameworks */ = { + 6E9611FFCDFF273D57F24B02 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Example-iOS/Pods-Example-iOS-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Example-iOS/Pods-Example-iOS-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Example-iOS-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Example-iOS/Pods-Example-iOS-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; C763224C380B0B67A1E6B77F /* [CP] Embed Pods Frameworks */ = { diff --git a/SensorsABTest/DataManger/SABTestTriggerIdentifier.h b/SensorsABTest/DataManger/SABTestTriggerIdentifier.h index 975ef18..09995af 100644 --- a/SensorsABTest/DataManger/SABTestTriggerIdentifier.h +++ b/SensorsABTest/DataManger/SABTestTriggerIdentifier.h @@ -22,16 +22,24 @@ NS_ASSUME_NONNULL_BEGIN +@class SABExperimentResult; + /// 事件标识,用户区分是否触发过 $ABTestTrigger 事件 -@interface SABTestTriggerIdentifier : NSObject +@interface SABTestTriggerIdentifier : NSObject + +/// 试验组 Id +@property (nonatomic, copy, readonly) NSString *experimentGroupId; /// 自定义主体 ID @property (nonatomic, copy) NSDictionary *customIDs; - (instancetype)init NS_UNAVAILABLE; -/// 指定初始化方法 -- (instancetype)initWithExperimentId:(NSString *)experimentId distinctId:(NSString *)distinctId NS_DESIGNATED_INITIALIZER; +/// 初始化实例 +/// @param experimentResult 试验结果配置 +/// @param distinctId 当前用户 distinctId +- (instancetype)initWithExperiment:(SABExperimentResult *)experimentResult distinctId:(NSString *)distinctId; + @end NS_ASSUME_NONNULL_END diff --git a/SensorsABTest/DataManger/SABTestTriggerIdentifier.m b/SensorsABTest/DataManger/SABTestTriggerIdentifier.m index a4782ca..8fe22e0 100644 --- a/SensorsABTest/DataManger/SABTestTriggerIdentifier.m +++ b/SensorsABTest/DataManger/SABTestTriggerIdentifier.m @@ -23,30 +23,41 @@ #endif #import "SABTestTriggerIdentifier.h" +#import "SABFetchResultResponse.h" + @interface SABTestTriggerIdentifier() +/// 当前用户 distinctId +@property (nonatomic, copy) NSString *distinctId; + /// 试验 Id @property (nonatomic, copy) NSString *experimentId; -/// 当前用户 distinctId -@property (nonatomic, copy) NSString *distinctId; +@property (nonatomic, copy, readwrite) NSString *experimentGroupId; + @end @implementation SABTestTriggerIdentifier -- (instancetype)initWithExperimentId:(NSString *)experimentId distinctId:(NSString *)distinctId { + +- (instancetype)initWithExperiment:(SABExperimentResult *)experimentResult distinctId:(NSString *)distinctId { self = [super init]; if (self) { - _experimentId = experimentId; + _experimentId = experimentResult.experimentId; + _experimentGroupId = experimentResult.experimentGroupId; _distinctId = distinctId; } return self; } +#pragma mark isEqual /// 实现 isEqual:,判断是否为相同事件标识 - (BOOL)isEqual:(SABTestTriggerIdentifier *)identify { + if (identify == self) { + return YES; + } if (![self.distinctId isEqualToString:identify.distinctId]) { return NO; } @@ -59,4 +70,35 @@ - (BOOL)isEqual:(SABTestTriggerIdentifier *)identify { return [self.customIDs isEqualToDictionary:identify.customIDs]; } +- (NSUInteger)hash { + NSUInteger value = 0; + value ^= [self.experimentId hash]; + value ^= [self.experimentGroupId hash]; + value ^= [self.distinctId hash]; + if (self.customIDs.count > 0) { + value ^= [self.customIDs hash]; + } + return value; +} + + +#pragma mark NSCoding +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:self.experimentId forKey:@"experimentId"]; + [coder encodeObject:self.experimentGroupId forKey:@"experimentGroupId"]; + [coder encodeObject:self.distinctId forKey:@"distinctId"]; + [coder encodeObject:self.customIDs forKey:@"customIDs"]; +} + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super init]; + if (self) { + self.experimentId = [coder decodeObjectForKey:@"experimentId"]; + self.experimentGroupId = [coder decodeObjectForKey:@"experimentGroupId"]; + self.distinctId = [coder decodeObjectForKey:@"distinctId"]; + self.customIDs = [coder decodeObjectForKey:@"customIDs"]; + } + return self; +} + @end diff --git a/SensorsABTest/SABConstants.h b/SensorsABTest/SABConstants.h index 70e1f58..dd4a241 100644 --- a/SensorsABTest/SABConstants.h +++ b/SensorsABTest/SABConstants.h @@ -63,6 +63,9 @@ extern NSString *const kSABExperimentResultFileName; /// 自定义主体 ID extern NSString *const kSABCustomIDsFileName; +/// 触发 ABTestTrigger 事件标识信息 +extern NSString *const kSABTestTriggerIdentifiersFileName; + #pragma mark - NSNotificationName #pragma mark H5 打通相关 /// SA 注入 H5 打通 Bridge diff --git a/SensorsABTest/SABConstants.m b/SensorsABTest/SABConstants.m index 841f3f8..6b5e631 100644 --- a/SensorsABTest/SABConstants.m +++ b/SensorsABTest/SABConstants.m @@ -25,7 +25,7 @@ #import "SABConstants.h" // 当前版本号 -NSString *const kSABLibVersion = @"0.2.2"; +NSString *const kSABLibVersion = @"0.2.3"; // SA 最低支持版本 NSString *const kSABMinSupportedSALibVersion = @"4.2.0"; @@ -66,6 +66,8 @@ NSString *const kSABCustomIDsFileName = @"SensorsABTestCustomIDs"; +NSString *const kSABTestTriggerIdentifiersFileName = @"SensorsABTestTriggerIdentifierSources"; + #pragma mark - NSNotificationName,依赖 SA #pragma mark H5 打通相关 /// SA 注入 H5 打通 Bridge diff --git a/SensorsABTest/SABManager.m b/SensorsABTest/SABManager.m index eba2074..8df50f9 100644 --- a/SensorsABTest/SABManager.m +++ b/SensorsABTest/SABManager.m @@ -38,6 +38,8 @@ #import "SensorsABTestExperiment+Private.h" #import "SABRequestManager.h" #import "SABTestTriggerIdentifier.h" +#import "SABStoreManager.h" +#import "SABFileStorePlugin.h" /// 调用 js 方法名 static NSString * const kSABAppCallJSMethodName = @"window.sensorsdata_app_call_js"; @@ -70,7 +72,8 @@ @interface SABManager() @property (nonatomic, strong) SABExperimentDataManager *dataManager; /// 触发过的事件标识 -@property (nonatomic, strong) NSMutableArray *trackedIdentifiers; +@property (nonatomic, copy) NSArray *trackedIdentifiers; +@property (nonatomic, strong) dispatch_queue_t serialQueue; @property (nonatomic, strong) NSTimer *timer; // 暂停时刻时间 @@ -89,8 +92,9 @@ - (instancetype)initWithConfigOptions:(nonnull SensorsABTestConfigOptions *)conf self = [super init]; if (self) { _configOptions = [configOptions copy]; - _trackedIdentifiers = [NSMutableArray array]; - + NSString *serialQueueLabel = [NSString stringWithFormat:@"com.SensorsABTest.SABManager.serialQueue.%p", self]; + _serialQueue = dispatch_queue_create([serialQueueLabel UTF8String], DISPATCH_QUEUE_SERIAL); + // 数据存储和解析 _dataManager = [[SABExperimentDataManager alloc] init]; @@ -98,7 +102,9 @@ - (instancetype)initWithConfigOptions:(nonnull SensorsABTestConfigOptions *)conf // 注册监听 [self setupListeners]; - + + [self unarchiveABTestTriggerIdentifiers]; + // 获取所有最新试验结果 [self fetchAllABTestResultWithTimes:kSABAsyncFetchExperimentMaxTimes]; } @@ -122,6 +128,23 @@ - (void)setupListeners { [notificationCenter addObserver:self selector:@selector(reloadAllABTestResult:) name:kSABSAResetAnonymousIdNotification object:nil]; } +#pragma mark - ABTestTrigger Identifiers +/// 缓存事件标识信息 +- (void)archiveABTestTriggerIdentifiers:(NSArray *)trackedIdentifiers { + // 存储到本地 + self.trackedIdentifiers = trackedIdentifiers; + + [SABStoreManager.sharedInstance setObject:trackedIdentifiers forKey:kSABTestTriggerIdentifiersFileName]; +} + +/// 读取本地缓存事件标识信息 +- (void)unarchiveABTestTriggerIdentifiers { + dispatch_async(self.serialQueue, ^{ + NSArray *results = [SABStoreManager.sharedInstance objectForKey:kSABTestTriggerIdentifiersFileName]; + self.trackedIdentifiers = results; + }); +} + #pragma mark - notification Action // 状态变化通知 - (void)appLifecycleStateDidChange:(NSNotification *)sender { @@ -306,6 +329,7 @@ - (nullable id)fetchCacheABTestWithExperiment:(SensorsABTestExperiment *)experim SABLogWarn(@"The cache experiment result is empty, paramName: %@", experiment.paramName); return nil; } + // 判断和默认值类型是否一致 if (![resultData isSameTypeWithDefaultValue:experiment.defaultValue]) { NSString *resulTypeString = [SABExperimentResult descriptionWithExperimentResultType:resultData.variable.type]; @@ -315,9 +339,12 @@ - (nullable id)fetchCacheABTestWithExperiment:(SensorsABTestExperiment *)experim } if (!resultData.isWhiteList) { - // 埋点 - [self trackABTestWithData:resultData]; + dispatch_async(self.serialQueue, ^{ + // 埋点 + [self trackABTestWithData:resultData]; + }); } + return resultData.variable.value; } @@ -416,14 +443,29 @@ - (void)trackABTestWithData:(SABExperimentResult *)resultData { } // 构建触发事件标识 - SABTestTriggerIdentifier *eventIdentify = [[SABTestTriggerIdentifier alloc] initWithExperimentId:resultData.experimentId distinctId:distinctId]; + SABTestTriggerIdentifier *eventIdentify = [[SABTestTriggerIdentifier alloc] initWithExperiment:resultData distinctId:distinctId]; eventIdentify.customIDs = self.dataManager.customIDs; - // 是否已经触发事件 - if ([self.trackedIdentifiers containsObject:eventIdentify]) { - return; + + NSArray *trackedIdentifiers = self.trackedIdentifiers; + NSMutableArray *newTrackedIdentifiers = [NSMutableArray arrayWithArray:trackedIdentifiers]; + + /// 对比是否触发过相同事件 + for (SABTestTriggerIdentifier *trackedEventIdentify in trackedIdentifiers) { + if (![trackedEventIdentify isEqual:eventIdentify]) { + continue; + } + + // 试验组 Id 相同,不触发事件 + if ([trackedEventIdentify.experimentGroupId isEqualToString:eventIdentify.experimentGroupId]) { + return; + } else { // 试验组 Id 不同,移除事件标识,后续再次触发事件 + [newTrackedIdentifiers removeObject:trackedEventIdentify]; + break; + } } + // 记录当前试验触发事件 - [self.trackedIdentifiers addObject:eventIdentify]; + [newTrackedIdentifiers addObject:eventIdentify]; NSMutableDictionary *properties = [NSMutableDictionary dictionary]; properties[kSABTriggerExperimentId] = resultData.experimentId; @@ -442,6 +484,9 @@ - (void)trackABTestWithData:(SABExperimentResult *)resultData { }); [SABBridge track:kSABTriggerEventName properties:properties]; + + // 缓存事件标识信息 + [self archiveABTestTriggerIdentifiers:[newTrackedIdentifiers copy]]; } /// 开始更新计时 diff --git a/SensorsABTesting.podspec b/SensorsABTesting.podspec index ebbf086..a329720 100644 --- a/SensorsABTesting.podspec +++ b/SensorsABTesting.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'SensorsABTesting' - s.version = "0.2.2" + s.version = "0.2.3" s.summary = 'The official iOS/macOS SDK of Sensors A/B Testing.' s.homepage = 'http://www.sensorsdata.cn' s.license = { :type => 'Apache 2.0', :file => 'LICENSE' }