Sandboxing...

Discussion in 'Mac Programming' started by ArtOfWarfare, Feb 9, 2012.

  1. macrumors 603

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #1
    How can I make my app sandbox compliant? The list of things it does that I'm not sure whether are okay or not are...

    - It calls IOReg and collects information on various devices (name, battery percent, whether it's charging, etc.,)
    - It makes an NSStatusItem.
    - It stores a bunch of data into NSUserDefaults
    - It modifies whether it is a launch item or not. The code it uses to do this is below:

    Code:
    - (NSArray *)loginItems
    {
        CFArrayRef snapshotRef = LSSharedFileListCopySnapshot(loginItemsListRef, NULL);
        return (__bridge NSArray *)snapshotRef;
    }
    
    // Return a CFRetained item for the app's bundle, if there is one.
    - (LSSharedFileListItemRef)mainBundleLoginItemCopy
    {
        NSArray *loginItems = [self loginItems];
        NSURL *bundleURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
        
        for (id item in loginItems) {
            LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
            CFURLRef itemURLRef;
            
            if (LSSharedFileListItemResolve(itemRef, 0, &itemURLRef, NULL) == noErr) {
                // Again, use toll-free bridging.
                NSURL *itemURL = (__bridge NSURL *)itemURLRef;
                if ([itemURL isEqual:bundleURL])
                {
                    return (__bridge LSSharedFileListItemRef)item;
                }
            }
        }
        
        return NULL;
    }
    
    - (BOOL)launchOnLogin
    {
        if (!loginItemsListRef)
            return NO;
        
        LSSharedFileListItemRef itemRef = [self mainBundleLoginItemCopy];    
        if (!itemRef)
            return NO;
        
        CFRelease(itemRef);
        return YES;
    }
    
    - (void)setLaunchOnLogin:(BOOL)value
    {
        if (!loginItemsListRef)
            return;
        
        if (!value) {
            [self removeMainBundleFromLoginItems];
        } else {
            [self addMainBundleToLoginItems];
        }
    }
    
    - (void)addMainBundleToLoginItems
    {
        // We use the URL to the app itself (i.e. the main bundle).
        NSURL *bundleURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
        
        NSDictionary *properties;
        properties = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:@"com.apple.loginitem.HideOnLaunch"];
        
        LSSharedFileListItemRef itemRef;
        itemRef = LSSharedFileListInsertItemURL(loginItemsListRef,
                                                kLSSharedFileListItemLast,
                                                NULL,
                                                NULL,
                                                (__bridge CFURLRef)bundleURL,
                                                (__bridge CFDictionaryRef)properties,
                                                NULL);
        if (itemRef) {
            CFRelease(itemRef);
        }
    }
    
    - (void)removeMainBundleFromLoginItems
    {
        // Try to get the item corresponding to the main bundle URL.
        LSSharedFileListItemRef itemRef = [self mainBundleLoginItemCopy];
        if (!itemRef)
            return;
        
        LSSharedFileListItemRemove(loginItemsListRef, itemRef);
        
        CFRelease(itemRef);
    }
    I guess I should have a more clear question: What, if anything, do I need to do to make my app sandbox compliant? Are there any entitlements I need to give it? Do I need to use different APIs? Is there any part that simply can't be done with sandboxing? (I fear that I may just have to give Battery Status a final update next week and then lie low and wait for Apple to remove it for not being sandbox compliant.)
     
  2. Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #2
    Did you read Apple's extensive documentation?
    https://developer.apple.com/devcenter/mac/app-sandbox/


    These are fine.

    This won't work. You will just have to make the user do this manually.

    If you have a helper app you want to launch at login, use SMLoginItemSetEnabled().
     
  3. thread starter macrumors 603

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #3
    Darn. Users specifically cite the ease of accessing the option as something they like in reviews of the app. Oh well, I guess if I want to update the app after March 1st it'll have to have the option replaced with a note explaining that only system preferences is non-hackable enough to be allowed to have such an ability to change which apps are allowed to launch at log-in. And provide instructions with how to add (or remove) it as a launch item, of course.
     

Share This Page