How does OS X's defaults command get access to prefs of sandboxed apps?

和自甴很熟 提交于 2020-08-22 05:16:49

问题


I am writing a preferences editor tool (see http://www.tempel.org/PrefsEditor). It is effectively a GUI version of the defaults command.

I have trouble reading (let alone writing) preferences of random sandboxed applications, though.

For instance, when I try to get the keys of the Maps app, I get NULL returned:

CFArrayRef prefs = CFPreferencesCopyKeyList (CFSTR("com.apple.Maps"), kCFPreferencesCurrentUser, kCFPreferencesAnyHost);

However, the defaults command is able to read those prefs:

defaults read com.apple.Maps

I like to know how the defaults command accomplishes this, trying to do the same in my tool.


回答1:


try that:

CFPropertyListRef prop = CFPreferencesCopyValue(CFSTR("ElementsVersion"),
CFSTR("/Users/karsten/Library/Containers/com.apple.Maps/Data/Library/Preferences/com.apple.Maps"),
CFSTR("kCFPreferencesCurrentUser"),
CFSTR("kCFPreferencesAnyHost"));

seems you need the path to the file, not just the bundle-id




回答2:


Karsten’s answer is correct but for the sake of completeness, the defaults command uses the undocumented _CFPreferencesCopyApplicationMap() function to retrieve the full URL of the preferences.

#import <CoreFoundation/CoreFoundation.h>

extern CFDictionaryRef _CFPreferencesCopyApplicationMap(CFStringRef userName, CFStringRef hostName);

int main(int argc, char *argv[])
{
    @autoreleasepool
    {
        CFDictionaryRef applicationMap = _CFPreferencesCopyApplicationMap(kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
        CFArrayRef urls = CFDictionaryGetValue(applicationMap, CFSTR("com.apple.mail"));
        CFShow(urls);
        CFRelease(applicationMap);
    }
}



回答3:


I've added to 0xced's excellent answer so that the code can be packaged into a command-line tool that accepts the bundle ID as an argument. Forgive me if this is obvious to experienced Mac programmers, but as someone who has never used CoreFoundation I found this to be non-trivial.

#import <CoreFoundation/CoreFoundation.h>

extern CFDictionaryRef _CFPreferencesCopyApplicationMap(CFStringRef userName, CFStringRef hostName);

int main(int argc, char *argv[]) {
    @autoreleasepool {
        if (argc < 2) {
            // Print usage string & exit.
            fprintf(stderr, "usage: GetPrefDomains bundle_id\n");
            exit(1);
        }
        
        // Get the bundle ID from the first command-line argument.
        CFStringRef bundleID = CFStringCreateWithCString(NULL, argv[1], kCFStringEncodingUTF8);
        
        // Get the list of preference domain urls.
        CFDictionaryRef applicationMap = _CFPreferencesCopyApplicationMap(kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
        CFArrayRef urls = CFDictionaryGetValue(applicationMap, bundleID);
        
        // If no urls exist (invalid bundle ID), exit.
        if (!urls) {
            fprintf(stderr, "No preference domains found.\n");
            exit(0);
        }
        
        // Print the paths to the preference domains.
        CFIndex urlsCount = CFArrayGetCount(urls);
        for (int i = 0; i < urlsCount; i++) {
            CFURLRef url = CFArrayGetValueAtIndex(urls, i);
            CFStringRef path = CFURLCopyPath(url);
            printf("%s\n", CFStringGetCStringPtr(path, kCFStringEncodingUTF8));
        }
        
        // Clean up.
        CFRelease(bundleID);
        CFRelease(applicationMap);
    }
}

Save the code as GetPrefDomains.m, compile, and invoke as: GetPrefDomains com.apple.mail

This was useful to me because surprisingly the defaults command is case-sensitive and misbehaves silently with certain Apple applications that are under the filesystem protections in SIP on Mojave 10.14 or later (Safari & Mail, most notably). Add in the fact that Apple's capitalization rules are not consistent (com.apple.mail vs. com.apple.Notes), sandboxed preference paths, and the fact that that the filesystem is not case-sensitive and you quickly run into some very frustrating edge cases.



来源:https://stackoverflow.com/questions/20705279/how-does-os-xs-defaults-command-get-access-to-prefs-of-sandboxed-apps

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!