Mahadev Mandale
Mahadev Mandale

Reputation: 447

How to save downloaded files(audio, doc) automatically to user's Downloads folder in mac os x sandboxed application?

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?

Upvotes: 5

Views: 404

Answers (1)

Mahadev Mandale
Mahadev Mandale

Reputation: 447

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.

Upvotes: 3

Related Questions