From f316700790d5b5f3e9b0a8206d058bfd575293f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E7=8E=89=E5=9B=BD?= Date: Mon, 20 Nov 2023 18:39:32 +0800 Subject: [PATCH] Release 4.5.23 --- SensorsAnalyticsSDK.podspec | 2 +- SensorsAnalyticsSDK.xcodeproj/project.pbxproj | 8 ++ .../ChannelMatch/SAChannelMatchManager.m | 22 +--- .../Core/SAConstants+Private.h | 9 ++ SensorsAnalyticsSDK/Core/SAConstants.m | 9 ++ .../Core/SensorsAnalyticsSDK.m | 6 +- .../Core/Utils/SACommonUtility.h | 5 +- .../Core/Utils/SACommonUtility.m | 13 +++ .../Deeplink/SAAdvertisingConfig.h | 8 +- .../Deeplink/SAAdvertisingConfig.m | 2 + .../Deeplink/SAAppInteractTracker.h | 32 ++++++ .../Deeplink/SAAppInteractTracker.m | 106 ++++++++++++++++++ .../Deeplink/SADeepLinkProcessor.h | 3 - .../Deeplink/SADeepLinkProcessor.m | 15 +-- .../Deeplink/SADeeplinkManager.m | 51 ++++++++- .../Deeplink/SADeferredDeepLinkProcessor.m | 5 +- 16 files changed, 252 insertions(+), 44 deletions(-) create mode 100644 SensorsAnalyticsSDK/Deeplink/SAAppInteractTracker.h create mode 100644 SensorsAnalyticsSDK/Deeplink/SAAppInteractTracker.m diff --git a/SensorsAnalyticsSDK.podspec b/SensorsAnalyticsSDK.podspec index 38542e1e..fb74d008 100644 --- a/SensorsAnalyticsSDK.podspec +++ b/SensorsAnalyticsSDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SensorsAnalyticsSDK" - s.version = "4.5.22" + s.version = "4.5.23" s.summary = "The official 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}" } diff --git a/SensorsAnalyticsSDK.xcodeproj/project.pbxproj b/SensorsAnalyticsSDK.xcodeproj/project.pbxproj index f3696d2b..db0b0b59 100644 --- a/SensorsAnalyticsSDK.xcodeproj/project.pbxproj +++ b/SensorsAnalyticsSDK.xcodeproj/project.pbxproj @@ -515,6 +515,8 @@ F28997D8273B6D66005E7D5E /* SAGesturePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = F28997D6273B6D66005E7D5E /* SAGesturePlugin.m */; }; F296FF042935A3DF00C40C48 /* NSObject+SAToString.h in Headers */ = {isa = PBXBuildFile; fileRef = F296FF022935A3DF00C40C48 /* NSObject+SAToString.h */; }; F296FF052935A3DF00C40C48 /* NSObject+SAToString.m in Sources */ = {isa = PBXBuildFile; fileRef = F296FF032935A3DF00C40C48 /* NSObject+SAToString.m */; }; + F2A3F7632AE64FA80089809C /* SAAppInteractTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = F2A3F7612AE64FA80089809C /* SAAppInteractTracker.h */; }; + F2A3F7642AE64FA80089809C /* SAAppInteractTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = F2A3F7622AE64FA80089809C /* SAAppInteractTracker.m */; }; F2B643F62832302F00544BD2 /* SensorsAnalyticsSDK+SAAppExtension.h in Headers */ = {isa = PBXBuildFile; fileRef = F2B643F42832302F00544BD2 /* SensorsAnalyticsSDK+SAAppExtension.h */; settings = {ATTRIBUTES = (Public, ); }; }; F2B643F72832302F00544BD2 /* SensorsAnalyticsSDK+SAAppExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = F2B643F52832302F00544BD2 /* SensorsAnalyticsSDK+SAAppExtension.m */; }; F2C877B828A65849002BDA2C /* SAExposureData+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = F2C877B628A65849002BDA2C /* SAExposureData+Private.h */; }; @@ -1111,6 +1113,8 @@ F28997D6273B6D66005E7D5E /* SAGesturePlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAGesturePlugin.m; sourceTree = ""; }; F296FF022935A3DF00C40C48 /* NSObject+SAToString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+SAToString.h"; sourceTree = ""; }; F296FF032935A3DF00C40C48 /* NSObject+SAToString.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SAToString.m"; sourceTree = ""; }; + F2A3F7612AE64FA80089809C /* SAAppInteractTracker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SAAppInteractTracker.h; sourceTree = ""; }; + F2A3F7622AE64FA80089809C /* SAAppInteractTracker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAAppInteractTracker.m; sourceTree = ""; }; F2B643F42832302F00544BD2 /* SensorsAnalyticsSDK+SAAppExtension.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SensorsAnalyticsSDK+SAAppExtension.h"; sourceTree = ""; }; F2B643F52832302F00544BD2 /* SensorsAnalyticsSDK+SAAppExtension.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SensorsAnalyticsSDK+SAAppExtension.m"; sourceTree = ""; }; F2C877B628A65849002BDA2C /* SAExposureData+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SAExposureData+Private.h"; sourceTree = ""; }; @@ -2061,6 +2065,8 @@ F214620E2A8CE2A90021C27D /* SAAdvertisingConfig.h */, F214620F2A8CE2A90021C27D /* SAAdvertisingConfig.m */, F2727AE82A8DC17F00166C6A /* SAAdvertisingConfig+Private.h */, + F2A3F7612AE64FA80089809C /* SAAppInteractTracker.h */, + F2A3F7622AE64FA80089809C /* SAAppInteractTracker.m */, ); path = Deeplink; sourceTree = ""; @@ -2482,6 +2488,7 @@ F27EA3D627393B4B00896B3A /* SACellClickDynamicSubclassPlugin.h in Headers */, 4DD1296A25F8E451008C0B1E /* SAViewNode.h in Headers */, A8356DC52656459A00FD64AA /* SAAppTracker.h in Headers */, + F2A3F7632AE64FA80089809C /* SAAppInteractTracker.h in Headers */, 88847F4A27605D3F007321E4 /* SABaseStoreManager.h in Headers */, 883BAAB02669CD18008105D2 /* SAExceptionManager.h in Headers */, 45BD80CE26F0B49700DCC759 /* SAThreadSafeDictionary.h in Headers */, @@ -2918,6 +2925,7 @@ 8809806C27FEE78900EB2B3D /* SAEncryptInterceptor.m in Sources */, 4DD1285C25F872A4008C0B1E /* SAObjectSerializerConfig.m in Sources */, F21C226828F7B0E500847823 /* NSDictionary+SACopyProperties.m in Sources */, + F2A3F7642AE64FA80089809C /* SAAppInteractTracker.m in Sources */, 4D1B925F2817F2F3007C31D5 /* SAReferrerTitlePropertyPlugin.m in Sources */, A8CC22332685E50C00E96A03 /* SARemoteConfigEventObject.m in Sources */, 8809805827FDA85E00EB2B3D /* SARemoteConfigInterceptor.m in Sources */, diff --git a/SensorsAnalyticsSDK/ChannelMatch/SAChannelMatchManager.m b/SensorsAnalyticsSDK/ChannelMatch/SAChannelMatchManager.m index 40e45621..97192a8c 100644 --- a/SensorsAnalyticsSDK/ChannelMatch/SAChannelMatchManager.m +++ b/SensorsAnalyticsSDK/ChannelMatch/SAChannelMatchManager.m @@ -38,6 +38,7 @@ #import "SAProfileEventObject.h" #import "SAPropertyPluginManager.h" #import "SAChannelInfoPropertyPlugin.h" +#import "SACommonUtility.h" NSString * const kSAChannelDebugFlagKey = @"com.sensorsdata.channeldebug.flag"; NSString * const kSAChannelDebugInstallEventName = @"$ChannelDebugInstall"; @@ -45,8 +46,6 @@ NSString * const kSAEventPropertyUserAgent = @"$user_agent"; NSString * const kSAEventPropertyChannelCallbackEvent = @"$is_channel_callback_event"; -static NSString * const kSAHasTrackInstallation = @"HasTrackInstallation"; -static NSString * const kSAHasTrackInstallationDisableCallback = @"HasTrackInstallationWithDisableCallback"; @interface SAChannelMatchManager () @@ -193,7 +192,7 @@ - (NSDictionary *)eventProperties:(NSDictionary *)properties disableCallback:(BO result[kSAEventPropertyUserAgent] = [self simulateUserAgent]; } - result[kSAEventPropertyInstallSource] = [self appInstallSource]; + result[kSAEventPropertyInstallSource] = [SACommonUtility appInstallSource]; return result; } @@ -208,7 +207,7 @@ - (NSDictionary *)profileProperties:(NSDictionary *)properties { result[kSAEventPropertyUserAgent] = [self simulateUserAgent]; } - result[kSAEventPropertyInstallSource] = [self appInstallSource]; + result[kSAEventPropertyInstallSource] = [SACommonUtility appInstallSource]; // 用户属性中不需要添加 $ios_install_disable_callback,这里主动移除掉 // (也会移除自定义属性中的 $ios_install_disable_callback, 和原有逻辑保持一致) @@ -219,17 +218,6 @@ - (NSDictionary *)profileProperties:(NSDictionary *)properties { return result; } -- (NSString *)appInstallSource { - NSMutableDictionary *sources = [NSMutableDictionary dictionary]; - sources[@"idfa"] = [SAIdentifier idfa]; - sources[@"idfv"] = [SAIdentifier idfv]; - NSMutableArray *result = [NSMutableArray array]; - for (NSString *key in sources.allKeys) { - [result addObject:[NSString stringWithFormat:@"%@=%@", key, sources[key]]]; - } - return [result componentsJoinedByString:@"##"]; -} - #pragma mark - 附加渠道信息 - (void)trackChannelWithEventObject:(SABaseEventObject *)obj properties:(nullable NSDictionary *)propertyDict { if (self.configOptions.enableAutoAddChannelCallbackEvent) { @@ -327,7 +315,7 @@ - (void)showRelinkAlertWithURL:(NSURL *)url { // 重连二维码对应的设备信息 NSMutableSet *deviceIdSet = [NSMutableSet setWithArray:[deviceId componentsSeparatedByString:@"##"]]; // 当前设备的设备信息 - NSSet *installSourceSet = [NSSet setWithArray:[[self appInstallSource] componentsSeparatedByString:@"##"]]; + NSSet *installSourceSet = [NSSet setWithArray:[[SACommonUtility appInstallSource] componentsSeparatedByString:@"##"]]; [deviceIdSet intersectSet:installSourceSet]; // 取交集,当交集不为空时,表示设备一致 if (deviceIdSet.count > 0) { @@ -373,7 +361,7 @@ - (void)uploadUserInfoIntoWhiteList:(NSDictionary *)qureyItems { NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:qureyItems]; params[@"distinct_id"] = [[SensorsAnalyticsSDK sharedInstance] distinctId]; params[@"has_active"] = @([self isAppInstalled]); - params[@"device_code"] = [self appInstallSource]; + params[@"device_code"] = [SACommonUtility appInstallSource]; request.HTTPBody = [SAJSONUtil dataWithJSONObject:params]; [self showIndicator]; diff --git a/SensorsAnalyticsSDK/Core/SAConstants+Private.h b/SensorsAnalyticsSDK/Core/SAConstants+Private.h index 6fd5b288..c22be306 100644 --- a/SensorsAnalyticsSDK/Core/SAConstants+Private.h +++ b/SensorsAnalyticsSDK/Core/SAConstants+Private.h @@ -144,6 +144,7 @@ extern NSNotificationName const SA_TRACK_LOGOUT_NOTIFICATION; extern NSNotificationName const SA_TRACK_IDENTIFY_NOTIFICATION; extern NSNotificationName const SA_TRACK_RESETANONYMOUSID_NOTIFICATION; extern NSNotificationName const SA_TRACK_EVENT_H5_NOTIFICATION; +extern NSNotificationName const SA_TRACK_Set_Server_URL_NOTIFICATION; #pragma mark - ABTest related notifications /// 注入打通 bridge @@ -198,3 +199,11 @@ extern NSString * const kRandomTimeKey; extern NSString * const kStartDeviceTimeKey; extern NSString * const kSARemoteConfigSupportTransportEncryptKey; extern NSString * const kSARemoteConfigConfigsKey; + +//SAT Remarketing +extern NSString * const kSAAppInteractEventTimeIntervalKey; +extern NSString * const kSAAppInteractEventName; +extern NSString * const kSAHasTrackInstallation; +extern NSString * const kSAHasTrackInstallationDisableCallback; +extern NSString * const kSAEventPropertyHasInstalledApp; +extern NSString * const kSAEventPropertyAwakeFromDeeplink; diff --git a/SensorsAnalyticsSDK/Core/SAConstants.m b/SensorsAnalyticsSDK/Core/SAConstants.m index 25c037f1..6ff13e2d 100644 --- a/SensorsAnalyticsSDK/Core/SAConstants.m +++ b/SensorsAnalyticsSDK/Core/SAConstants.m @@ -164,6 +164,7 @@ void sensorsdata_dispatch_safe_sync(dispatch_queue_t queue,DISPATCH_NOESCAPE dis NSNotificationName const SA_TRACK_IDENTIFY_NOTIFICATION = @"SensorsAnalyticsTrackIdentifyNotification"; NSNotificationName const SA_TRACK_RESETANONYMOUSID_NOTIFICATION = @"SensorsAnalyticsTrackResetAnonymousIdNotification"; NSNotificationName const SA_TRACK_EVENT_H5_NOTIFICATION = @"SensorsAnalyticsTrackEventFromH5Notification"; +NSNotificationName const SA_TRACK_Set_Server_URL_NOTIFICATION = @"SensorsAnalyticsSetServerUrlNotification"; #pragma mark - ABTest related notifications NSNotificationName const SA_H5_BRIDGE_NOTIFICATION = @"SensorsAnalyticsRegisterJavaScriptBridgeNotification"; @@ -223,3 +224,11 @@ void sensorsdata_dispatch_safe_sync(dispatch_queue_t queue,DISPATCH_NOESCAPE dis NSString * const kStartDeviceTimeKey = @"startDeviceTime"; NSString * const kSARemoteConfigSupportTransportEncryptKey = @"supportTransportEncrypt"; NSString * const kSARemoteConfigConfigsKey = @"configs"; + +//SAT Remarketing +NSString * const kSAAppInteractEventTimeIntervalKey = @"appInteract_timestamp"; +NSString * const kSAAppInteractEventName = @"$AppInteract"; +NSString * const kSAHasTrackInstallation = @"HasTrackInstallation"; +NSString * const kSAHasTrackInstallationDisableCallback = @"HasTrackInstallationWithDisableCallback"; +NSString * const kSAEventPropertyHasInstalledApp = @"$sat_has_installed_app"; +NSString * const kSAEventPropertyAwakeFromDeeplink = @"$sat_awake_from_deeplink"; diff --git a/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m b/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m index 710f0f43..0b849776 100755 --- a/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m +++ b/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m @@ -64,7 +64,7 @@ #import "SALimitKeyManager.h" #import "NSDictionary+SACopyProperties.h" -#define VERSION @"4.5.22" +#define VERSION @"4.5.23" void *SensorsAnalyticsQueueTag = &SensorsAnalyticsQueueTag; @@ -404,6 +404,7 @@ - (void)setServerUrl:(NSString *)serverUrl { // macOS 暂不支持远程控制,即不支持 setServerUrl: isRequestRemoteConfig: 接口 dispatch_async(self.serialQueue, ^{ self.configOptions.serverURL = serverUrl; + [[NSNotificationCenter defaultCenter] postNotificationName:SA_TRACK_Set_Server_URL_NOTIFICATION object:nil]; }); #else [self setServerUrl:serverUrl isRequestRemoteConfig:NO]; @@ -423,7 +424,8 @@ - (void)setServerUrl:(NSString *)serverUrl isRequestRemoteConfig:(BOOL)isRequest dispatch_async(self.serialQueue, ^{ if (![self.configOptions.serverURL isEqualToString:serverUrl]) { self.configOptions.serverURL = serverUrl; - + [[NSNotificationCenter defaultCenter] postNotificationName:SA_TRACK_Set_Server_URL_NOTIFICATION object:nil]; + // 更新数据接收地址 [SAModuleManager.sharedInstance updateServerURL:serverUrl]; } diff --git a/SensorsAnalyticsSDK/Core/Utils/SACommonUtility.h b/SensorsAnalyticsSDK/Core/Utils/SACommonUtility.h index 9e24b99e..9139bbe8 100644 --- a/SensorsAnalyticsSDK/Core/Utils/SACommonUtility.h +++ b/SensorsAnalyticsSDK/Core/Utils/SACommonUtility.h @@ -37,5 +37,8 @@ /// 计算 hash + (NSString *)hashStringWithData:(NSData *)data; - +#if TARGET_OS_IOS +/// $ios_install_source ++ (NSString *)appInstallSource; +#endif @end diff --git a/SensorsAnalyticsSDK/Core/Utils/SACommonUtility.m b/SensorsAnalyticsSDK/Core/Utils/SACommonUtility.m index 707ea3d7..087dde03 100644 --- a/SensorsAnalyticsSDK/Core/Utils/SACommonUtility.m +++ b/SensorsAnalyticsSDK/Core/Utils/SACommonUtility.m @@ -24,6 +24,7 @@ #import "SACommonUtility.h" #import "SAValidator.h" +#import "SAIdentifier.h" #import @implementation SACommonUtility @@ -88,4 +89,16 @@ + (NSString *)hashStringWithData:(NSData *)data { return [hashNumber stringValue]; } +#if TARGET_OS_IOS ++ (NSString *)appInstallSource { + NSMutableDictionary *sources = [NSMutableDictionary dictionary]; + sources[@"idfa"] = [SAIdentifier idfa]; + sources[@"idfv"] = [SAIdentifier idfv]; + NSMutableArray *result = [NSMutableArray array]; + for (NSString *key in sources.allKeys) { + [result addObject:[NSString stringWithFormat:@"%@=%@", key, sources[key]]]; + } + return [result componentsJoinedByString:@"##"]; +} +#endif @end diff --git a/SensorsAnalyticsSDK/Deeplink/SAAdvertisingConfig.h b/SensorsAnalyticsSDK/Deeplink/SAAdvertisingConfig.h index 3cb6b286..db627bd7 100644 --- a/SensorsAnalyticsSDK/Deeplink/SAAdvertisingConfig.h +++ b/SensorsAnalyticsSDK/Deeplink/SAAdvertisingConfig.h @@ -25,10 +25,14 @@ NS_ASSUME_NONNULL_BEGIN @interface SAAdvertisingConfig : NSObject -- (instancetype)init NS_UNAVAILABLE; - - (instancetype)initWithServerUrl:(NSString *)serverUrl events:(NSArray*)events secretKey:(nullable SASecretKey *)key; +/// enable remarketing or not, default is NO +@property (nonatomic, assign) BOOL enableRemarketing; + +/// url that wakeup app, pass the url to SDK in case that you delay init SDK +@property (nonatomic, copy) NSString *wakeupUrl; + @end NS_ASSUME_NONNULL_END diff --git a/SensorsAnalyticsSDK/Deeplink/SAAdvertisingConfig.m b/SensorsAnalyticsSDK/Deeplink/SAAdvertisingConfig.m index 3ec9a6de..dea68b50 100644 --- a/SensorsAnalyticsSDK/Deeplink/SAAdvertisingConfig.m +++ b/SensorsAnalyticsSDK/Deeplink/SAAdvertisingConfig.m @@ -53,6 +53,8 @@ - (nonnull id)copyWithZone:(nullable NSZone *)zone { config.adsServerUrl = self.adsServerUrl; config.adsEvents = self.adsEvents; config.adsSecretKey = self.adsSecretKey; + config.enableRemarketing = self.enableRemarketing; + config.wakeupUrl = self.wakeupUrl; return config; } diff --git a/SensorsAnalyticsSDK/Deeplink/SAAppInteractTracker.h b/SensorsAnalyticsSDK/Deeplink/SAAppInteractTracker.h new file mode 100644 index 00000000..7fc83e63 --- /dev/null +++ b/SensorsAnalyticsSDK/Deeplink/SAAppInteractTracker.h @@ -0,0 +1,32 @@ +// +// SAAppInteractTracker.h +// SensorsAnalyticsSDK +// +// Created by 陈玉国 on 2023/10/23. +// Copyright © 2015-2023 Sensors Data Co., Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface SAAppInteractTracker : NSObject + +@property (nonatomic, assign) BOOL awakeFromDeeplink; +@property (nonatomic, copy) NSString *wakeupUrl; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SensorsAnalyticsSDK/Deeplink/SAAppInteractTracker.m b/SensorsAnalyticsSDK/Deeplink/SAAppInteractTracker.m new file mode 100644 index 00000000..14d972a0 --- /dev/null +++ b/SensorsAnalyticsSDK/Deeplink/SAAppInteractTracker.m @@ -0,0 +1,106 @@ +// +// SAAppInteractTracker.m +// SensorsAnalyticsSDK +// +// Created by 陈玉国 on 2023/10/23. +// Copyright © 2015-2023 Sensors Data Co., Ltd. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if ! __has_feature(objc_arc) +#error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag on this file. +#endif + +#import "SAAppInteractTracker.h" +#import "SAAppLifecycle.h" +#import "SAConstants+Private.h" +#import "SensorsAnalyticsSDK.h" +#import "SAStoreManager.h" +#import "SALog.h" +#import "SAIdentifier.h" +#import "SACommonUtility.h" + +@interface SAAppInteractTracker () + +@property (nonatomic, assign) BOOL hasInstalledApp; + +@end + +@implementation SAAppInteractTracker + +- (instancetype)init { + if (self = [super init]) { + [self addListener]; + _hasInstalledApp = [self isAppInstalled]; + } + return self; +} + +- (void)addListener { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appLifecycleStateDidChange:) name:kSAAppLifecycleStateDidChangeNotification object:nil]; +} + +- (void)removeListener { + [[NSNotificationCenter defaultCenter] removeObserver:self name:kSAAppLifecycleStateDidChangeNotification object:nil]; +} + +- (void)appLifecycleStateDidChange:(NSNotification *)sender { + SAAppLifecycleState newState = [sender.userInfo[kSAAppLifecycleNewStateKey] integerValue]; + SAAppLifecycleState oldState = [sender.userInfo[kSAAppLifecycleOldStateKey] integerValue]; + if (!self.awakeFromDeeplink && oldState == SAAppLifecycleStateInit && newState == SAAppLifecycleStateStart) { + self.awakeFromDeeplink = self.awakeFromDeeplink ?: self.wakeupUrl ? YES : NO; + } + if (newState == SAAppLifecycleStateStart) { + [self trackAppInteract]; + self.awakeFromDeeplink = NO; + self.hasInstalledApp = [self isAppInstalled]; + } +} + +- (BOOL)shouldTrackAppInteract { + NSTimeInterval lastAppInteractTimeInterval = [[SAStoreManager sharedInstance] doubleForKey:kSAAppInteractEventTimeIntervalKey]; + NSTimeInterval nowTimeInterval = [[NSDate date] timeIntervalSince1970]; + if (lastAppInteractTimeInterval >= nowTimeInterval) { + SALogError(@"Incorrect timeInterval for last AppInteract event"); + return NO; + } + if (lastAppInteractTimeInterval == 0) { + return YES; + } + NSDate *lastAppInteractDate = [NSDate dateWithTimeIntervalSince1970:lastAppInteractTimeInterval]; + BOOL inToday = [[NSCalendar currentCalendar] isDateInToday:lastAppInteractDate]; + return !inToday; +} + +- (void)trackAppInteract { + if (![self shouldTrackAppInteract]) { + return; + } + BOOL hasInstalledApp = self.hasInstalledApp; + BOOL awakeFromDeeplink = self.awakeFromDeeplink; + [[SensorsAnalyticsSDK sharedInstance] track:kSAAppInteractEventName withProperties:@{kSAEventPropertyHasInstalledApp: @(hasInstalledApp), kSAEventPropertyAwakeFromDeeplink: @(awakeFromDeeplink), kSAEventPropertyInstallSource: [SACommonUtility appInstallSource]}]; + NSTimeInterval timestamp = [[NSDate date] timeIntervalSince1970]; + [[SAStoreManager sharedInstance] setDouble:timestamp forKey:kSAAppInteractEventTimeIntervalKey]; +} + +- (BOOL)isAppInstalled { + SAStoreManager *manager = [SAStoreManager sharedInstance]; + return [manager boolForKey:kSAHasTrackInstallationDisableCallback] || [manager boolForKey:kSAHasTrackInstallation]; +} + +- (void)dealloc { + [self removeListener]; +} + +@end diff --git a/SensorsAnalyticsSDK/Deeplink/SADeepLinkProcessor.h b/SensorsAnalyticsSDK/Deeplink/SADeepLinkProcessor.h index 566479cb..f177a0fd 100644 --- a/SensorsAnalyticsSDK/Deeplink/SADeepLinkProcessor.h +++ b/SensorsAnalyticsSDK/Deeplink/SADeepLinkProcessor.h @@ -70,9 +70,6 @@ typedef BOOL(^SADeepLinkCompletion)(SADeepLinkObject *object); /// 获取最后一次的渠道归因参数 - (NSDictionary *)acquireLatestChannels:(NSDictionary *)dictionary; -/// 设备信息 -- (NSString *)appInstallSource; - @end @interface SADeepLinkProcessorFactory : NSObject diff --git a/SensorsAnalyticsSDK/Deeplink/SADeepLinkProcessor.m b/SensorsAnalyticsSDK/Deeplink/SADeepLinkProcessor.m index f8be9b21..61d28be1 100644 --- a/SensorsAnalyticsSDK/Deeplink/SADeepLinkProcessor.m +++ b/SensorsAnalyticsSDK/Deeplink/SADeepLinkProcessor.m @@ -26,11 +26,11 @@ #import "SADeepLinkConstants.h" #import "SensorsAnalyticsSDK+Private.h" #import "SAConstants+Private.h" -#import "SAIdentifier.h" #import "SAQueryDeepLinkProcessor.h" #import "SARequestDeepLinkProcessor.h" #import "SADeepLinkEventProcessor.h" #import "SADeferredDeepLinkProcessor.h" +#import "SACommonUtility.h" @interface SADeepLinkLaunchEventObject : SAPresetEventObject @@ -88,22 +88,11 @@ - (NSDictionary *)presetKeyPrefix:(NSString *)presetKeyPrefix customKeyPrefix:(N return channels; } -- (NSString *)appInstallSource { - NSMutableDictionary *sources = [NSMutableDictionary dictionary]; - sources[@"idfa"] = [SAIdentifier idfa]; - sources[@"idfv"] = [SAIdentifier idfv]; - NSMutableArray *result = [NSMutableArray array]; - for (NSString *key in sources.allKeys) { - [result addObject:[NSString stringWithFormat:@"%@=%@", key, sources[key]]]; - } - return [result componentsJoinedByString:@"##"]; -} - - (void)trackDeepLinkLaunch:(NSDictionary *)properties { SADeepLinkLaunchEventObject *object = [[SADeepLinkLaunchEventObject alloc] initWithEventId:kSAAppDeepLinkLaunchEvent]; NSMutableDictionary *eventProperties = [NSMutableDictionary dictionary]; eventProperties[kSAEventPropertyDeepLinkURL] = self.URL.absoluteString; - eventProperties[kSAEventPropertyInstallSource] = [self appInstallSource]; + eventProperties[kSAEventPropertyInstallSource] = [SACommonUtility appInstallSource]; if (properties) { [eventProperties addEntriesFromDictionary:properties]; } diff --git a/SensorsAnalyticsSDK/Deeplink/SADeeplinkManager.m b/SensorsAnalyticsSDK/Deeplink/SADeeplinkManager.m index ffb7e44e..530d3a44 100644 --- a/SensorsAnalyticsSDK/Deeplink/SADeeplinkManager.m +++ b/SensorsAnalyticsSDK/Deeplink/SADeeplinkManager.m @@ -43,6 +43,7 @@ #import "SAPropertyPluginManager.h" #import "SALatestUtmPropertyPlugin.h" #import "SADeviceWhiteList.h" +#import "SAAppInteractTracker.h" @interface SADeepLinkManager () @@ -58,6 +59,10 @@ @interface SADeepLinkManager () @property (nonatomic, strong) SADeviceWhiteList *whiteList; +@property (nonatomic, strong) SAAppInteractTracker *appInteractTracker; + +@property (nonatomic, assign) BOOL hasInstalledApp; + @end @implementation SADeepLinkManager @@ -97,6 +102,7 @@ - (instancetype)init { [self disableDeferredDeepLink]; } _whiteList = [[SADeviceWhiteList alloc] init]; + _hasInstalledApp = [self isAppInstalled]; } return self; } @@ -105,7 +111,7 @@ - (void)appLifecycleStateDidChange:(NSNotification *)sender { SAAppLifecycleState newState = [sender.userInfo[kSAAppLifecycleNewStateKey] integerValue]; if (newState == SAAppLifecycleStateEnd) { [self disableDeferredDeepLink]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:kSAAppLifecycleStateDidChangeNotification object:nil]; + self.hasInstalledApp = [self isAppInstalled]; } } @@ -134,6 +140,26 @@ - (void)setConfigOptions:(SAConfigOptions *)configOptions { self.enable = configOptions.enableDeepLink; } +- (void)setEnable:(BOOL)enable { + _enable = enable; + self.appInteractTracker = enable && self.configOptions.advertisingConfig.enableRemarketing ? [[SAAppInteractTracker alloc] init] : nil; + if (!self.appInteractTracker) { + return; + } + NSString *wakeupUrl = self.configOptions.advertisingConfig.wakeupUrl; + if (!wakeupUrl || ![wakeupUrl isKindOfClass:[NSString class]]) { + return; + } + NSURL *wakeupURL = [NSURL URLWithString:wakeupUrl]; + if (!wakeupURL) { + return; + } + if (![self canHandleURL:wakeupURL]) { + return; + } + self.appInteractTracker.wakeupUrl = wakeupUrl; +} + - (void)filterValidSourceChannelKeys:(NSArray *)sourceChannels { NSSet *reservedPropertyName = sensorsdata_reserved_properties(); NSMutableSet *set = [[NSMutableSet alloc] init]; @@ -272,6 +298,13 @@ - (BOOL)canHandleURL:(NSURL *)url { if ([self.whiteList canHandleURL:url]) { return YES; } + + BOOL canWakeUp = [self canWakeUpWithUrl:url]; + self.appInteractTracker.awakeFromDeeplink = canWakeUp; + return canWakeUp; +} + +- (BOOL)canWakeUpWithUrl:(NSURL *)url { SADeepLinkProcessor *processor = [SADeepLinkProcessorFactory processorFromURL:url customChannelKeys:self.customChannelKeys]; return processor.canWakeUp; } @@ -301,7 +334,7 @@ - (BOOL)handleDeepLinkURL:(NSURL *)url { SADeepLinkProcessor *processor = [SADeepLinkProcessorFactory processorFromURL:url customChannelKeys:self.customChannelKeys]; processor.delegate = self; - [processor startWithProperties:nil]; + [processor startWithProperties:@{kSAEventPropertyHasInstalledApp: @(self.hasInstalledApp)}]; return processor.canWakeUp; } @@ -312,7 +345,14 @@ - (void)trackDeepLinkLaunchWithURL:(NSString *)url { return; } SADeepLinkEventProcessor *processor = [[SADeepLinkEventProcessor alloc] init]; - [processor startWithProperties:(url ? @{kSAEventPropertyDeepLinkURL: url} : nil)]; + NSMutableDictionary *properties = [NSMutableDictionary dictionary]; + if (self.configOptions.advertisingConfig.enableRemarketing) { + SAStoreManager *manager = [SAStoreManager sharedInstance]; + BOOL hasInstallApp = [manager boolForKey:kSAHasTrackInstallationDisableCallback] || [manager boolForKey:kSAHasTrackInstallation]; + properties[kSAEventPropertyHasInstalledApp] = @(hasInstallApp); + } + properties[kSAEventPropertyDeepLinkURL] = url; + [processor startWithProperties:properties]; } - (void)requestDeferredDeepLink:(NSDictionary *)properties { @@ -351,4 +391,9 @@ - (SADeepLinkCompletion)sendChannels:(NSDictionary *)channels latestChannels:(NS return self.oldCompletion; } +- (BOOL)isAppInstalled { + SAStoreManager *manager = [SAStoreManager sharedInstance]; + return [manager boolForKey:kSAHasTrackInstallationDisableCallback] || [manager boolForKey:kSAHasTrackInstallation]; +} + @end diff --git a/SensorsAnalyticsSDK/Deeplink/SADeferredDeepLinkProcessor.m b/SensorsAnalyticsSDK/Deeplink/SADeferredDeepLinkProcessor.m index 1d5d4640..db92dcb3 100644 --- a/SensorsAnalyticsSDK/Deeplink/SADeferredDeepLinkProcessor.m +++ b/SensorsAnalyticsSDK/Deeplink/SADeferredDeepLinkProcessor.m @@ -30,6 +30,7 @@ #import "SAUserAgent.h" #import "SANetworkInfoPropertyPlugin.h" #import "SAConstants+Private.h" +#import "SACommonUtility.h" @implementation SADeferredDeepLinkProcessor @@ -61,7 +62,7 @@ - (void)requestForDeferredDeepLink:(NSURLRequest *)request { properties[kSAEventPropertyDuration] = [NSString stringWithFormat:@"%.3f", interval]; properties[kSAEventPropertyADMatchType] = @"deferred deeplink"; - NSData *deviceInfoData = [[self appInstallSource] dataUsingEncoding:NSUTF8StringEncoding]; + NSData *deviceInfoData = [[SACommonUtility appInstallSource] dataUsingEncoding:NSUTF8StringEncoding]; NSString *base64 = [deviceInfoData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]; properties[kSAEventPropertyADDeviceInfo] = base64; @@ -150,7 +151,7 @@ - (NSURLRequest *)buildRequest:(NSString *)userAgent properties:(NSDictionary *) } NSMutableDictionary *params = [NSMutableDictionary dictionary]; - NSData *data = [[self appInstallSource] dataUsingEncoding:NSUTF8StringEncoding]; + NSData *data = [[SACommonUtility appInstallSource] dataUsingEncoding:NSUTF8StringEncoding]; NSString *base64 = [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]; params[kSARequestPropertyIDs] = base64; params[kSARequestPropertyUA] = userAgent;