沙盒机制

什么是沙盒?

沙盒通过限制应用的执行操作来显著提高操作系统的安全性,在iOS上一个应用无法访问另一个应用程序的沙盒。每一个应用都具有一个沙盒,是可以用来存储数据的目录。如果应用需要访问的数据不在沙盒上,则需要通过系统接口请求数据。例如:应用程序无法直接访问用户设备的照片,要访问用户照片第三方应用程序需要访问系统界面,系统界面增加一层安全性。

沙盒在哪?

在xcode工程中,使用NSHomeDirectory()来查看沙盒的根路径。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    print(NSHomeDirectory())

    return true
}

如果在模拟器上运行,在控制台得到:

/Users/ryan/Library/Developer/CoreSimulator/Devices/A9220FEF-FAC0-4B97-B036-0A1AE68C4ECC/data/Containers/Data/Application/80689FD1-6DF4-4B61-B2DF-718E039A6B37

沙盒是什么样的?

应用沙盒并不是空容器的形式生成,而是包含了一些目录并且这些目录有明确的作用。

我们使用以下代码查看沙盒路径下的目录内容。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        if let items = try? FileManager.default.contentsOfDirectory(atPath: NSHomeDirectory()) {
            for item in items {
                print(item)
            }
        }
        // Override point for customization after application launch.
        return true
    }

命令行的输出:

.com.apple.mobile_container_manager.metadata.plist
Library
Documents
tmp
SystemData

第一项是操作系统的属性列表,剩下的条目是沙盒下的文件目录。

Documents

Documents目录非常适合用于存储于用户数据之间相关的数据,于macOS的Documents目录作用非常相似。

如果你的应用程序使用SQLite数据库存储用户数据,则数据库文件数据可以存储在Documents目录下。

Library

Library目录包含Caches目录和Preferences目录。

  • Caches目录适合存储缓存数据,当操作系统需要释放存储空间时会清楚该目录,iCloud和iTunes不会备份该处文件。
  • Preferences目录包含默认数据库属性列表。如果将键值对存储在默认数据库中,键值对将会存储在默认数据库的属性列表中。
let userDefaults = UserDefaults.standard
userDefaults.set(true, forKey: "DidLaunch")

ios 获取沙盒中的文件 iphone沙盒_数据

tmp

临时数据应该存储在tmp目录,会实时清楚以保证占用不必要的磁盘空间,像Caches目录一样不被iCloud和iTunes保存。

Application Bundle

应用程序本身不位于沙盒中,使用Bundle.main.bundlePath或者Bundle.main.bundleURL查询Bundle路径。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    print(NSHomeDirectory())
    print(Bundle.main.bundlePath)

    return true
}

控制台输出:

/Users/ryan/Library/Developer/CoreSimulator/Devices/A9220FEF-FAC0-4B97-B036-0A1AE68C4ECC/data/Containers/Bundle/Application/811BFF24-4A3C-4D7E-948B-942430212232/SandBoxTest.app

发现Bundle路径和沙盒路径不同,你不能也不应该修改Bundle里的内容,如果被修改操作系统会拒绝启动应用。

参考文章

什么是应用沙盒

文件管理实例

将网络获取数据序列号写入沙盒Cache目录下。

- (void)_archiveListDataWithArray:(NSArray<ListItem *> *)array {
    // 获取沙盒Cache路径
    NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *cachePath = [pathArray firstObject];
    
    // 文件管理单例
    NSFileManager *fileManager = [NSFileManager defaultManager];
    // 创建文件夹路径
    NSString *dataPath = [cachePath stringByAppendingPathComponent:@"Data"];
    // 创建文件Data夹
    NSError *creatError;
    [fileManager createDirectoryAtPath:dataPath withIntermediateDirectories:YES attributes:nil error:&creatError];
    
    // 创建文件路径
    NSString *listDataPath = [dataPath stringByAppendingPathComponent:@"list"];
    // 序列号
    NSData * listData = [NSKeyedArchiver archivedDataWithRootObject:array requiringSecureCoding:YES error:nil];
    // 写入文件
    [fileManager createFileAtPath:listDataPath contents:listData attributes:nil];
    
    // 读取文件数据
    NSData *readListData = [fileManager contentsAtPath:listDataPath];
    // 反序列化
    __unused id unarchiveObj = [NSKeyedUnarchiver unarchivedObjectOfClasses:[NSSet setWithObjects:[NSArray class], [ListItem class], nil] fromData:readListData error:nil];
    NSLog(@"");
}