所謂sandbox App是指那些為了發布到App Store的,受到權限控制的App。一般Sandbox App擁有如下權限
一波三折 之一
項目需要我們在符合Sandbox權限約束下的App中使用第三方的一個開源項目的Binary。并在之中調用這個Binary以進行一些功能上的實現。
于是,我興高采烈地直接拿到了local build版本的這個Binary,以下簡稱N文件。我通過包一個帶UI的Sandbox App的方式,通過NSTask調用了這個Binary,一切功能運行正常。
于是乎直接申請對應App ID,上傳之,準備發布。
然而,正以為一切都盡在掌控之際,陡生變故。在使用Xcode上傳時,連第一步的Validate都未通過。并且錯誤顯示我的這個N文件無Sandbox權限。
經過研究,原來,在Sandbox下的可獨立執行的文件都必須符合Sandbox權限管控。可是,這是一個Command Line Tool的項目啊,這個如何加入Sandbox權限呢?
一波三折 之二
經過研究,發現可以通過
codesign --entitlements ./entitlements.plist -s "copy & paste your certificate from keychain" ./commandlinetool
來將我們手動創建的entitlements文件(記錄了app的sandbox權限信息)sign進對應的commondlinetool
請參考Stackoverflow原貼
以為一切就如此順利的搞定了。剛準備為自己的運氣而慶幸,直接運行,出現
Illegal instruction: 4
這是因為我們為一個原本不受權限控制的可執行文件強行添加權限之后無法執行。
再次研究,從Apple官方文檔中找到
Add the following arguments to your linker flags:
-sectcreate __TEXT __info_plist Info.plist_path
Info.plist 是記錄一個SandboxApp 相關Bundle信息的文件,我一拍腦袋。我只顧為一個Binary進行權限分配,而沒有為這個Binary包相關的Bundle信息,那么這個程序在運行時由于缺少Bundle信息,在Sandbox 化時系統無法為其生成相關的Container。根據文檔,我修改了Makefile,添加了Linkflag
一波三折 之三
折騰了一天,終于可以下班了吧。在Terminal中完美運行了這個Sandbox化的N文件之后,我把它重新包進了之前帶UI的Sandbox App。然而,運行后程序毫無反饋。調試后發現,既無報錯也無Console。因為正常如果有任何異常都會有Console報錯,如果能夠運行,Console中會有運行中的Log信息。
欲哭無淚,毫無頭緒。
經過多方求助終于在Apple的一個developer forum回帖中發現了一個相關回答
其中,有價值的兩點
1.Sandbox inheritance (com.apple.security.inherit)
2.converting your tool to some sort of script (a shell script, Python, whatever).
先嘗試了包一個shell,發現在Sandbox的app中調用bash去run 自己寫的shell,再通過這個shell去run我們的binary是不可行的,報錯:operation not permitted
再看第二點,查Apple 文檔和具體的這個com.apple.security.inherit權限文檔
深入研究后發現,
To enable sandbox inheritance, a child must use exactly two App Sandbox entitlement keys: com.apple.security.app-sandbox and com.apple.security.inherit. If you specify any other App Sandbox entitlement, the system aborts the child process. You can, however, confer other capabilities to a child process by way of iCloud and notification entitlements.
也就是說,我們的N文件現在是作為我們包的UI App的子項,于是我們需要讓這個N文件繼承UI App的Sandbox權限,而不是把它自己作為一個獨立的Sandbox App。
于是,
- 去掉Makefile中之前添加的linkflag
- 將entitlement文件改為
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
重新make,然后codesign,并把新N文件包進去
黎明
終于,這個程序正常了,并且N文件和外包的UI App公用同樣的Bundle信息,同一個Container,使用同樣的Sandbox權限。
總結
整個過程一波三折,每當有進展之后以為圓滿解決了又來了更大的問題。同時,相關資料非常少,我全程查英文第一手資料,但是無奈Apple文檔目錄太深,Google也幫不了我。好在各種機緣和強大的同事,我們一步一步的猜想,實驗,破解了謎團。
App已經提交了,也許Apple不允許這樣的通過N文件的方式進行包裝,不過在這個過程中對Sandbox權限和項目構建有了更深的理解。
相關的中文資料基本沒有,希望能夠給同樣在坑中的人們帶來一些參考。