macrubyでSandboxのsecurity-scoped bookmarkを取り扱う方法
Mac App Storeに申請するアプリはすべてSandboxが有効でなければならない。Sandboxを有効化する上で必要な初期設定は開発言語に関係なく、TARGETS > Summary > Entitlements > Enable App Sandboxingにチェックを入れて、必要なAccessにチェックを入れておく必要がある。Sandboxの設定ではインターネットアクセスや印刷などいくつかの処理に対して可否を設定することにになるが、ここではファイルへのアクセスについてまとめる。
Sandboxが有効なアプリでは、アプリが勝手にファイルを新規保存したり読み込んだりすることができない。ただし、Entitlementsの
com.apple.security.files.user-selected.read-write
をYESにしておくとユーザーがNSOpenPanelやNSSavePanelを介して選択したファイルやフォルダへのアクセスが可能になる。しかしこれだけでは不便なので、ユーザーが選択したファイルに後ほどアクセスするための設定
com.apple.security.files.bookmarks.app-scope
がある。これを有効にしておくと、NSOpenPanelやNSSavePanelで指定したファイルを「bookmarkデータ(security-scoped bookmarks)」として格納することができる(NSData)。さらにBookmarkデータはplistに保存しておくことができるので、次回起動時に自動で読み込んだりすることができる(user-selectedを有効にするだけではできない)。なお、com.apple.security.files.bookmarks.app-scope
についてはxcodeのGUI上にチェックボックスがないようなので、Entitlementsを直接編集して、上記Keyを追加、TypeをBoolean、ValueをYESにしておく必要がある。具体的な手順について以下まとめる。
NSOpenPanelでopenPanel = NSOpenPanel.openPanel
を開き、ファイルを読み込んだ後、
def bkURLtoData(url)
error = Pointer.new('@')
bkFileData = url.bookmarkDataWithOptions(NSURLBookmarkCreationWithSecurityScope,
includingResourceValuesForKeys:nil,
relativeToURL:nil, error:error)
if error[0]
puts error[0].description
raise
end
return bkFileData
end
def bkDataToURL(data)
error = Pointer.new('@')
bkFileURL = NSURL.URLByResolvingBookmarkData(data,
options:NSURLBookmarkResolutionWithSecurityScope,
relativeToURL:nil,
bookmarkDataIsStale:nil,
error:error)
return bkFileURL
if error[0]
puts error[0].description
raise
end
end
# Create a bookmark file NSData Object
bkData = bkURLtoData(NSURL.fileURLWithPath(opePanel.filename))
# Get NSURL path of the bookmark file NSData Object
bkURL = bkDataToURL(bkData)
上のbkURLtoData
で引数にURLを与えるとブックマークデータ(NSDataオブジェクト)が生成される。またまたブックマークデータのNSURLはbkDataToURL
で取得できる。上述したようにブックマークデータはplistに保存することができて、後々読み込んでファイル操作することができる。たとえば、以下の様にする。
user_plist = NSUserDefaults.standardUserDefaults
# Save: @user_plist.setObject value, forKey:key
user_plist.setObject bkData, forKey:"bkData"
# Load: @user_plist.dataForKey(key)
user_plist.dataForKey("bkData")
またplistに保存されているかどうかは、ターミナルでdefaults read com.appID.AppName
と打てば確認できる。
ブックマークされたデータに対して処理をする場合は
bkURL.startAccessingSecurityScopedResource
# Do any processes you want (File.open, for example)
bkURL.stopAccessingSecurityScopedResource
というように処理の開始と終了を宣言する必要がある。
基本的な処理は問題なくできるのだけど、複雑な処理、たとえばmacgemのsqlite3でデータベースをdb = SQLite3::Database.open bkURL.path
で開いて更にdb.execute "CREATE VIRTUAL TABLE"
したりするとエラーになる(どうしたらよいかわかりません)。
なお、テンポラリディレクトリはsandboxの有無に関係なくアクセス自由なので、どうしてもうまくいかないときはNSTemporaryDirectory()
のなかで作業して、最後にmoveItemAtURL
でファイルを移動してもいいのかも。
error = Pointer.new('@')
fileManager = NSFileManager.defaultManager
fileManager.moveItemAtURL(NSURL.fileURLWithPath(tmp_file),
toURL:NSURL.fileURLWithPath(distination_file),
error: error)
if error[0]
puts error[0].description
raise
end
もちろん、ここでdistination_file
はNSOpenPanelやNSSavePanelで指定されたURLまたはBookmarkDataのURLである必要がある。
参考
PS. App Storeで問題になる被仕向送金手数料ですが、最近ソニー銀行で無料化されたようですね。