Песочница приложения: закладка в области документа не разрешается; не возвращает ошибку

Я делаю песочницу в своем приложении и пытаюсь разрешить импорт / экспорт нескольких файлов, используя XML-файл для ссылки на них. Чтобы разрешить моему приложению (или другому изолированному приложению) доступ к файлам, перечисленным в XML, я также включаю сериализованную закладку в области безопасности. Я сериализирую его, как описано в этом ответе, и мои модульные тесты (которые не являются изолированными) пишут и читают данные XML без проблем. Когда мое приложение разрешает закладку, NSURL возвращается ноль, как и NSError ссылка. Поскольку я не верю, что так и должно быть, почему это происходит? Я могу обойти это, предложив пользователю выбрать файл / каталог с NSOpenPanel, но я все еще хотел бы, чтобы закладки работали как надо.

Воспроизведено в тестовом проекте

Чтобы воспроизвести дома, создайте новое приложение Какао в XCode и используйте следующую Gist для файлов в проекте: https://gist.github.com/2582589 (обновлено с правильным циклом следующего просмотра)

Затем следуйте инструкциям Apple, чтобы подписать код проекта. Вы воспроизводите проблему (которую я представил в Apple как rdar: // 11369377), последовательно нажимая кнопки. Вы выбираете любой файл на диске (вне контейнера приложения), затем XML для экспорта и затем тот же XML для импорта.

Надеюсь, вы, ребята, сможете помочь мне понять, что я делаю не так. Либо я делаю что-то не так, и фреймворк ошибочно сохраняет себя, либо я делаю это правильно, и он полностью сломан. Я стараюсь не обвинять рамки, так что это? Или есть другая возможность?

Образец кода

Экспорт XML в docURL:

// After the user picks an XML (docURL) destination with NSSavePanel

[targetURL startAccessingSecurityScopedResource];
NSData *bookmark = [targetURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
                       includingResourceValuesForKeys:nil
                                        relativeToURL:docURL
                                                error:&error];
[targetURL stopAccessingSecurityScopedResource];

Импорт XML из docURL:

// After the user selected the XML (docURL) from an NSOpenPanel

NSURL *result = [NSURL URLByResolvingBookmarkData:bookmarkData
                                          options:NSURLBookmarkResolutionWithSecurityScope
                                    relativeToURL:docURL
                              bookmarkDataIsStale:nil
                                            error:&error];

Я попытался окружить этот звонок [docURL ..AccessingSecurityScopedResource], что не имело значения (как и ожидалось, поскольку docURL уже находится в области видимости после того, как он был выбран на открытой панели

Кроме того, я указываю следующее в моем app.entitlements файл:

com.apple.security.files.user-selected.read-write
com.apple.security.files.bookmarks.app-scope
com.apple.security.files.bookmarks.collection-scope

Как упоминалось выше, второй шаг (разрешение закладки) завершается, но оставляет оба error а также result ноль. Поскольку я выполнял песочницу, большинство ошибок, которые я сделал, привело к NSError будучи возвращенным, что помогло мне устранить ошибку. Но теперь нет ошибки, и URL не разрешен.

Разные шаги по устранению неполадок

  • Я попытался поместить XML-файл в изолированную программную среду моего приложения, но это не имело значения, поэтому доступ к XML-файлу не является проблемой.

  • Приложение использует ARC, но также и модульные тесты, которые успешно выполняются. Я попытался использовать alloc/init вместо метода класса autoreleased тоже (на всякий случай)

  • Я вставил код разрешения URL-адреса сразу после создания закладки, и он работает нормально, создавая защищенный URL-адрес

  • Я сделал po на первоначально созданной закладке (до сериализации), а затем на закладке после десериализации, и они соответствуют 100%. Сериализация не проблема

  • Я заменил разрешение вызова на CFURLCreateByResolvingBookmarkData(..) без изменений. Если это ошибка, она присутствует в Core Foundation API, а также на уровне Cocoa.

  • Указание значения для bookmarkDataIsStale: не имеет никакого эффекта

  • Если я укажу 0 за options:, тогда я получаю обратно действительный NSURL, но у него нет области безопасности, и поэтому последующие вызовы для чтения файла все еще терпят неудачу

    Другими словами, десериализованная закладка действительно действительна. Если данные закладки были повреждены, я сомневаюсь, что NSURL сможет с этим что-нибудь сделать

  • NSURL.h не содержал никаких полезных комментариев, чтобы указать на то, что я делаю неправильно

Кто-нибудь еще успешно использует закладки документа в области безопасности в изолированном приложении? Если так, что ты делаешь иначе, чем я?

Запрос версии ОС

Может ли кто-то, имеющий доступ к бета-версии Mountain Lion, проверить, показывает ли мой примерный проект ту же ошибку (отсутствие)? Если это ошибка, исправленная после Lion, я не буду беспокоиться об этом. Я еще не в программе разработчика, и поэтому не имею доступа. Я не уверен, что ответ на этот вопрос нарушит NDA, но я надеюсь, что нет.

1 ответ

Решение

В своем коде Gist измените следующую строку в AppDelegate.m (строка 61):

[xmlTextFileData writeToURL:savePanel.URL atomically:YES];

в

[xmlTextFileData writeToURL:savePanel.URL atomically:NO];

Ваш код будет работать.

Причиной этого, вероятно, является та же самая причина, по которой необходимо иметь существующий (но пустой) файл, который будет содержать закладки в области документа перед вызовом [anURL bookmarkDataWithOptions]: при создании экземпляра NSData ScopedBookmarkAgent добавляет что-то (например, тег, возможно, расширенный атрибут файла) для этого файла.

Если вы записываете данные (то есть URL-адреса закладок) в этот файл атомарно, фактически они записываются не непосредственно в файл, а сначала во временный файл, который переименовывается, если операция записи прошла успешно. Кажется, что тег, который был добавлен в (пустой, но существующий) файл, который будет содержать закладки, теряется в процессе записи во временный файл, а затем переименовывает его (и, следовательно, вероятно, удаляет исходный пустой файл),

Кстати: не нужно создавать закладки для приложений, прежде чем передавать соответствующие URL-адреса в XML-файл, содержащий закладки в документах.

Дополнение: com.apple.security.files.bookmarks.collection-scope было переименовано в com.apple.security.files.bookmarks.document-scope в 10.7.4.

Другие вопросы по тегам