开发者

Access iTunes user preferences in OSX Lion

开发者 https://www.devze.com 2023-04-06 14:24 出处:网络
I want to access iTunes user preferences such as playlists programmatically. I use to do it with the following code, however since OSX Lion, I get a nil in response.

I want to access iTunes user preferences such as playlists programmatically.

I use to do it with the following code, however since OSX Lion, I get a nil in response.

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSDictionary *use开发者_StackOverflowrPreferences = [userDefaults persistentDomainForName:@"com.apple.iApps"];

NSArray *databasePaths = [userPreferences objectForKey:@"iTunesRecentDatabasePaths"];

I've also made sure my app has all of its entitlements enabled.

Any suggestions on how I can fix this?


Long story made short: You just can not do it using a Sandboxed app. Turn off Sandboxing and you will see that it works. Why? Well, that's because of containers. A sandbox lives in its own container and so when you call [NSUserDefaults standardUserDefaults] Cocoa uses the path of your container rather than the POSIX path of ~/Library/Preferences which is where com.apple.iApps.plist resides. That sums up why you get nil. Also, there is a blurb on this here in NSUserDefaults: link

How to fix this?

It's really not to bad. First you have to do a little bit of work to get the POSIX path of your home directory. I setup a bunch of NSURL category methods. However the root path is POSIX based. Here is the code snippet to get you started.

1.

+ (NSURL *) homePOSIXURL {
struct passwd *pwUser  = getpwuid(getuid());     
const char    *homeDir = pwUser->pw_dir;
return [NSURL fileURLWithPath:[NSString stringWithUTF8String:homeDir] isDirectory:YES]; }

When all is said and done, construct a full path to the plist. It hasn't changed for years so you can consider it sticky.

So you might get something that looks like this now:

2.

    NSURL * prefURL = [[NSURL libraryPOSIXURL] URLByAppendingPathComponent:@"Preferences" isDirectory:YES];
    prefURL = [prefURL URLByAppendingPathComponent:@"com.apple.iApps.plist"];

Now let's turn this plist, which is fairly small into something we can play with. Perhaps NSData? That sounds good, right?

3.

 NSData * prefData = [NSData dataWithContentsOfURL:prefURL];

Ok, finally we can use this now to get an NSDictionary. Here is how I do it.

4.

NSDictionary * prefDict = [NSDictionary collectionFromPropertyList:prefData];

Yeah, yeah another Category on NSDictionary. I must have a million of them.

Because I'm in a sharing mood, here ya go:

+ (id) collectionFromPropertyList:(NSData *)pList {

    if ( [pList length] > 0 )
        return [NSPropertyListSerialization propertyListWithData:pList 
                                                         options:NSPropertyListImmutable 
                                                          format:nil error:nil];
    return nil;
}

So, you think we are done? Well, almost. If you get this far, you will get a deny like so:

deny file-read-data /Users/UserName/Library/Preferences/com.apple.iApps.plist

Are we loving our Sandboxed app?! Basically add your temporary entitlement and you should be off to the races again. Best of luck to ya!

0

精彩评论

暂无评论...
验证码 换一张
取 消