Reputation: 447
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
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,
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.
Asked the user to select(or create and select) the desired folder to which my application want to access(read/write) using NSOpenPanel.
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];
}
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];
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