试想有这么一款游戏:里面有山有水,有车有房,有铁轨公路,你在里面上天入海,杀人放火,驾飞机,开坦克,你似乎拥有整个世界,而另一个玩家也有同样的幻觉;对于游戏主机来说,不过是给你们每人一个“盒子”,一个微观盆景罢了,你的胡作非为,对其他玩家不会造成任何影响。这便是沙盒,一种文件访问权限的隔离机制。
每个应用都有相同的文件目录,对自己目录下的修改不会对其它应用造成影响。
换句话说,应用也不能通过相同的路径访问到其它应用的文件,这与我们在PC机下常用文件共享有很大的差别。
沙盒中各个文件夹的差别
每个应用默认都有以下文件夹,如下图所示:
每个目录的功能有以下差别:
每个文件夹的“能力”各有差别,以适用不同的使用场景,Document/适合用户生成的,需要备份、共享的数据,如文件工具生成的Doc类文档。
Library/适合后台记录值,但用户无需看到的数据,比如服务器同步数据,缓存数据库文件等。
根目录新建其它文件夹会怎么样?
可以建任意文件夹及文件,但备份等行为并不保证,比如iOS8下无法在根目录建立文件夹,iOS9却可以,不要依赖这种不确定的系统行为。
如何查看沙盒文件
查看模拟器沙盒:
- APP工程里加入以下代码:
NSString *homeDirectory = NSHomeDirectory();
NSLog(@"path:%@", homeDirectory);
控制台输出的路径如下
/Users/[用户名]/Library/Developer/CoreSimulator/Devices/04D49FFD-11F6-4A1E-BE74-D7C3A1AD1D40/data/Containers/Data/Application/20DE6878-D29E-431C-BAC1-78B4A85F51D3/Documents
20DE6878-D29E-431C-BAC1-78B4A85F51D3 这串字母数字
每次应用启动都会变化,小心不要被先前的路径误导
-
打开Finder
使用Finder打开路径
模拟器沙盒中的目录
查看真机沙盒
打开Xcode设备管理器选择齿轮图标 选择Show Container
显示的真机沙盒
编程访问各文件夹的方法
访问Home
见上文 查看模拟器沙盒
访问Document
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) objectAtIndex:0];
NSLog(@"The document's path:%@", documentPath);
这里返回的数组在iOS平台上总是只有一个对象
更换以上NSDocumentDirectory的枚举值,可获得其它沙盒目录路径
NSLibraryDirectory //.../Library/
NSCachesDirectory //.../Library/Caches/
NSString *tempPath = NSTemporaryDirectory(); //.../tmp/
NSLog(@"tempPath:%@", tempPath);
获得安装包中的文件路径
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@”apple” ofType:@”png”];
突破沙盒
1. 在程序间共享文档
可以通过UIDocumentInteractionController
将文件分享给其它应用:
- (void)shareFile {
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"我的图片" ofType:@"jpeg"]; //创建实例
UIDocumentInteractionController *documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]]; //设置代理
documentController.delegate = self;
BOOL canOpen = [documentController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
if (!canOpen) {
NSLog(@"沒有程序可以打开要分享的文件");
}
}
注册自己能打开的文件:
这需要在程序的Info.plist文件中添加CFBundleDocumentTypes键, 它是一个dictionary数组,每个dictionary表示了一个指定的文档类型。
数组中的每个 dictionary 可能包含以下键:
CFBundleTypeName
指定文档类型名称。
CFBundleTypeIconFiles
是一个数组,包含多个图片文件名,用于作为该文档的图标。
LSItemContentTypes
是一个数组,包含多个UTI类型的字符串。UTI
类型是本文档类型(组)所包含的文件类型。
LSHandlerRank
表示应用程序是“拥有”还是仅仅是“打开”这种类型而已。
一个plist文件中的例子:
<dict>
<key>CFBundleTypeName</key>
<string>My File Format</string>
<key>CFBundleTypeIconFiles</key>
<array>
<string>MySmallIcon.png</string>
<string>MyLargeIcon.png</string>
</array>
<key>LSItemContentTypes</key>
<array>
<string>com.example.myformat</string>
</array>
<key>LSHandlerRank</key>
<string>Owner</string>
</dict>
响应其它应用的打开文件请求:
实现application:didFinishLaunchingWithOptions:
方法中获得该文件的信息,而不是applicationDidFinishLaunching
如果你的应用程序处于活跃状态,此时application:didFinishLaunchingWithOptions:
方法是不会被调用的。需要实现application:openURL:options:
方法
网友评论