Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing the desktop in a Sandboxed app

I'm building an application that has a feature to open newly taken screenshots. I would like to distribute it using the Mac App Store. Unfortunately, it needs to be sandboxed.

To find the new screenshots I run a NSMetaDataQuery. It returns a few entries but unfortunately I can't get their URL since they are on the Desktop (out of my app's sandbox).

How can I fix this ?

Here is some of the code

query = [[NSMetadataQuery alloc] init];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryUpdated:) name:NSMetadataQueryDidStartGatheringNotification object:query];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryUpdated:) name:NSMetadataQueryDidUpdateNotification object:query];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryUpdated:) name:NSMetadataQueryDidFinishGatheringNotification object:query];

[query setDelegate:self];
[query setPredicate:[NSPredicate predicateWithFormat:@"kMDItemIsScreenCapture = 1"]];
[query startQuery];

numberOfScreenshots = [query resultCount];
[self uploadToAmazonS3:[[[query results]objectAtIndex:([query resultCount]-1)]valueForAttribute:NSMetadataItemURLKey]];

Thanks

like image 944
BrainOverfl0w Avatar asked Aug 28 '12 05:08

BrainOverfl0w


2 Answers

Without asking user permission, you can access only Music, Movies, Pictures and Download folders. Entitlements

You have to ask user, to grant you access to Desktop Folder. Then use mechanism called Security-Scoped Bookmarks, read more about it in AppSandboxDesignGuide.

  1. Use NSOpenPanel to choose directory.
  2. Save bookmark for future use, for example in NSUserDefaults.
  3. Get access

1 and 2

    NSOpenPanel *openPanel = [[NSOpenPanel alloc] init];
    [openPanel setCanChooseFiles:NO];
    [openPanel setCanChooseDirectories:YES];
    [openPanel setCanCreateDirectories:YES];

    [openPanel beginWithCompletionHandler:^(NSInteger result){
        if (result == NSFileHandlingPanelOKButton) {
            for (NSURL *fileURL in [openPanel URLs]) {
                NSString *filename = [fileURL path];
                [[NSUserDefaults standardUserDefaults] setObject:filename forKey:@"PathToFolder"];

                NSError *error = nil;
                NSData *bookmark = [fileURL bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
                     includingResourceValuesForKeys:nil
                                      relativeToURL:nil
                                              error:&error];
                if (error) {
                    NSLog(@"Error creating bookmark for URL (%@): %@", fileURL, error);
                    [NSApp presentError:error];
                } else {
                    [[NSUserDefaults standardUserDefaults] setObject:bookmark forKey:@"PathToFolder"];
                    [[NSUserDefaults standardUserDefaults] synchronize];
                }
                break;
            }
        }        
}];

3.

    NSError *error = nil;
    NSData *bookmark = [[NSUserDefaults standardUserDefaults] objectForKey:@"PathToFolder"];
    bookmarkedURL = [NSURL URLByResolvingBookmarkData:bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:nil error:&error];
    BOOL ok = [bookmarkedURL startAccessingSecurityScopedResource];
    NSLog(@"Accessed ok: %d %@", ok, [bookmarkedURL relativePath]);

So, that sould be it.

like image 94
pawelropa Avatar answered Nov 15 '22 06:11

pawelropa


After you have allowed access you also need to get the path to the real home folder - all the other file APIs only provide the path to the sandboxed folder even when access to the real one as been enabled. To get around this annoying problem, Apple recommend doing this to get the real home folder:

#include <sys/types.h>
#include <pwd.h>

const char *home = getpwuid(getuid())->pw_dir;
NSString *path = [[NSFileManager defaultManager] 
                  stringWithFileSystemRepresentation:home
                  length:strlen(home)];
NSString *realHomeDirectory = [[NSURL fileURLWithPath:path isDirectory:YES] path];
like image 42
malhal Avatar answered Nov 15 '22 06:11

malhal