MacOS изолированное приложение: доступ к файлам без NSOpenPanel - PullRequest
0 голосов
/ 17 января 2019

В изолированном приложении на основе NSDocument любой совместимый документ может быть доступен с помощью NSOpenPanel, независимо от того, где документ сохранен. Без NSOpenPanel приложение может получать доступ только к файлам в контейнере с песочницей.

Поскольку мое приложение управляет двумя типами подкласса NSdocument («Текст для чтения / записи» и «Изображение только для чтения»), я пытаюсь реализовать отдельное меню «Открыть последние» для изображений. Я отключил обычное поведение для них, когда они открываются пользователем, переопределяя метод noteNewRecentDocumentURL: (NSURL *)url NSDocumentController для возврата NO для URL-адресов изображений. Чтобы в обычном меню «Файл» -> «Открыть недавние» отображались только текстовые документы (и открывались нормально, когда пользователь их выбирал). Изображения перечислены в пользовательском меню.

Проблема возникает с этими URL-адресами изображений, поскольку приложение помещено в «песочницу»: приложение не может открыть напрямую любой файл изображения, указанный в специальном меню (любая операция чтения возвращает ошибку -54. Это поведение можно проверить с помощью:

[[NSFileManager defaultManager] isReadableFileAtPath:[fileURL path]]

, который всегда возвращает FALSE в этой ситуации. Существует только одно исключение: при повторном открытии из выделенного меню «Открыть недавно» файл, который ранее был открыт с помощью NSOpenPanel в том же сеансе приложения, а затем закрыт: в этом случае isReadableFileAtPath: возвращает TRUE, и файл может быть доступен. Но когда приложение закрывается и перезапускается, к таким файлам последних изображений нельзя получить доступ таким образом.

Я нашел три решения для решения этой проблемы:

  1. Перемещение файла изображения в контейнере с песочницей, как только пользователь "легально" получил к нему доступ через NSOpenPanel. Это работает, конечно, но мешает пользователю самому определять местоположение своих файлов! Точно так же дублирование файла в песочнице не является решением.

  2. Создание псевдонима для этих файлов в песочнице. Поскольку я не мог найти способ сделать это, я не мог проверить, является ли это решением или нет.

  3. Отключить изолированную программную среду приложения. Но это худшее решение, так как есть много причин использовать песочницу!

Существует ли 4-е решение, которое разрешило бы доступ только для чтения к любому файлу изображения, где бы он ни находился, без отключения песочницы?

Ответы [ 2 ]

0 голосов
/ 17 января 2019

Ну, предложение Ивана было превосходным. После нескольких чтений (менее часа) я смог реализовать эту закладку в области безопасности. Для заинтересованных людей вот основные выводы.

  1. добавить функцию в файл разрешений вашего изолированного приложения установите для com.apple.security.files.bookmarks.document-scope (или для com.apple.security.files.bookmarks.app-scope или обоих) значение TRUE.

  2. Измените метод открытия документа (который вызывает NSOpenPanel) следующим образом:

-(void) openMyDocument:(id)sender{

      // ... do your stuff

    [self.panel beginWithCompletionHandler:^(NSInteger result) {
        if (result == NSModalResponseOK) {
            NSURL* selectedURL = [[self.panel URLs] objectAtIndex:0];            
            NSData *bookmark = nil;
            NSError *error = nil;
            bookmark = [selectedURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
                     includingResourceValuesForKeys:nil
                                      relativeToURL:nil // Make it app-scoped
                                              error:&error];
            if (error) {
                NSLog(@"Error while creating bookmark for URL (%@): %@", selectedURL, error);
            }
            NSString *access = [NSString stringWithFormat:@"%@%@", @"Access:", [selectedURL path]];
            [[NSUserDefaults standardUserDefaults] setObject:bookmark forKey:access];
            [[NSUserDefaults standardUserDefaults] synchronize];

            // ... then open the document your way
        }
    }
}
  1. Измените метод, который вы создали, чтобы прочитать файл без использования NSOpenPanel
- (void) openDocumentForScopedURL: (NSURL *) fileURL

        NSString *accessKey = [NSString stringWithFormat:@"%@%@", @"Access:", [fileURL path]];
        NSData *bookmarkData = [[NSUserDefaults standardUserDefaults] objectForKey:accessKey];
        NSURL *bookmarkFileURL = nil;
        if (bookmarkData == nil){
            // no secured-scoped bookmark found, alert the user
            return;
        } else {
            NSError *error = nil;
            BOOL bookmarkDataIsStale;

            bookmarkFileURL = [NSURL
                               URLByResolvingBookmarkData:bookmarkData
                               options:NSURLBookmarkResolutionWithSecurityScope
                               relativeToURL:nil
                               bookmarkDataIsStale:&bookmarkDataIsStale
                               error:&error];
            [bookmarkFileURL startAccessingSecurityScopedResource];
        }


        // ... Then open your file, using bookmarkFileURL
        // ... and do your stuff

        // IMPORTANT. You must notify that stopped to access

        [bookmarkFileURL stopAccessingSecurityScopedResource];            
}
0 голосов
/ 17 января 2019

Вы не можете получить доступ к любому файлу, несмотря ни на что.

Кроме того, я не уверен, что означает ваше второе решение, поэтому, вероятно, вы не смогли им следовать. Вы, вероятно, хотели обратиться к «закладкам в области безопасности», а не к «псевдонимам», и они работают очень хорошо, и именно по этому пути вы должны следовать.

...