默认情况下,有一个MainMenu.xib关联该应用程序。收下。它由Info.plist使用,它对于调试很有用。事实上,要调试自定义URL方案,可以将NSWindow添加到该xib,并放置可用于显示调试消息的标签。在调试此问题时,我找不到其他方式记录或显示调试消息。
接下来,应用程序的实现需要注册的URL方案告诉系统有一个应用程序,它能够打开它。在app的AppDelegate中我的“appDidFinishLaunching”方法的实现下面。
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
[appleEventManager setEventHandler:self andSelector:@selector(handleAppleEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
[[NSUserDefaults standardUserDefaults] addSuiteNamed:suiteName];
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:suiteName];
NSString *optionsPath = [[NSBundle mainBundle] pathForResource:@"defaultOptions" ofType:@"plist"];
NSDictionary *defaultOptions = [NSDictionary dictionaryWithContentsOfFile:optionsPath];
[defaults registerDefaults:defaultOptions];
}
的suiteName
变量是一个静态的NSString与反向DNS格式:static NSString *suiteName = @"com.onekiloparsec.qlfitsconfig.user-defaults-suite";
然后,应用程序需要在所述事件的触发作用。因此,必须对事件做些事情,并使用该事件来存储偏好。这是实施。请注意,方法的签名必须正好是那个,而不是因为我们在上面声明它,而是因为这是系统唯一认可的方法。
- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
NSString *URLString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
if (URLString) {
NSURL *URL = [NSURL URLWithString:URLString];
if (URL) {
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:suiteName];
for (NSString *component in [URL pathComponents]) {
if ([component containsString:@"="]) {
NSArray *keyValue = [component componentsSeparatedByString:@"="];
[defaults setObject:keyValue.lastObject forKey:keyValue.firstObject];
}
}
[defaults synchronize];
}
}
}
其基本思想是我们将通过URL参数提供首选项作为键值对。因此,我们在这里将该URL字符串转换为一对首选项,这些首选项存储为字符串。
这就是所有的应用程序。为了测试和调试它,您需要构建并运行它(例如,使用正在运行的/ Utilities/Activity Monitor.app进行检查)。您可以键入以下命令到终端看看会发生什么:
$ open qlfitsconfig://save/option1=value1/option2=value2
如果你已经保持了上述标签的窗口,你可以用它们来显示/调试您的应用程序接收到什么事件。
现在回到QL发生器。在生成器的“构建阶段”中包含配置应用程序作为“目标依赖项”。此外,添加一个新的“复制文件”构建阶段(在复制包资源构建阶段之后)将该帮助应用程序复制到QL包中(见图片)。
现在,在代码中,更确切地说,方法预览方法中:OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options)
。
在开始时,我确定配置帮助应用程序实际上已注册到系统的启动服务。要找到它,必须使用QL生成器的包标识符。根据在Build阶段(Helpers
目录)中复制的位置,特别注意构建应用程序的URL的方式。
NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.onekiloparsec.QLFits3"];
NSURL *urlConfig = [NSURL fileURLWithPath:[[bundle bundlePath] stringByAppendingPathComponent:@"Contents/Helpers/QLFitsConfig.app"]];
LSRegisterURL((__bridge CFURLRef) urlConfig, true);
最后一行是使用传统的API,但我无法使新的工作。这是一个弱点,应该找到一个更好的方法。
现在,如果某些首选项已保存,则可以使用NSUserDefaults
的实例访问它们,前提是我们使用助手应用中定义的相同套件名称对其进行初始化。例如:
static NSString *suiteName = @"com.onekiloparsec.qlfitsconfig.user-defaults-suite";
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:suiteName];
BOOL alwaysShowHeaders = YES;
if ([defaults stringForKey:@"alwaysShowHeaders"]) {
alwaysShowHeaders = [[defaults stringForKey:@"alwaysShowHeaders"] isEqualToString:@"1"];
}
这就是Obj-C代码。
最后一部分是Javascript代码。在我的QL生成器(whose code can be checked on GitHub)中,我使用包含所有html和JS代码的template.html
文件。你可以在这里组织自己。
我首先打算在复选框切换时更改QL首选项。但它似乎不起作用(没有事件触发)。我做它的唯一方法是,一旦我的复选框设置,用户被要求使用按钮“保存”首选项。我点击该按钮后保存偏好设置。这是我template.html里面的JS代码
<script>
function saveConfig (a) {
a.href = "qlfitsconfig://save";
a.href += "/alwaysShowHeaders=" + (document.getElementById("alwaysShowHeadersInput").checked ? "1" : "0");
a.href += "/showSummaryInThumbnails=" + (document.getElementById("showSummaryInThumbnailsInput").checked ? "1" : "0");
return true;
}
</script>
alwaysShowHeadersInput
和showSummaryInThumbnailsInput
是我在HTML代码复选框的“身份证”。保存按钮正在触发saveConfig
功能。
而且按钮必须在a
标签中声明:
<a href="#" onClick="saveConfig(this);return true;" style="float:right;"><input id="save" type="button" value="Save"></a>
这里的喜好是什么样子,我QL窗口:
的Et瞧!