diff --git a/SensorsAnalyticsSDK.podspec b/SensorsAnalyticsSDK.podspec index 130e5dcf..51779f0c 100644 --- a/SensorsAnalyticsSDK.podspec +++ b/SensorsAnalyticsSDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "SensorsAnalyticsSDK" - s.version = "4.7.2" + s.version = "4.8.0" 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 75dbf207..3ad10304 100644 --- a/SensorsAnalyticsSDK.xcodeproj/project.pbxproj +++ b/SensorsAnalyticsSDK.xcodeproj/project.pbxproj @@ -140,6 +140,8 @@ 4DC4815828B775B60068D5F4 /* SAVisualizedElementView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DC4815228B775B60068D5F4 /* SAVisualizedElementView.m */; }; 4DC4815928B775B60068D5F4 /* SAFlutterPluginBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DC4815328B775B60068D5F4 /* SAFlutterPluginBridge.h */; }; 4DC4815A28B775B60068D5F4 /* SAFlutterElementView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DC4815428B775B60068D5F4 /* SAFlutterElementView.m */; }; + 4DC579CD2C85D3CA00486E4D /* SAMacHistoryFileStorePlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DC579CB2C85D3CA00486E4D /* SAMacHistoryFileStorePlugin.h */; }; + 4DC579CE2C85D3CA00486E4D /* SAMacHistoryFileStorePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DC579CC2C85D3CA00486E4D /* SAMacHistoryFileStorePlugin.m */; }; 4DD1282025F87225008C0B1E /* UIView+SAVisualizedViewPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD1281D25F87225008C0B1E /* UIView+SAVisualizedViewPath.h */; }; 4DD1282125F87225008C0B1E /* SAVisualizedViewPathProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD1281E25F87225008C0B1E /* SAVisualizedViewPathProperty.h */; }; 4DD1282225F87225008C0B1E /* UIView+SAVisualizedViewPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DD1281F25F87225008C0B1E /* UIView+SAVisualizedViewPath.m */; }; @@ -732,6 +734,8 @@ 4DC4815228B775B60068D5F4 /* SAVisualizedElementView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAVisualizedElementView.m; sourceTree = ""; }; 4DC4815328B775B60068D5F4 /* SAFlutterPluginBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SAFlutterPluginBridge.h; sourceTree = ""; }; 4DC4815428B775B60068D5F4 /* SAFlutterElementView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAFlutterElementView.m; sourceTree = ""; }; + 4DC579CB2C85D3CA00486E4D /* SAMacHistoryFileStorePlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SAMacHistoryFileStorePlugin.h; sourceTree = ""; }; + 4DC579CC2C85D3CA00486E4D /* SAMacHistoryFileStorePlugin.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAMacHistoryFileStorePlugin.m; sourceTree = ""; }; 4DD1281D25F87225008C0B1E /* UIView+SAVisualizedViewPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+SAVisualizedViewPath.h"; sourceTree = ""; }; 4DD1281E25F87225008C0B1E /* SAVisualizedViewPathProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SAVisualizedViewPathProperty.h; sourceTree = ""; }; 4DD1281F25F87225008C0B1E /* UIView+SAVisualizedViewPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+SAVisualizedViewPath.m"; sourceTree = ""; }; @@ -1756,6 +1760,8 @@ 883ED1A927699A3500A0706A /* SABaseStoreManager.m */, 88EC2DF5275768DE00EF9778 /* SAFileStorePlugin.h */, 88EC2DF6275768DE00EF9778 /* SAFileStorePlugin.m */, + 4DC579CB2C85D3CA00486E4D /* SAMacHistoryFileStorePlugin.h */, + 4DC579CC2C85D3CA00486E4D /* SAMacHistoryFileStorePlugin.m */, 88EC2DFD2757693600EF9778 /* SAUserDefaultsStorePlugin.h */, 88EC2DFE2757693600EF9778 /* SAUserDefaultsStorePlugin.m */, 88EC2DF9275768EE00EF9778 /* SAAESStorePlugin.h */, @@ -2485,6 +2491,7 @@ F22E1B1B26A55C8A0033A748 /* SAAppPageLeaveTracker.h in Headers */, 4DD1285925F872A4008C0B1E /* SAEnumDescription.h in Headers */, 88F5537927FD6A5400D95E7C /* SANodeObject.h in Headers */, + 4DC579CD2C85D3CA00486E4D /* SAMacHistoryFileStorePlugin.h in Headers */, 4DD1285D25F872A4008C0B1E /* SAVisualizedConnection.h in Headers */, 88E6BEDD278ECE5E006B1E4C /* SAAppVersionPropertyPlugin.h in Headers */, A8356DCF2656459A00FD64AA /* SAGestureViewProcessorFactory.h in Headers */, @@ -2916,6 +2923,7 @@ A8CC22332685E50C00E96A03 /* SARemoteConfigEventObject.m in Sources */, 8809805827FDA85E00EB2B3D /* SARemoteConfigInterceptor.m in Sources */, 88BC3A01281543E000A98EDA /* SAPropertyPlugin.m in Sources */, + 4DC579CE2C85D3CA00486E4D /* SAMacHistoryFileStorePlugin.m in Sources */, 4DD1285E25F872A4008C0B1E /* SAVisualizedObjectSerializerManager.m in Sources */, F2E4ABA626ECAC5400BA7F01 /* SensorsAnalyticsSDK+DeepLink.m in Sources */, 4DD1286D25F872A4008C0B1E /* SAVisualizedManager.m in Sources */, diff --git a/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m b/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m index 8387a6db..36caf3a8 100755 --- a/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m +++ b/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m @@ -63,12 +63,13 @@ #import "SAEventStore.h" #import "SALimitKeyManager.h" #import "NSDictionary+SACopyProperties.h" +#import "SAMacHistoryFileStorePlugin.h" #if TARGET_OS_IOS || TARGET_OS_TV #import #endif -#define VERSION @"4.7.2" +#define VERSION @"4.8.0" void *SensorsAnalyticsQueueTag = &SensorsAnalyticsQueueTag; @@ -262,6 +263,11 @@ - (void)dealloc { } - (void)resgisterStorePlugins { +#if TARGET_OS_OSX + SAMacHistoryFileStorePlugin *macFilePlugin = [[SAMacHistoryFileStorePlugin alloc] init]; + [[SAStoreManager sharedInstance] registerStorePlugin:macFilePlugin]; +#endif + SAFileStorePlugin *filePlugin = [[SAFileStorePlugin alloc] init]; [[SAStoreManager sharedInstance] registerStorePlugin:filePlugin]; diff --git a/SensorsAnalyticsSDK/Store/SABaseStoreManager.h b/SensorsAnalyticsSDK/Store/SABaseStoreManager.h index ed89315c..a374965d 100644 --- a/SensorsAnalyticsSDK/Store/SABaseStoreManager.h +++ b/SensorsAnalyticsSDK/Store/SABaseStoreManager.h @@ -29,6 +29,8 @@ typedef void(^SAStoreManagerCompletion)(id _Nullable object); - (void)registerStorePlugin:(id)plugin; +- (void)unregisterStorePluginWithPluginClass:(Class)cla; + #pragma mark - get - (nullable id)objectForKey:(NSString *)key; diff --git a/SensorsAnalyticsSDK/Store/SABaseStoreManager.m b/SensorsAnalyticsSDK/Store/SABaseStoreManager.m index 8f8ad244..967e55f2 100644 --- a/SensorsAnalyticsSDK/Store/SABaseStoreManager.m +++ b/SensorsAnalyticsSDK/Store/SABaseStoreManager.m @@ -92,6 +92,7 @@ - (id)objForKey:(NSString *)key { return nil; } + #pragma mark - public - (void)registerStorePlugin:(id)plugin { @@ -108,6 +109,20 @@ - (void)registerStorePlugin:(id)plugin { }); } +- (void)unregisterStorePluginWithPluginClass:(Class)cla { + if (!cla) { + return; + } + dispatch_async(self.serialQueue, ^{ + [self.plugins enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if ([obj isKindOfClass:cla]) { + [self.plugins removeObject:obj]; + *stop = YES; + } + }]; + }); +} + #pragma mark - get - (id)objectForKey:(NSString *)key { diff --git a/SensorsAnalyticsSDK/Store/SAFileStorePlugin.m b/SensorsAnalyticsSDK/Store/SAFileStorePlugin.m index c7ad14ac..34b6edc1 100644 --- a/SensorsAnalyticsSDK/Store/SAFileStorePlugin.m +++ b/SensorsAnalyticsSDK/Store/SAFileStorePlugin.m @@ -23,6 +23,11 @@ #endif #import "SAFileStorePlugin.h" +#import "SAMacHistoryFileStorePlugin.h" + +#if __has_include("SAStoreManager.h") +#import "SAStoreManager.h" +#endif static NSString * const kSAFileStorePluginType = @"cn.sensorsdata.File."; @@ -31,8 +36,8 @@ @implementation SAFileStorePlugin + (NSString *)filePath:(NSString *)key { NSString *name = [key stringByReplacingOccurrencesOfString:kSAFileStorePluginType withString:@""]; #if TARGET_OS_OSX - // 兼容老版 mac SDK 的本地数据 - NSString *filename = [NSString stringWithFormat:@"com.sensorsdata.analytics.mini.SensorsAnalyticsSDK.%@.plist", name]; + NSString *appId = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; + NSString *filename = [NSString stringWithFormat:@"sensorsanalytics-%@-%@.plist", appId, name]; #else NSString *filename = [NSString stringWithFormat:@"sensorsanalytics-%@.plist", name]; #endif @@ -45,7 +50,6 @@ + (NSString *)filePath:(NSString *)key { stringByAppendingPathComponent:filename]; #endif - } #pragma mark - SAStorePlugin @@ -58,8 +62,32 @@ - (NSString *)type { return kSAFileStorePluginType; } +// macOS 历史数据迁移 - (void)upgradeWithOldPlugin:(nonnull id)oldPlugin { + if (![oldPlugin isKindOfClass:SAMacHistoryFileStorePlugin.class]) { + return; + } + + NSArray *storeKeys = [self storeKeys]; + for (NSString *key in storeKeys) { + NSString *oldStoreKey = [NSString stringWithFormat:@"%@%@", oldPlugin.type, key]; + // 读取旧数据 + id historyValue = [oldPlugin objectForKey:oldStoreKey]; + if (!historyValue) { + continue; + } + + NSString *newStoreKey = [NSString stringWithFormat:@"%@%@", self.type, key]; + // 数据迁移到新插件 + [self setObject:historyValue forKey:newStoreKey]; + // 删除历史数据 + [oldPlugin removeObjectForKey:oldStoreKey]; + } +#if __has_include("SAStoreManager.h") + // 迁移完成或,移除旧插件 + [SAStoreManager.sharedInstance unregisterStorePluginWithPluginClass:SAMacHistoryFileStorePlugin.class]; +#endif } - (nullable id)objectForKey:(nonnull NSString *)key { diff --git a/SensorsAnalyticsSDK/Store/SAMacHistoryFileStorePlugin.h b/SensorsAnalyticsSDK/Store/SAMacHistoryFileStorePlugin.h new file mode 100644 index 00000000..eeb4a359 --- /dev/null +++ b/SensorsAnalyticsSDK/Store/SAMacHistoryFileStorePlugin.h @@ -0,0 +1,38 @@ +// +// SAMacHistoryFileStorePlugin.h +// SensorsAnalyticsSDK +// +// Created by  储强盛 on 2024/9/2. +// Copyright © 2015-2024 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 +#import "SAStorePlugin.h" + + +NS_ASSUME_NONNULL_BEGIN + +// macOS 历史文件迁移 +@interface SAMacHistoryFileStorePlugin : NSObject + + ++ (NSString *)filePath:(NSString *)key; + +- (NSArray *)storeKeys; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SensorsAnalyticsSDK/Store/SAMacHistoryFileStorePlugin.m b/SensorsAnalyticsSDK/Store/SAMacHistoryFileStorePlugin.m new file mode 100644 index 00000000..02a2179c --- /dev/null +++ b/SensorsAnalyticsSDK/Store/SAMacHistoryFileStorePlugin.m @@ -0,0 +1,92 @@ +// +// SAMacHistoryFileStorePlugin.m +// SensorsAnalyticsSDK +// +// Created by  储强盛 on 2024/9/2. +// Copyright © 2015-2024 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 "SAMacHistoryFileStorePlugin.h" + +static NSString * const kSAMacHistoryFileStorePluginType = @"cn.sensorsdata.File.Mac."; + + +@implementation SAMacHistoryFileStorePlugin + + ++ (NSString *)filePath:(NSString *)key { + NSString *name = [key stringByReplacingOccurrencesOfString:kSAMacHistoryFileStorePluginType withString:@""]; + // 兼容老版 macOS SDK 的本地数据 + NSString *filename = [NSString stringWithFormat:@"com.sensorsdata.analytics.mini.SensorsAnalyticsSDK.%@.plist", name]; + return [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject] + stringByAppendingPathComponent:filename]; +} + +#pragma mark - SAStorePlugin + +- (NSArray *)storeKeys { + return @[@"$channel_device_info", @"login_id", @"distinct_id", @"com.sensorsdata.loginidkey", @"com.sensorsdata.identities", @"first_day", @"super_properties", @"latest_utms", @"SAEncryptSecretKey", @"SAVisualPropertiesConfig", @"SASessionModel"]; +} + +- (NSString *)type { + return kSAMacHistoryFileStorePluginType; +} + +- (void)upgradeWithOldPlugin:(nonnull id)oldPlugin { +} + +- (nullable id)objectForKey:(nonnull NSString *)key { + if (!key) { + return nil; + } + NSString *filePath = [SAMacHistoryFileStorePlugin filePath:key]; + @try { + return [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + } @catch (NSException *exception) { + return nil; + } +} + +- (void)setObject:(nullable id)value forKey:(nonnull NSString *)key { + if (!key) { + return; + } + // 屏蔽非法数据类型,防止野指针造成异常 + if(!value && ![value conformsToProtocol:@protocol(NSCoding)]) { + return; + } + + NSString *filePath = [SAMacHistoryFileStorePlugin filePath:key]; + + // macOS10.13 不包含 NSFileProtectionComplete + NSDictionary *protection = [NSDictionary dictionary]; + + [[NSFileManager defaultManager] setAttributes:protection + ofItemAtPath:filePath + error:nil]; + [NSKeyedArchiver archiveRootObject:value toFile:filePath]; +} + +- (void)removeObjectForKey:(nonnull NSString *)key { + NSString *filePath = [SAMacHistoryFileStorePlugin filePath:key]; + [[NSFileManager defaultManager] removeItemAtPath:filePath error:NULL]; +} + + +@end