2024年02月18日, 編集履歴
macOS App Sandbox下におけるSecurity-scoped Bookmarkについて
App Sandbox環境下のmacOSアプリにおいて、ローカルファイルへのアクセスには制限が課せられている。
コード内で適当に生成したURL
ではローカルファイルへアクセスできない。ファイルへのアクセス権を得るには、
NSOpenPanel
fileImporter()
モディファイア- ドラッグ&ドロップ
等の限られた方法を取る必要がある。
ただしNSOpenPanel
等で取得したURL
は、その起動中はURL先のファイルにアクセス可能だが、そのURLを保存しておいたとしても、次の起動時にはアクセスできなくなってしまう。URLへのアクセスを永続化するには、Security-scopedなURL Bookmarkを作らなければならない。
URLからSecurity-scoped Bookmarkの生成
URL
のbookmarkData(options:includingResourceValuesForKeys:relativeTo:)
関数を使ってSecurity-scoped Bookmark(Data
型)を作成する。options
引数にはwithSecurityScope
を指定。URLへのアクセスが読み込みのみで良い場合は、securityScopeAllowOnlyReadAccess
も併用する。
let bookmarkData = try? url.bookmarkData(options: [.withSecurityScope, .securityScopeAllowOnlyReadAccess], includingResourceValuesForKeys: nil, relativeTo: nil)
Security-scoped BookmarkからURLを生成し、アクセスする
URL
のinit(resolvingBookmarkData:options:relativeTo:bookmarkDataIsStale:)
関数を使うことで、Security-scoped BookmarkなData
からURL
を生成できる。resolvingBookmarkData
引数にはSecurity-scoped BookmarkなData
を、options
引数にはwithSecurityScope
を指定する。
生成されたURLに実際にアクセスするには、アクセス前にstartAccessingSecurityScopedResource()
を実行し、アクセス後にはstopAccessingSecurityScopedResource()
を実行する。
var isStale = false
let urlData = // 前項の手法で保存したURLのData
if let url = try? URL(resolvingBookmarkData: urlData, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale) {
if url.startAccessingSecurityScopedResource() {
// URL先への読み書き処理
url.stopAccessingSecurityScopedResource()
}
}
URL
のinit(resolvingBookmarkData:options:relativeTo:bookmarkDataIsStale:)
実行後にisStale
がtrue
になっている場合、Bookmark Data作成以降にURL先ファイルの名前が変更されたり、場所が変更されたことを意味する。その場合でも返却されたURLは変更後のものになっており、アクセスは可能だが、新しくSecurity-scoped Bookmarkを生成し直す必要がある。
Security-scoped Bookmarkを再生成するときも、URL先へのアクセスに相当するので、startAccessingSecurityScopedResource()
とstopAccessingSecurityScopedResource()
が必要になる。