NativeScript iOS应用如何在构建时预填充Documents文件夹
问题1:iOS release版本文件写入限制理解验证
你对iOS文件系统权限的理解是正确的:
- iOS系统中,打包后的
.app应用包本身是经过数字签名的只读目录,release构建场景下不允许任何写入、修改、新增文件的操作,所有写入操作必须在应用沙箱的可写目录(Documents、Library、tmp等)下执行。 - debug构建版本可以写入.app目录只是苹果为了方便开发者调试提供的特殊权限,不属于正式环境的规则,线上环境不要依赖这个特性。
问题2:预填充Documents目录的实现方案
iOS系统本身不支持在应用安装阶段直接将文件写入Documents目录,该目录是应用首次启动时由系统动态创建的,构建阶段无法直接预知其路径并提前写入内容。你可以通过硬链接增量同步的方案实现和预填充几乎一致的体验,完全避免全量复制的性能开销:
具体操作步骤
- 第一步:将所有原始数据文件放到NativeScript项目的
app/iOSResources/目录下,这部分文件会在构建时自动打包进.app的根目录,作为只读的原始版本库。 - 第二步:在应用启动逻辑中添加增量同步代码,仅当Documents下对应文件缺失或版本落后时,通过硬链接关联.app内的原始文件,硬链接不会复制实际数据,仅增加文件系统引用,无论文件多大都可以毫秒级完成同步,代码示例如下:
const fileManager = NSFileManager.defaultManager; // 获取.app包路径 const bundlePath = NSBundle.mainBundle.bundlePath; // 获取Documents目录路径 const docsPath = fileManager.URLsForDirectoryInDomains(NSDocumentDirectory, NSUserDomainMask).firstObject.path; // 你存放原始数据文件的目录名,可自行修改 const RES_DATA_DIR = "app_data"; const bundleDataFullPath = `${bundlePath}/${RES_DATA_DIR}`; const docsDataFullPath = `${docsPath}/${RES_DATA_DIR}`; // 确保Documents下的目标目录存在 if (!fileManager.fileExistsAtPath(docsDataFullPath)) { fileManager.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(docsDataFullPath, true, null, null); } // 遍历原始数据文件列表做增量同步 const dataFiles = fileManager.contentsOfDirectoryAtPathError(bundleDataFullPath, null); for (let i = 0; i < dataFiles.count; i++) { const fileName = dataFiles.objectAtIndex(i); const bundleFile = `${bundleDataFullPath}/${fileName}`; const docsFile = `${docsDataFullPath}/${fileName}`; let needSync = false; if (!fileManager.fileExistsAtPath(docsFile)) { needSync = true; } else { // 对比修改时间,仅当包内文件更新时才同步 const bundleModifyTime = fileManager.attributesOfItemAtPathError(bundleFile, null).objectForKey(NSFileModificationDate); const docsModifyTime = fileManager.attributesOfItemAtPathError(docsFile, null).objectForKey(NSFileModificationDate); if (bundleModifyTime.compare(docsModifyTime) === NSOrderedDescending) { needSync = true; fileManager.removeItemAtPathError(docsFile, null); } } if (needSync) { // 硬链接,无数据复制开销 fileManager.linkItemAtPathToPathError(bundleFile, docsFile, null); } }
后续你需要更新原始数据文件时,只要替换app/iOSResources/下的对应文件,用户更新应用后首次启动就会自动同步新版本的文件,原有已经被用户修改过的文件不会被覆盖。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

