Cocoa обработчик протокола с использованием NSAppleEventManager и kInternetEventClass/kAEGetURL

Это версия Cocoa этого вопроса:

Обработчик AEInstallEventHandler не запускается при запуске

Здесь моя регистрация протокола Info.plist:

    ...
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>My Protocol</string>
            <key>CFBundleURLIconFile</key>
            <string>myicon</string>
            <key>CFBundleTypeRole</key>
            <string>Viewer</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>myapp</string>
            </array>
        </dict>
    </array>

Здесь, где я устанавливаю метод для прослушивания события kInternetEventClass/kAEGetURL, когда на ссылку браузера вызывается ссылка "myapp://unused/? a = 123 & b = 456":

- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
    [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(getURL:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
    ...
}

Здесь метод обработчика:

- (void)getURL:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)reply
{
    [[[event paramDescriptorForKeyword:keyDirectObject] stringValue] writeToFile:@"/testbed/complete_url.txt" atomically:YES];
}

Здесь тестовая веб-ссылка:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
</head>
<body>
    <a href="myapp://open/?a=123&b=456">Open My App</a>
</body>
</html>

Все это отлично работает, если приложение уже запущено.

Вызывается метод обработчика и фиксируется полный URL-адрес.

Однако, если приложение еще не запущено, эта же ссылка запустит приложение, но обработчик не будет вызван - что имеет смысл, поскольку обработчик еще не был связан с событием.

Те аргументы в URL-адресе важны для нашего приложения для координации с webapp. Хотя в большинстве случаев наше приложение уже работает при нажатии этого клика, разумно ожидать, что в некоторых случаях он не будет.

Я попытался проверить параметры среды и обработать вызовы, и я не вижу URL-адреса в любом из них.

Кто-нибудь знает, как можно надежно зафиксировать этот URL-адрес, даже если наше приложение еще не запущено при нажатии браузера?

Ответ 1

Яблоки SimpleScriptingPlugin sample регистрируют обработчик в applicationWillFinishLaunching:, что, вероятно, более чистое, чем использование init. (И, как сказал миккер, обработчик получает вызов до applicationDidFinishLaunching:.)

Ответ 2

Я столкнулся с этой точной проблемой. Я не знаю, правильно ли это решение, но вы можете зарегистрировать обработчик событий в делетете приложения init -method.

// in AppDelegate.m

- (id)init
{
  self = [super init];

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

  return self;
}

Следует отметить, что handleURLEvent:withReplyEvent получает вызов до applicationDidFinishLaunching:, если приложение запускается с помощью схемы URL.