4
votes

In my Mac OS X application I tried to save downloaded files to application's directory(i.e. HomeDirectory()/Documents) but App Store rejected my application saying that your downloaded file is not accessible to the user easily( i.e. without opening the app). Then I tried to write the downloaded files to ~/Downloads folder by adding Read/Write permission in entitlements, but App Store again reject the application saying

Your application accesses the following location(s):

~/Download

The majority of developers encountering this issue are opening files in Read/Write mode instead of Read-Only mode, in which case it should be changed to Read-Only.

Other common reasons for this issue include:

  • creating or writing files in the above location(s), which are not valid locations for files to be written as stated in documentation.

  • writing to the above location(s) without using a valid app-id as a container for the written files.

Now the issue is App Store is neither allow me to save the files in App's Directory nor in System's folder(i.e. Downloads). Also I Don't want to use NSSavePanel every time. I want to download the files silently. Where should I save my files?

1
What kind of files are they? Is the user explicitly choosing “hey, download this file” in the UI or is this download something that your app does on its own (e.g. some asset it needed to download)? A little more context about the nature of the download might be helpful.Rob
@Rob No, my app does not provide UI to download the files. My app download the files by it's own by checking on server if any file available for download. If available, it start downloading the files and as of now I was trying to save those downloaded files to user's ~/Downloads folder which is not acceptable by App Store Review process. It's very hectic to ask user every time where do you want to save this files.Mahadev Mandale
@Rob Thanks for you quick replay. The files are like audio, doc files. End user do need to access this files. At very first I did tried to save the files to app's directory and provides the UI to access those files to user but Apple says "Your app saves user data to the app's container, which is not user accessible." even though I had provided the UI in the App. Then in next release I changed the save location from app's container to ~?Downloads but now Apple says "Your application accesses the following location(s): ~/Download "Mahadev Mandale
Continue.... "The majority of developers encountering this issue are opening files in Read/Write mode instead of Read-Only mode, in which case it should be changed to Read-Only. Other common reasons for this issue include: - creating or writing files in the above location(s), which are not valid locations for files to be written as stated in documentation. - writing to the above location(s) without using a valid app-id as a container for the written files."Mahadev Mandale
And yes, these audio and doc files can be opened by variety of apps.Mahadev Mandale

1 Answers

2
votes

With the help of Security-Scoped Bookmark, user-selected read-write entitlement and NSOpenPanel I was abled to read/write to user selected folder.

Below are the steps I followed,

  1. Added

    <key>com.apple.security.app-sandbox</key>
    <true/>
    
    <key>com.apple.security.files.bookmarks.app-scope</key>
    <true/>
    
    <key>com.apple.security.files.user-selected.read-write</key>
    <true/>
    

    in Entitlements file.

  2. Asked the user to select(or create and select) the desired folder to which my application want to access(read/write) using NSOpenPanel.

  3. When user selects the folder, I created the bookmark of selected folder path as bookmarked path in NSUserDefaults using NSURLBookmarkCreationWithSecurityScope.

    NSOpenPanel *openDlg = [NSOpenPanel openPanel];
    
    [openDlg setCanChooseDirectories:YES];
    
    [openDlg setCanCreateDirectories:YES];
    
    [openDlg setAllowsMultipleSelection:FALSE];
    
    [openDlg setPrompt:@"Select"];
    
    if ( [openDlg runModal] == NSModalResponseOK )
    {
    
        NSURL *url = openDlg.URL;
    
        NSError *error = nil;
    
        NSData *bookmark = [url 
                      bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
                      includingResourceValuesForKeys:nil
                                  relativeToURL:nil
                                          error:&error];
    
        NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    
        [userDefaults setObject:bookmark forKey:@"DOWNLOAD_FOLDER_BOOKMARK_PATH"];
    
        [userDefaults synchronize];
    
    }
    
  4. Once you saved the bookmarked path in NSUserDefaults you can access the saved path later using NSURLBookmarkResolutionWithSecurityScope.

     NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    
     NSData * bookmarkedPathData = [userDefaults objectForKey:@"DOWNLOAD_FOLDER_BOOKMARK_PATH"];
    
     NSURL* urlFromBookmark = [NSURL URLByResolvingBookmarkData:bookmarkedPathData 
     options:NSURLBookmarkResolutionWithSecurityScope
                                                     relativeToURL:nil
                                               bookmarkDataIsStale:nil
                                                             error:&error];
    
  5. Once you got the saved Bookmarked URL you can use that URL to perform read, write operation. Before reading/writing from/to the URL, please start the scope using [urlFromBookmark startAccessingSecurityScopedResource]; . And after finishing read/write operation stop the scope using [saveFolder stopAccessingSecurityScopedResource];

Note: I did tried to write to directly to Documents, Downloads, Desktop without creating folder inside these directories but Apple rejected the app, saying

Your application access the following locations 'Downloads'.

Then instead of writing directly to these directories( Documents, Downloads, Desktop), I asked the user to select(create & select) a folder, then performed the read/write operations on user selected folder using Security-Scope-Bookmark.

Hope this helps someone.