iOS默認(rèn)并且只能讀寫對(duì)應(yīng)的沙盒目錄聂儒。
OSX自從10.6系統(tǒng)開始引入沙盒機(jī)制,規(guī)定發(fā)布到Mac AppStore的應(yīng)用,必須遵守沙盒約定。沙盒對(duì)應(yīng)用訪問的系統(tǒng)資源,硬件外設(shè),文件,網(wǎng)絡(luò),XPC,都做了嚴(yán)格的限制,這樣能防止惡意的App通過系統(tǒng)漏洞,攻擊系統(tǒng),獲取控制權(quán)限,保證了OSX系統(tǒng)的安全外驱。沙盒相當(dāng)于給每個(gè)App一個(gè)獨(dú)立的空間刻剥。要獲取自己空間之外的資源必須獲得授權(quán)遮咖。
macOS APP不需要上架的時(shí)候,可以不開啟Sandbox 功能造虏,可以隨意訪問mac上的文件御吞。
當(dāng)未開啟Sandbox功能上傳到APPStore的時(shí)候提示:
iTunes Store operation failed.
App sandbox not enabled. The following executables must include the "com.apple.security.app-sandbox" entitlement with a Boolean value of true in the entitlements property list: [( "org.skyfox.ProfilesTool.pkg/Payload/ProfilesTool.app/Contents/MacOS/ProfilesTool" )] Refer to App Sandbox page at https://developer.apple.com/devcenter/mac/app-sandbox/ for more information on sandboxing your app.
開啟Sandbox
App Sandbox
在Xcode工程target設(shè)置Tab的Capabilities中選擇 App Sandbox 為ON即可開啟使用沙盒,Xcode自動(dòng)生成.entitlements權(quán)限配置文件到工程漓藕。并且可以配置相應(yīng)的權(quán)限陶珠,(網(wǎng)絡(luò),硬件享钞,App Data揍诽,文件訪問)
Network:網(wǎng)絡(luò)訪問控制
Incoming Connections(Server) :應(yīng)用做為Server對(duì)外提供HTTP,FTP等服務(wù)時(shí)需要打開
Outgoing Connections(Client):做為客戶端,訪問服務(wù)器時(shí)需要打開
Hardware:硬件資源控, Printing為必須勾選栗竖。App的默認(rèn)第一個(gè)頂級(jí)菜單中有打印功能的子菜單:
Camera
Micophone
USB
Printing
App Data:獲取系統(tǒng)的聯(lián)系人暑脆,位置,日歷服務(wù)時(shí)需要打開:
Contacts
Location
Calendar
File Access:文件和用戶目錄的訪問控制,分為禁止none,只讀,讀寫3類:
User Selected File:文檔類應(yīng)用或者需要用戶選擇打開某個(gè)文件時(shí),需要選擇合適的訪問權(quán)限.
Downloads Folder
Pictures Folder
Music Folder
Movies Folder
如果應(yīng)用中不需要的權(quán)限項(xiàng)划滋,一律不要打開饵筑。否則App Review團(tuán)隊(duì)會(huì)拒絕你的應(yīng)用上架
entitlements權(quán)限配置信息存儲(chǔ)
沙盒中每個(gè)需要訪問權(quán)限的項(xiàng)都對(duì)應(yīng)一個(gè)key埃篓,對(duì)應(yīng)的value处坪,YES 或 NO表示是否允許訪問。選擇配置了沙盒的訪問控制信息后架专,Xcode會(huì)自動(dòng)保存到一個(gè)擴(kuò)展名為.entitlements的plist文件中
應(yīng)用打包時(shí)會(huì)對(duì)這個(gè)文件進(jìn)行簽名同窘, 應(yīng)用運(yùn)行期間要獲取某個(gè)權(quán)限時(shí),系統(tǒng)都會(huì)通過.entitlements去檢查應(yīng)用是否有授權(quán)部脚,如果沒有就拒絕訪問想邦。
Sandbox之外的文件怎么訪問?
那么問題就出現(xiàn)了委刘,開啟Sandbox 功能之后丧没,NSHomeDirectory對(duì)應(yīng)的文件夾形如:
/Users/yourName/Library/Containers/com.xxxx.appname/Data
程序數(shù)據(jù)文件的存儲(chǔ)路徑也不同,原來在
~/Library/Application Support/<app_name>/
如今在沙盒內(nèi):
~Library/Containers/<bundle_id>/Data/Library/Application/Support/<app_name>/
沙盒保證了程序只能訪問沙盒container下的文件夾锡移,這樣就相對(duì)安全的保護(hù)了程序自身呕童。
訪問沙盒外部文件
一、讓用戶人為選擇目錄
Capabilities中選擇 App Sandbox 淆珊,在File Access中User Selected File項(xiàng)中選擇Read/Write文件讀寫權(quán)限
沙盒有個(gè)默認(rèn)的規(guī)則夺饲。在App運(yùn)行期間通過NSOpenPanel用戶手動(dòng)打開的任意位置的文件,把這個(gè)這個(gè)路徑保存下來,后面都是可以直接用這個(gè)路徑繼續(xù)訪問獲取文件內(nèi)容的往声。
但是App重新啟動(dòng)后,這個(gè)文件路徑就不能直接訪問了擂找。要想永久的獲得應(yīng)用的Container目錄之外的文件,這里必須講一下Security-Scoped Bookmark。
Security-scoped bookmarks:
使用bookmarks之前同樣要在.entitlements文件中填寫對(duì)應(yīng)的key與value
Security-scoped bookmarks有2種:
1. An app-scoped bookmark
能為已沙盒程序提供對(duì)用戶指定文件和文件夾的持久訪問權(quán)浩销。 例如贯涎,如果程序采用了一個(gè)程序容器外的下載或處理目標(biāo)文件夾,通過 NSOpenpanel 對(duì)話框獲得用戶想使用該文件夾的初始訪問權(quán)慢洋。
然后柬采,為其創(chuàng)建一個(gè) app-scoped bookmark,將它作為程序的配置儲(chǔ)存(可能用屬性列 表文件或 NSUserDefaults 類)且警。有了 app-scoped bookmark粉捻,程序就能獲得對(duì)該文件夾的 未來訪問權(quán)了。這種bookmark方式使用的比較多斑芜。
在.entitlements文件對(duì)應(yīng)的key對(duì)應(yīng)的權(quán)限key為com.apple.security.files.bookmarks.app-scope
2. A document-scoped bookmark
提供了對(duì)特定文檔的持久訪問權(quán)肩刃。可以理解為針對(duì)文檔嵌套的一種權(quán)限模式杏头。比如你開發(fā)一個(gè)能編輯ppt文檔的應(yīng)用盈包,里面嵌入了視頻文件,圖片文件連接。那么下次打開這個(gè)ppt文檔時(shí)就能直接訪問這些文件而不需要在通過NSOpenPanel打開獲得授權(quán)醇王。
Document-scoped bookmark 只能指向文件而不是文件夾呢燥。并且這個(gè)文件必須不在系統(tǒng)使用的 位置上(如/private 或/Library)
在.entitlements文件對(duì)應(yīng)的key對(duì)應(yīng)的權(quán)限key為com.apple.security.files.bookmarks.document-scope
保存打開的文件URL的bookmark
獲取到URL的bookmarkData存儲(chǔ)到NSUserDefaults等位置
NSData *bookmarkData =[url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:NULL];
應(yīng)用啟動(dòng)時(shí)通過URL的bookmark獲取文件授權(quán)
通過bookmark數(shù)據(jù)解析獲取授權(quán)的NSURL,并且執(zhí)行startAccessingSecurityScopedResource方法得到訪問權(quán)限。
執(zhí)行block回調(diào)完成相關(guān)內(nèi)容讀取后,執(zhí)行stopAccessingSecurityScopedResource停止授權(quán)寓娩。
NSURL *allowedUrl = [NSURL URLByResolvingBookmarkData:bookmarkData options:NSURLBookmarkResolutionWithSecurityScope|NSURLBookmarkResolutionWithoutUI relativeToURL:nil bookmarkDataIsStale:&bookmarkDataIsStale error:NULL];
@try {
[allowedUrl startAccessingSecurityScopedResource];
block();
} @finally {
[allowedUrl stopAccessingSecurityScopedResource];
}
二叛氨、文件訪問臨時(shí)例外
在開啟沙盒功能的App中,App僅可以訪問container中的數(shù)據(jù)棘伴,application groupcontainer寞埠,POSIX可讀的公開位置、用戶手動(dòng)Open或Save dialog打開的位置 焊夸。如果您的應(yīng)用程序需要永久訪問到其他位置仁连,你可以通過啟用本人所述的臨時(shí)例外entitlement權(quán)限鍵將額外的位置帶入你的沙盒
為每個(gè)您想要啟用訪問的路徑,將路徑指定為相應(yīng)的entitlement權(quán)限key值數(shù)組阱穗。每個(gè)字符串必須以斜杠 (/) 字符開頭 — — 它代表絕對(duì)路徑或相對(duì)于用戶的主目錄的路徑饭冬。如果您提供的是一個(gè)目錄路徑,你必須以斜杠字符串結(jié)束揪阶。
home-relative-path
臨時(shí)例外, 提供一個(gè)相對(duì)于user home目錄的路徑昌抠。相對(duì)于~
例如我指定“/Library/MobileDevice/Provisioning Profiles/”目錄用來讀取系統(tǒng)的profies文件。
當(dāng)我設(shè)置home相對(duì)路徑后遣钳,在程序中要手動(dòng)拼接上home目錄扰魂。
拼接home路徑有兩種方式:
一種是getpwuid方法
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <assert.h>
struct passwd *pw = getpwuid(getuid());
NSString *home = [NSString stringWithUTF8String:pw->pw_dir];
一種是根據(jù)沙盒目錄字符串截取
NSString *home = NSHomeDirectory();
NSArray *pathArray = [home componentsSeparatedByString:@"/"];
NSString *absolutePath;
if ([pathArray count] > 2) {
absolutePath = [NSString stringWithFormat:@"/%@/%@", [pathArray objectAtIndex:1], [pathArray objectAtIndex:2]];
}
absolute-path
臨時(shí)例外, 提供一個(gè)絕對(duì)路徑麦乞。相對(duì)于 /
Entitlement key | Capability |
---|---|
com.apple.security.temporary-exception.files.home-relative-path.read-only | 開啟對(duì)于home指定子目錄或者文件的只讀權(quán)限 |
com.apple.security.temporary-exception.files.home-relative-path.read-write | 開啟對(duì)于home指定子目錄或者文件的讀寫權(quán)限 |
com.apple.security.temporary-exception.files.absolute-path.read-only | 開啟對(duì)于 / 指定子目錄或者文件的只讀權(quán)限 |
com.apple.security.temporary-exception.files.absolute-path.read-write | 開啟對(duì)于 / 指定子目錄或者文件的讀寫權(quán)限 |