Закладка URL-адреса в области безопасности MacOS для папки - PullRequest
1 голос
/ 16 октября 2019

У меня проблемы (в Мохаве и Каталине) с «повторным использованием» закладки URL-адреса области безопасности для папки между запусками приложения в моем приложении.

Это простое приложение для распаковки, использующее libarchive framework. Пользователь выбирает файл для распаковки, я хочу сохранить закладку URL для его родительской папки (например, ~ / Desktop) и использовать его повторно, когда пользователь в следующий раз попытается распаковать файл в той же папке.

Сначала я добавил следующее вФайл разрешений моего приложения:

<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>

При первом обращении к файлу (соответственно к родительской папке):

  1. Пользователь выбирает файл для распаковки
  2. Я представляю NSOpenPanel для получения доступа к папке с файлами:
let directoryURL = fileURL.deletingLastPathComponent()

let openPanel = NSOpenPanel()
openPanel.allowsMultipleSelection = false
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = false
openPanel.prompt = "Grant Access"
openPanel.directoryURL = directoryURL

openPanel.begin { [weak self] result in
    guard let self = self else { return }
    // WARNING: It's absolutely necessary to access NSOpenPanel.url property to get access
    guard result == .OK, let url = openPanel.url else {
        // HANDLE ERROR HERE ...
        return
    }

    // We got URL and need to store bookmark's data
    // ...
}
Я получаю данные закладки из папки URL и сохраняю их в архиве с ключами:
let data = try url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
bookmarks[url] = data
NSKeyedArchiver.archiveRootObject(bookmarks, toFile: bookmarksPath)
Теперь я начинаю использовать file URL и использую libarchive для распаковки .zip файла в его родительскую папку:
fileURL.startAccessingSecurityScopedResource()
// Decompressing file with libarchive...
fileURL.stopAccessingSecurityScopedResource()
Все работает как положено, ZIP-файл распаковывается

При перезапуске приложения распаковываете файл в той же папке, повторно используя сохраненные данные закладок:

  1. Я получаю закладки из архива ключей:
let bookmarks = NSKeyedUnarchiver.unarchiveObject(withFile: bookmarksPath) as? [URL: Data]
Я получаю данные закладок из закладок для родительской папки файла и разрешаю их:
let directoryURL = fileURL.deletingLastPathComponent()
let data = bookmarks[directoryURL]!
var isStale = false
let newURL = try URL(resolvingBookmarkData: data, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
Теперь я снова начинаю использовать file URL и использую libarchive для распаковки .zip файла в его родительскую папку:
fileURL.startAccessingSecurityScopedResource()
// Decompressing file with libarchive...
fileURL.stopAccessingSecurityScopedResource()

Но на этот раз libarchive возвращаетсяошибка: Failed to open \'/Users/martin/Desktop/Archive.zip\'

Я знаю, что могу делать что-то ужасно неправильное или не понимать концепцию URL-адресов закладок в области безопасности, но не могу найти, в чем проблема. Есть подсказки?

ЗАКЛЮЧИТЕЛЬНОЕ РЕШЕНИЕ Ответ Rckstr и ответ в этой ветке форума разработчиков Apple указали мне правильное направление. Абсолютно необходимо позвонить startAccessingSecurityScopedResource() в тот же момент, когда URL-адрес, возвращенный try URL(resolvingBookmarkData: data, options: .withSecurityScope ...

1 Ответ

2 голосов
/ 16 октября 2019

Вы разрешаете закладку в области безопасности (для каталога) на let newUrl, но вы звоните startAccessingSecurityScopedResource() по URL-адресу файла fileURL. Вам нужно позвонить по этому номеру newURL.

newURL.startAccessingSecurityScopedResource()
// Decompressing fileURL with libarchive...
newURL.stopAccessingSecurityScopedResource()

Еще два замечания:

  1. При получении доступа через NSOpenPanel вам не нужно звонить startAccessingSecurityScopedResource() и stopAccessingSecurityScopedResource(), потому что пользователь явно предоставил вам доступ для этого сеанса.
  2. Вместо этого я использую var isStale: ObjCBool = ObjCBool(false). Я не эксперт по Swift, поэтому не уверен, что var isStale = false можно использовать.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...