Кто-нибудь успешно реализовал «открытое» действие для расширения приложения поставщика файлов? Я дошел до того, что смог прочитать файл, когда пользователь изначально выбирает файл в расширении набора документов (по сути, это действие «импорт»). Но что-то за этим не удается. Вот проблемы, с которыми я столкнулся:Реализация UIDocumentPickerModeOpen с поставщиками файлов
- Случаи подключения, если я использую
NSFileCoordinator
. Если я сохраню URL и попытаюсь либо прочитать, либо написать ему позже, вызовЭто работает, если я использую закладки.startAccessingSecurityScopedResource
возвращаетNO
.Если я пытаюсьЭто работает, если я создаю закладки внутри области безопасности.bookmarkDataWithOptions:
, я вернусь Error Domain = NSCocoaErrorDomain Code = 260 "Операция не может быть завершена. (Cocoa ошибка 260.)".
Вот шаблон, который создается для startProvidingItemAtURL:
при создании расширения поставщика файла:
- (void)startProvidingItemAtURL:(NSURL *)url completionHandler:(void (^)(NSError *))completionHandler {
// Should ensure that the actual file is in the position returned by URLForItemWithIdentifier:, then call the completion handler
NSError* error = nil;
__block NSError* fileError = nil;
NSData * fileData = [NSData data];
// TODO: get the contents of file at <url> from model
[self.fileCoordinator coordinateWritingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
[fileData writeToURL:newURL options:0 error:&fileError];
}];
if (error!=nil) {
completionHandler(error);
} else {
completionHandler(fileError);
}
}
Но расширение тупики, когда я использую координатор файл. Кроме того, в документации для startProvidingItemAtURL:
указано «Примечание Не используйте координацию файлов внутри этого метода»., так что я взял его.
В другом приложении, это то, что я делаю, чтобы прочитать этот файл в первый раз, а затем создать закладку для этого:
// Start accessing the security scoped resource.
[url startAccessingSecurityScopedResource];
void (^accessor)(NSURL *) = ^void(NSURL *url) {
// If the file is missing, create a default here. This really should be done inside
// the FileProvider method startProvidingItemAtURL:. Unfortunately, that method does
// not get called unless we use use the file coordinator, which can deadlock the app.
if (![url checkResourceIsReachableAndReturnError:nil]) {
// TODO: Create a real default file here.
[[NSFileManager defaultManager] createFileAtPath:url.path
contents:nil
attributes:nil];
}
// TODO: Do something with this file.
};
#ifdef USE_FILE_COORDINATOR
NSFileCoordinator *fileCoordinator = [NSFileCoordinator new];
[fileCoordinator coordinateReadingItemAtURL:url
options:NSFileCoordinatorReadingWithoutChanges
error:NULL
byAccessor:accessor];
#else
accessor(url);
#endif
// Store a bookmark for the url in the defaults so we can use it later.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSError *error = nil;
NSURLBookmarkCreationOptions options = 0;
#ifdef NSURLBookmarkCreationWithSecurityScope
options |= NSURLBookmarkCreationWithSecurityScope;
#endif
NSData *bookmarkData = [url bookmarkDataWithOptions:options
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&error];
if (error) {
NSLog(@"ERROR: %@", error);
}
[defaults setObject:bookmarkData forKey:@"BookmarkDataKey"];
// Stop accessing the security scoped resource.
[url stopAccessingSecurityScopedResource];
И, наконец, использовать закладку позже, я делаю следующее:
// Get the bookmark from the defaults file.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *bookmarkData = [defaults objectForKey:@"BookmarkDataKey"];
if (bookmarkData) {
// Convert the bookmark into a URL.
NSError *error;
BOOL bookmarkIsStale;
NSURLBookmarkResolutionOptions options = NSURLBookmarkResolutionWithoutUI;
#ifdef NSURLBookmarkResolutionWithSecurityScope
options |= NSURLBookmarkResolutionWithSecurityScope;
#endif
NSURL *url = [NSURL URLByResolvingBookmarkData:bookmarkData
options:options
relativeToURL:nil
bookmarkDataIsStale:&bookmarkIsStale
error:&error];
// Get the data from the URL.
BOOL securitySucceeded = [url startAccessingSecurityScopedResource];
if (securitySucceeded) {
NSString *message = [NSString stringWithFormat:@"Random number: #%d", arc4random() % 10000];
NSData *fileData = [NSKeyedArchiver archivedDataWithRootObject:message];
NSError *fileError = nil;
[fileData writeToURL:url options:0 error:&fileError];
[url stopAccessingSecurityScopedResource];
}
}
Второе приложение также иногда является взаимоблокировками, если я использую координацию файлов. Так что я должен просто не использовать координацию файлов во втором приложении? Проблема в том, что если я не использую координацию файлов, то startProvidingItemAtURL:
в расширении File Provider никогда не будет вызван.
Также the documentation says использовать NSURLBookmarkCreationWithSecurityScope
, но это не определено для iOS. То же самое касается NSURLBookmarkResolutionWithSecurityScope
. Должен ли я просто использовать значения OS X или просто не использовать их?
Пожалуйста, добавьте код, чтобы я мог вам помочь. Поставщик файлов немного сложнее. Даже мы отслеживали его по методам следа и ошибок –
Спасибо за ваш ответ. В конце концов, я думаю, что я заработал, удалив координатор файла и игнорируя константы закладки безопасности в области безопасности. –
Привет, Можете ли вы поделиться простой демонстрацией на github. Спасибо, – Durgaprasad