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

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

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

Чтобы воспроизвести дома, создайте новое приложение Cocoa в 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], что не имело значения (как и ожидалось, поскольку URL-адрес документа уже находится в пределах области действия после выбора на открытой панели

Кроме того, я указываю следующее в моем файле 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 nil. Поскольку я внедрял песочницу, большинство ошибок, которые я сделал, привели к возвращению 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, но надеюсь, что нет.


person Dov    schedule 21.04.2012    source источник
comment
В любом случае, я не мог помочь, но этот вопрос - что-то вроде журнала путешествий по вашим исследованиям. Было бы здорово, если бы вы могли его переработать, забыв о том, КАК вы туда попали. Без обид: вопрос кажется качественным, что отражают 5 голосов (теперь 6 с моим).   -  person Dan Rosenstark    schedule 21.05.2012
comment
@Yar спасибо за вклад и голосование. Я сохранил (большинство) обновлений по двум причинам. Во-первых, я документирую шаги, которые пробовал, чтобы другие могли избежать повторного устранения неполадок, а во-вторых, я размещал обновления внизу (вместо того, чтобы добавлять новую информацию в основной вопрос), чтобы было понятнее тем, кто следит за вопросом, что на самом деле изменился. Я планировал отредактировать вопрос после того, как на него будет дан ответ. Вы предлагаете переупорядочить содержание вопроса или удалить менее важные части?   -  person Dov    schedule 21.05.2012
comment
оба. Это повысит вероятность получения ответа, а также сделает пост более актуальным для будущих пользователей, у которых совершенно другие исследования, но одна и та же проблема. Вы знаете, абстрагируйте проблему;)   -  person Dan Rosenstark    schedule 21.05.2012
comment
@Яр Готово. Это выглядит лучше?   -  person Dov    schedule 21.05.2012
comment
Спасибо @Dov, Вселенная благодарит тебя ;)   -  person Dan Rosenstark    schedule 22.05.2012
comment
Я не понимаю, как принятое решение решает проблему. Вы когда-нибудь решали, почему ваша ссылка NSError не устанавливается и почему она не возвращает указатель NSData?   -  person JP Richardson    schedule 10.07.2012
comment
Причина, по которой мой код не работал, заключалась в том, что запись файла работает атомарно. Он записывает файл во временное расположение, а затем перемещает его в нужное место назначения. Для песочницы ScopedBookmarkAgent добавляет в файл некоторые метаданные, которые удаляются, когда функция writeToURL:atomically: перемещает файл. Конечно, когда я иду читать закладку, я должен получить NSError обратно. Было бы легче отслеживать происходящее.   -  person Dov    schedule 10.07.2012


Ответы (1)


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

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

to

[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.

person Tim    schedule 09.06.2012
comment
Спасибо х1000. Эта мысль даже не пришла мне в голову. Что касается переименованного ключа полномочий, можете ли вы дать ссылку? В документации по-прежнему написано collection-scope. - person Dov; 12.06.2012
comment
Изменение имени права указано в таблице 3-4 Справочник по ключу права. - person Tim; 12.06.2012
comment
@Tim Вы упомянули, что необходимо иметь существующий (но пустой) файл, который будет содержать закладки в области документа. Как можно узнать место, в котором пользователь впервые сохранит новый документ. Кроме того, как создать пустой файл в каком-либо месте с включенной песочницей и NSSavePanel, который не появляется на картинке? - person AmaltasCoder; 02.01.2015