更新GoogleAnalytics pod后App崩溃,求助修复CoreData安全归档问题
解决GoogleAnalytics Pod更新后的CoreData安全归档崩溃问题
这个问题我之前也碰到过,本质是苹果对CoreData可转换属性的安全解码要求升级了——旧版的NSKeyedUnarchiveFromDataTransformer存在安全风险,现在苹果要求改用NSSecureUnarchiveFromData或它的子类,而新版GoogleAnalytics SDK里的GAIHit实体还在使用不安全的转换器配置,所以触发了警告甚至崩溃。
下面是具体的解决步骤:
步骤1:自定义安全转换器
我们需要创建一个继承自NSSecureUnarchiveFromDataTransformer的子类,确保它能安全解码GAIHit的parameters属性(通常是字典类型,包含字符串、数字等基础类型)。
Swift版本
import CoreData class SecureDictionaryTransformer: NSSecureUnarchiveFromDataTransformer { // 声明允许的顶层类型,覆盖父类的默认配置 override class var allowedTopLevelClasses: [AnyClass] { return [NSDictionary.self, NSString.self, NSNumber.self, NSArray.self] } // 定义转换器的唯一标识名称 static let transformerName = NSValueTransformerName(rawValue: "SecureDictionaryTransformer") // 注册转换器的方法 static func register() { let transformer = SecureDictionaryTransformer() ValueTransformer.setValueTransformer(transformer, forName: transformerName) } }
Objective-C版本
#import <CoreData/CoreData.h> @interface SecureDictionaryTransformer : NSSecureUnarchiveFromDataTransformer + (void)registerTransformer; @end @implementation SecureDictionaryTransformer + (NSArray<Class> *)allowedTopLevelClasses { return @[NSDictionary.class, NSString.class, NSNumber.class, NSArray.class]; } + (void)registerTransformer { SecureDictionaryTransformer *transformer = [[SecureDictionaryTransformer alloc] init]; [NSValueTransformer setValueTransformer:transformer forName:NSValueTransformerName(@"SecureDictionaryTransformer")]; } @end
步骤2:在App启动时注册转换器
在App的启动入口(比如AppDelegate的didFinishLaunchingWithOptions方法)里注册我们的自定义转换器,确保CoreData加载前能识别到它。
Swift版本
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 先注册自定义转换器 SecureDictionaryTransformer.register() // 再初始化GoogleAnalytics和CoreData栈 // 你的其他启动代码... return true }
Objective-C版本
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 注册自定义转换器 [SecureDictionaryTransformer registerTransformer]; // 初始化GoogleAnalytics和CoreData栈 // 你的其他启动代码... return YES; }
步骤3:修改GAIHit实体的属性配置
因为GAIHit是GoogleAnalytics SDK内置的CoreData实体,我们无法直接修改它的模型文件,所以需要在运行时动态更新它的parameters属性,指定使用我们的安全转换器。
Swift版本
找到你项目中初始化CoreData栈的位置,在栈初始化完成后添加这段代码:
// 替换成你项目中CoreData容器的实例 if let managedObjectModel = persistentContainer.managedObjectModel as? NSManagedObjectModel { // 获取GAIHit实体 guard let gaiHitEntity = managedObjectModel.entitiesByName["GAIHit"] else { return } // 获取parameters属性 guard let parametersAttr = gaiHitEntity.attributesByName["parameters"]?.mutableCopy() as? NSAttributeDescription else { return } // 设置使用我们的自定义转换器 parametersAttr.valueTransformerName = SecureDictionaryTransformer.transformerName // 更新实体的属性配置 gaiHitEntity.attributesByName["parameters"] = parametersAttr }
Objective-C版本
同样在CoreData栈初始化后添加:
// 替换成你项目的CoreData容器实例 NSManagedObjectModel *model = self.persistentContainer.managedObjectModel; NSEntityDescription *gaiHitEntity = model.entitiesByName[@"GAIHit"]; NSAttributeDescription *parametersAttr = gaiHitEntity.attributesByName[@"parameters"]; NSMutableAttributeDescription *mutableAttr = [parametersAttr mutableCopy]; mutableAttr.valueTransformerName = NSValueTransformerName(@"SecureDictionaryTransformer"); [gaiHitEntity.attributesByName setObject:mutableAttr forKey:@"parameters"];
注意事项
- 确保
allowedTopLevelClasses包含parameters属性中所有可能存储的类型,如果你的项目里还有其他自定义类型,也要把它们加进去(前提是这些类型已经实现了NSSecureCoding协议)。 - 做完这些修改后,建议清理项目的Derived Data,然后重新编译运行,避免缓存问题。
- 这个方案不需要修改GoogleAnalytics的SDK源码,也不需要CoreData的数据迁移,因为我们只是替换了解码方式,数据本身是兼容的。
内容的提问来源于stack exchange,提问作者CanabaltVi
相关产品推荐
相关产品推荐

