cocoa - 存在 - url swift 4



無効なNSURLブックマークを処理する正しい方法は何ですか? (1)

セキュリティスコープのブックマークからNSURLを解決するときに、ユーザーがそのファイルまたはフォルダの名前を変更したり移動した場合、ブックマークは無効になります。 Appleのドキュメントには、

isStale

戻ると、YESの場合、ブックマークデータは古くなっています。 アプリは、返されたURLを使用して新しいブックマークを作成し、既存のブックマークの保存されたコピーの代わりに使用する必要があります。

残念ながら、これはまれに私のために働く。 時間の5%で動作する可能性があります。 返されたURLを使用して新しいブックマークを作成しようとすると、エラーコード256が発生し、コンソールで検索すると、更新されたURLのdeny file-read-dataというsandboxdのメッセージが表示されます。

メモブックマークの再生成が機能する場合は、初めてブックマークが再生成されたときにのみ動作するように見えます。 フォルダ/ファイルを再度移動/名前を変更する必要はありません。

最初にブックマークを作成して保存する方法

-(IBAction)bookmarkFolder:(id)sender {
  _openPanel = [NSOpenPanel openPanel];
  _openPanel.canChooseFiles = NO;
  _openPanel.canChooseDirectories = YES;
  _openPanel.canCreateDirectories = YES;
  [_openPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
    if (_openPanel.URL != nil) {
      NSError *error;
      NSData *bookmark = [_openPanel.URL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
                                  includingResourceValuesForKeys:nil
                                                   relativeToURL:nil
                                                           error:&error];
      if (error != nil) {
        NSLog(@"Error bookmarking selected URL: %@", error);
        return;
      }
      NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
      [userDefaults setObject:bookmark forKey:@"bookmark"];
    }
  }];
}

ブックマークを解決するコード

-(void)resolveStoredBookmark {
  NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
  NSData *bookmark = [userDefaults objectForKey:@"bookmark"];
  if (bookmark == nil) {
    NSLog(@"No bookmark stored");
    return;
  }
  BOOL isStale;
  NSError *error;
  NSURL *url = [NSURL URLByResolvingBookmarkData:bookmark
                                         options:NSURLBookmarkResolutionWithSecurityScope
                                   relativeToURL:nil
                             bookmarkDataIsStale:&isStale
                                           error:&error];
  if (error != nil) {
    NSLog(@"Error resolving URL from bookmark: %@", error);
    return;
  } else if (isStale) {
    if ([url startAccessingSecurityScopedResource]) {
      NSLog(@"Attempting to renew bookmark for %@", url);
      // NOTE: This is the bit that fails, a 256 error is 
      //       returned due to a deny file-read-data from sandboxd
      bookmark = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
               includingResourceValuesForKeys:nil
                                relativeToURL:nil
                                        error:&error];
      [url stopAccessingSecurityScopedResource];
      if (error != nil) {
        NSLog(@"Failed to renew bookmark: %@", error);
        return;
      }
      [userDefaults setObject:bookmark forKey:@"bookmark"];
      NSLog(@"Bookmark renewed, yay.");
    } else {
      NSLog(@"Could not start using the bookmarked url");
    }
  } else {
    NSLog(@"Bookmarked url resolved successfully!");
    [url startAccessingSecurityScopedResource];
    NSArray *contents = [NSFileManager.new contentsOfDirectoryAtPath:url.path error:&error];
    [url stopAccessingSecurityScopedResource];
    if (error != nil) {
      NSLog(@"Error reading contents of bookmarked folder: %@", error);
      return;
    }
    NSLog(@"Contents of bookmarked folder: %@", contents);
  }
}

ブックマークが古くなった場合、解決された解決済みのURLは正しい場所を指しています。[url startAccessingSecurityScopedResource]がYESを返すにもかかわらず、実際にはファイルにアクセスできません。

おそらく私は失礼したブックマークに関するドキュメントを誤解していますが、私はちょっとばかげたことをやっていたいと思っています。 ブックマークされたファイル/フォルダの名前を変更したり移動したりするたびにNSOpenPanelをポップすると、私の唯一の選択肢はばかばかしいようです。

私は、 com.apple.security.files.bookmarks.app-scopecom.apple.security.files.user-selected.read-write 、およびcom.apple.security.app-sandboxがすべてtrueに設定されていることを追加する必要があります私の権利ファイルで。


私は多くの失望したテストの後、次の結論に至りました。 論理的ではあるが、ユーザーにとっての経験は理想とはかけ離れており、ユーザーがブックマークされたリソースへの参照を再構築するのに役立つかどうかによって、開発者にとって大きな痛みとなるため、残念だ。

私が「更新する」と言うとき、「古いブックマークから解決されたURLを使って古いブックマークを置き換える新しいブックマークを生成する」という意味です。

  1. ブックマークされたリソースが、アプリケーションにアクセス権を持つディレクトリ内で移動または名前変更されている限り、更新は常に機能します。 したがって、デフォルトでは、常にアプリケーションのコンテナフォルダ内で動作します。

  2. ブックマークされたリソースがアプリケーションにアクセス権がないフォルダに移動さ​​れた場合、更新は失敗します。 例えば、ユーザはコンテナフォルダからフォルダをコンテナフォルダの外のあるフォルダにドラッグする。 URLを解決できますが、ブックマークにアクセスしたり更新したりすることはできません。

  3. ブックマークされたリソースがアプリケーションにアクセスできないフォルダに保存され、名前が変更された場合、更新は失敗します。 つまり、ユーザーはアプリケーションにリソースへのアクセス権を明示的に付与し、名前を変更するだけで間違ってそのアクセス権を取り消すことができます。

  4. リソースを別のボリュームに移動すると、解決に失敗します。 これがブックマークの一般的な制限であるのか、サンドボックスアプリケーションでの使用の場合だけであるかはわかりません。

2と3の問題では、ブックマークされたURLの解決が機能するので、開発者としてはまともな立場にいます。 あなたは、少なくともあなたのアプリへのアクセスを許可する必要があるリソースとその場所を正確に伝えることで、ユーザーを導くことができます。 ブックマークを更新する必要があるすべてのリソースが(直接的または間接的に)含まれているフォルダを選択することで、エクスペリエンスを向上させることができます。 これはボリュームであっても、アプリケーションに多くのアクセス権を与えることができれば問題を完全に解決できます。

問題4については、解決はまったく機能しません。 新しい場所を解決できないため、ヒントなしでファイルの場所を変更する必要があります。 私の現在のアプリでこの問題の苦痛を軽減したことの1つは、ブックマークを保存するすべてのリソースに拡張属性を追加することです。 これを行うと、ユーザーは以前に関連付けられたリソースを検索するためのフォルダを選択できるようになります。

しかし、ブックマークは静的パスの保存に勝っています。