你知道iOS是如何获取夜间模式启动图片的缓存路径的吗??百度APP技术团队曾发布过一个深夜黑坑——iOS启动图像异常修复方案。这篇文章分享了一些关于启动图的研究,但是通过文章的内容,我们还是解决不了这个问题:iOS如何获取夜间模式启动图的缓存路径?经过一系列的研究,笔者在模拟器场景下得到了一个解决方案,现分享笔者的研究记录。方案一:尝试通过开机图片的文件名来判断缓存的图片是否属于夜间模式。我们先提炼深夜坑-iOS启动画面异常修复解决方案提供的资料。原文提供了以下两条信息:缓存启动图片的文件名是有规律的,但我们不知道规律。四个启动镜像的文件名├──1FFD332B-EBA0-40C9-8EEE-BEC9AEF7C41A@3x.ktx├──96920D11-6312-4D69-BBDB-AFBB52DBDDB3@3x.ktx├──98F7B5B1-5B3B-478B-93A8-ED3DE6492AD1@3x.ktx└──D9D48845-8565-42CE-A834-479CC9CC8BAD@3x.ktx通过4个文件名,我们可以发现4张图片的命名符合以下规则:xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx结合苹果官方文档NSUUID的内容:`NSUUID`conformtoRFC4122version4andarecreatedwithrandombytes。我们可以得到如下结论:4个文件名都是NSUUID动态生成的文件名,只包含版本4,没有其他有效信息。方案二:通过系统文件分析方案一失败后,我们猜测是iOS通过其他方式保存了夜间模式启动图片的缓存路径信息。经过一系列的测试,笔者找到了applicationState.db文件。applicationState.db系统会通过applicationState.db保存程序状态等各种信息,当然也会包含夜间模式启动图的缓存路径信息。本文分析的文件位于~/Library/Developer/CoreSimulator/Devices/1F9B22C5-E446-??4881-AFE4-3373E3513C59/data/Library/FrontBoard/applicationState.db,其中1F9B22C5-E446-??4881-AFE4-3373E3513C59代表iOS模拟器设备ID。完整的模拟器ID列表可以通过命令plutil-p~/Library/Developer/CoreSimulator/Devices/device_set.plist查看为了方便分析系统文件,本文以iOS14模拟器为目标分析。版本信息如下:(lldb)platformstatusPlatform:ios-simulatorTriple:x86_64h-apple-macosxOSVersion:10.15.6(19G2021)Kernel:DarwinKernelVersion19.6.0:ThuJun1820:49:00PDT2020;root:xnu-6153.141.1~1/RELEASE_name:127.0.0.1WorkingDir:/SDKPath:"/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"节点可用。另外,后续代码会假设Bundle标识为test.SplashTest来分析applicationState.db,首先尝试通过file命令获取applicationState.db。文件类型:文件~/Library/Developer/CoreSimulator/Devices/1F9B22C5-E446-??4881-AFE4-3373E3513C59/data/Library/FrontBoard/applicationState.db输出:SQLite3。xdatabase测试成功,上次使用SQLite版本3032003编写。通过file命令的输出可以看到文件类型为SQLite3.x。db结构,然后通过sqlite相关工具dump文件,我们可以得到如下信息:CREATETABLEkvs(idINTEGERPRIMARYKEY,application_identifierINTREFERENCESapplication_identifier_tab(id),keyINTREFERENCESkey_tab(id),valueBLOB,UNIQUE(application_identifier,key));CREATEINDEXkvs_keysONkvs(key);CREATEINDEXkvs_application_identifiersONkvs(application_identifier);CREATEVIEWkvs_debugASSELECTapplication_identifier_tab.application_identifier,key_tab.key,valueFROMapplication_identifier_tab,key_tab,kvsWHEREkvs.application_identifier=application_identifier_tab.idANDkvs.key=key_tab.id/*kvs_debug(application_identifier,"key",value)*/;application_identifier_tab保存了设备上安装的应用程序列表(id是主键,application_identifier是APP的Bundle标识)key_tab负责Document常量字符串。经测试,夜间模式启动图缓存路径的路径属于XBApplicationSnapshotManifest。sqlite>.schemakey_tabCREATETABLEkey_tab(idINTEGERPRIMARYKEY,keyTEXTNOTNULL,UNIQUE(key));sqlite>.width250sqlite>select*fromkey_tab;idkey--------------------------------------------------1SBLaunchImageIngestionInfo2XBApplicationSnapshotManifest3_SBScenes4SBApplicationShortcutItems5compatibilityInfo6SBApplicationRecentlyUpdated7SBApplicationRecentlyUpdatedTimerStartDatekvs_debug负责串联以上3个表:kvs.lashentestification.youapplication_biidentifier=得到4个结果,第二个负责保存snapshot相关信息------------------------------test.SplashTest_SBScenesbplist00test.SplashTestXBApplicationSnapshotManifestbplist00test.SplashTestSBApplicationRecentlyUpdated0test.SplashTestcompatibilityInfobplist00export在对XBApplicationSnapshotManifest进行一些研究之后,我们有发现XBApplicationSnapshotManifest对应的值就是SplashBoard库XBApplicationSnapshotManifestImpl类的持久化结果所以,我们可以通过下面的代码来dumpvalue的内容。+(void)load{void*lib=dlopen("/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/系统/图书馆/PrivateFrameworks/SplashBoard.framework/SplashBoard",RTLD_NOW);printf("%p",lib);[selfdump:@"/Users/test/Library/Developer/CoreSimulator/Devices/1F9B22C5-E446-??4881-AFE4-3373E3513C59/data/Library/FrontBoard/XBApplicationSnapshotManifest.plist"];}+(void)dump:(NSString*)path{NSData*data0=[NSDatadataWithContentsOfFile:path];NSPropertyListFormatf=-1;NSError*error=nil;NSData*data1=[NSPropertyListSerializationpropertyListWithData:data0options:NSPropertyListReadStreamErrorformat:&ferror:&error];if(f==kCFPropertyListXMLFormat_v1_0){NSLog(@"kCFPropertyListXMLFormat_v1_0");}idobj=[NSKeyedUnarchiverunarchiveTopLevelObjectWithData:data1error:&error];@NSLog(@"%",obj);}dump结果:
