OS X的默认命令如何访问沙盒应用的首选项?

时间:2013-12-20 13:59:46

标签: macos sandbox

我正在编写首选项编辑器工具(请参阅http://www.tempel.org/PrefsEditor)。它实际上是defaults命令的GUI版本。

我无法阅读(更不用说写)随机沙盒应用程序的首选项了。

例如,当我尝试获取Maps应用程序的键时,我返回NULL:

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

但是,defaults命令能够读取这些首字母:

defaults read com.apple.Maps

我想知道defaults命令如何实现这一点,尝试在我的工具中执行相同操作。

3 个答案:

答案 0 :(得分:4)

试试:

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

似乎你需要文件的路径,而不仅仅是bundle-id

答案 1 :(得分:4)

Karsten的回答是正确的,但为了完整起见,defaults命令使用未记录的_CFPreferencesCopyApplicationMap()函数来检索首选项的完整URL。

#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);
    }
}

答案 2 :(得分:1)

我已经在0xced的出色答案中添加了代码,以便可以将代码打包到接受捆绑ID作为参数的命令行工具中。如果这对有经验的Mac程序员来说是显而易见的,请原谅我,但是作为从未使用过CoreFoundation的人,我发现这并不简单。

#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);
    }
}

将代码另存为GetPrefDomains.m,编译并调用为: GetPrefDomains com.apple.mail

这对我很有用,因为令人惊讶的是defaults命令区分大小写,并且在Mojave 10.14或更高版本(Safari&Mail,最著名)上受SIP文件系统保护的某些Apple应用程序无声地表现。再加上苹果的大小写规则不一致(com.apple.mailcom.apple.Notes),沙盒偏好路径以及文件系统不区分大小写和 的事实。您很快就会遇到一些非常令人沮丧的边缘情况。