【问题标题】:How to handle with a default URL scheme如何处理默认 URL 方案
【发布时间】:2010-12-31 18:07:55
【问题描述】:

我想在我的应用中构建 URI(或 URL 方案)支持。

我在我的+ (void)initialize 中做了一个LSSetDefaultHandlerForURLScheme(),我也在我的info.plist 中设置了特定的 URL 方案。所以我有没有Apple ScriptApple Events 的URL 方案。

当我在我最喜欢的浏览器中拨打myScheme: 时,系统会激活我的应用程序。

问题是,当它们被调用时如何处理它们。或者更好的说法是:当myScheme: 被调用时,我如何定义我的应用应该做什么。

是否有我必须实施的特殊方法,或者我必须在某处注册一个?

【问题讨论】:

    标签: macos cocoa url-scheme appkit


    【解决方案1】:

    当您提到 AppleScript 时,我想您正在使用 Mac OS X。

    注册和使用自定义 URL 方案的一种简单方法是在 .plist 中定义方案:

    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>URLHandlerTestApp</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>urlHandlerTestApp</string>
            </array>
        </dict>
    </array>
    

    要注册方案,请将其放入 AppDelegate 的初始化中:

    [[NSAppleEventManager sharedAppleEventManager]
        setEventHandler:self
            andSelector:@selector(handleURLEvent:withReplyEvent:)
          forEventClass:kInternetEventClass
             andEventID:kAEGetURL];
    

    每当您的应用程序通过 URL 方案激活时,都会调用定义的选择器。

    事件处理方法的存根,显示如何获取 URL 字符串:

    - (void)handleURLEvent:(NSAppleEventDescriptor*)event
            withReplyEvent:(NSAppleEventDescriptor*)replyEvent
    {
        NSString* url = [[event paramDescriptorForKeyword:keyDirectObject]
                            stringValue];
        NSLog(@"%@", url);
    }
    

    Apple 的文档:Installing a Get URL Handler

    更新 我刚刚注意到在applicationDidFinishLaunching: 中安装事件处理程序的沙盒应用程序存在问题。启用沙盒后,通过单击使用自定义方案的 URL 启动应用程序时,不会调用处理程序方法。 通过早一点安装处理程序,在applicationWillFinishLaunching: 中,该方法被按预期调用:

    - (void)applicationWillFinishLaunching:(NSNotification *)aNotification
    {
        [[NSAppleEventManager sharedAppleEventManager]
            setEventHandler:self
                andSelector:@selector(handleURLEvent:withReplyEvent:)
              forEventClass:kInternetEventClass
                 andEventID:kAEGetURL];
    }
    
    - (void)handleURLEvent:(NSAppleEventDescriptor*)event
            withReplyEvent:(NSAppleEventDescriptor*)replyEvent
    {
        NSString* url = [[event paramDescriptorForKeyword:keyDirectObject]
                            stringValue];
        NSLog(@"%@", url);
    }
    

    在 iPhone 上,处理 URL 方案激活的最简单方法是实现 UIApplicationDelegate 的 application:handleOpenURL: - Documentation

    【讨论】:

    • 愚蠢的问题,但是 AppDelegate 的初始化到底在哪里?哪种方法?
    • 什么是keyDirectObject,它在哪里定义?我不明白 keyDirectObject 的价值应该是什么。谢谢。
    • 对于那些像我一样想知道的人,“keyDirectObject 如何在没有语法错误的情况下编译缺少符号?”,它在 AE/AppleEvents.h 中定义为枚举案例。不知何故,AE/AppleEvents.h 会被包含在您的应用中,即使您没有直接包含它。
    • 如果您的目标是 macOS 10.13 及更高版本,您可以使用新的 NSApplicationDelegate 方法 func application(_ application: NSApplication, open urls: [URL]) -- 无需注册 NSAppleEventManager,只需在您的应用委托中实现该方法。
    • 如何注册我的应用程序以用于我的自定义 URL? LSSetDefaultHandlerForURLScheme 返回 -54,我将其翻译为“沙盒说不”(osstatus.com/search/…)。
    【解决方案2】:

    所有学分都应归 weichselkch

    为了您的方便,我只是添加了 swift(2.2/3.0) 代码

    func applicationWillFinishLaunching(_ notification: Notification) {
        NSAppleEventManager.shared().setEventHandler(self, andSelector: #selector(self.handleGetURL(event:reply:)), forEventClass: UInt32(kInternetEventClass), andEventID: UInt32(kAEGetURL) )
    }
    
    @objc func handleGetURL(event: NSAppleEventDescriptor, reply:NSAppleEventDescriptor) {
        if let urlString = event.paramDescriptor(forKeyword: keyDirectObject)?.stringValue {
            print("got urlString \(urlString)")
        }
    }
    

    【讨论】:

    • 不知道有没有办法避免应用在接收到URL时被激活发送到前台?
    【解决方案3】:

    问题是,在调用方案时如何处理它们。

    这就是 Apple 事件的用武之地。当 Launch Services 希望您的应用打开一个 URL 时,它会向您的应用发送一个 kInternetEventClass/kAEGetURL 事件。

    The Cocoa Scripting Guide 使用this very task as an example of installing an event handler

    【讨论】:

      【解决方案4】:

      我只是添加了稍微不同的 Swift 4/5 版本的代码:

      func applicationWillFinishLaunching(_ notification: Notification) {
          NSAppleEventManager
              .shared()
              .setEventHandler(
                  self,
                  andSelector: #selector(handleURL(event:reply:)),
                  forEventClass: AEEventClass(kInternetEventClass),
                  andEventID: AEEventID(kAEGetURL)
              )
      
      }
      
      @objc func handleURL(event: NSAppleEventDescriptor, reply: NSAppleEventDescriptor) {
          if let path = event.paramDescriptor(forKeyword: keyDirectObject)?.stringValue?.removingPercentEncoding {
              NSLog("Opened URL: \(path)")
          }
      }
      

      【讨论】:

      • 不知道有没有办法避免应用在接收到URL时被激活发送到前台?
      【解决方案5】:

      您可以在脚本术语 SDEF 中定义“获取 URL”命令并实现相应的方法。例如,终端的 SDEF 包含以下用于处理 URL 的命令定义

      <command name="get URL" code="GURLGURL" description="Open a command an ssh, telnet, or x-man-page URL." hidden="yes">
          <direct-parameter type="text" description="The URL to open." />
      </command>
      

      并声明应用程序对其进行响应:

      <class name="application" code="capp" description="The application's top-level scripting object.">
          <cocoa class="TTApplication"/>
          <responds-to command="get URL">
              <cocoa method="handleGetURLScriptCommand:" />
          </responds-to>
      </class>
      

      TTApplication 类(NSApplication 的子类)定义了方法:

      - (void)handleGetURLScriptCommand:(NSScriptCommand *)command { … }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-03
        • 1970-01-01
        • 1970-01-01
        • 2019-07-28
        • 1970-01-01
        • 2015-02-14
        • 2014-07-30
        • 2011-03-15
        相关资源
        最近更新 更多