Пользовательский URI перенаправления в приложение MacOS не работает
Цель перенаправления
Я работаю над приложением, которое интегрируется с Cisco Webex Teams Api. К сожалению, для macOS у них нет SDK (у них есть только один для iOS), поэтому я пытаюсь аутентифицироваться с их типом Api "вручную".
Итак, я использую пользовательский URL -адрес с резервной копией идентификатора клиента для получения кода. При вызове этого URL -адреса запускается обычная процедура входа в систему Cisco, в которой пользователю предлагается войти в систему со своим именем пользователя и паролем. После успешного входа в систему сервер Cisco предоставит вам URL -адрес, содержащий код, необходимый для продолжения работы.
Что я получил так далеко
Пользовательский URL
Мой прототип в настоящее время просто состоит из кнопки, которая вызывает пользовательский URL для аутентификации. Чтобы получить этот URL, мне нужно было зарегистрировать свою интеграцию с Cisco здесь: https://developer.webex.com/my-apps
Пока, когда я нажимаю на мою кнопку, экземпляр WKWebView вступает во владение с моим пользовательским URL:
https://api.ciscospark.com/v1/authorize?client_id=<**personalClientId**>&response_type=code&redirect_uri=<**BundleIdentifier**>3A%2F%2Fredirect&scope=spark%3Aall%20spark%3Akms&state=set_state_here
URI перенаправления
Итак, мой URI перенаправления в настоящее время является ch.appfros.webexoauthwokflowprototype: // redirect; Этот URI перенаправления зарегистрирован в Cisco в моей регистрационной форме интеграции.
Я знаю, что я должен поместить этот URI перенаправления в мое приложение, поэтому я сделал это в результате соответствующего info.plist
раздел выглядит так:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>response</string>
<key>CFBundleURLSchemes</key>
<array>
<string>ch.appfros.webexoauthwokflowprototype://</string>
</array>
</dict>
</array>
Готовим AppDelegate
Насколько я сейчас выяснил, мне кажется, что мне нужно иметь дополнительную функцию в моем AppDelegate
, который обрабатывает обратный вызов. За cocoa
кажется, это func application(_ application: NSApplication, open urls: [URL])
метод.
Насколько я понимаю, мне пришлось бы обрабатывать все перенаправления там. мой AppDelegate
на данный момент выглядит так:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application)
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func application(_ application: NSApplication, open urls: [URL]) {
print("got answer")
}
}
У меня проблема
Моя проблема в том, что выполнение процедуры входа в систему приводит к сообщению There is no application set to open the URL ch.appfros.webexoauthwokflowprototype://redirect?code=
&state=loggedIn.
Итак, процесс аутентификации на стороне Cisco успешен, и он предоставляет моей системе URL -адрес, который мой компьютер не знает, как обрабатывать... Я даже вижу код, который мне нужен, чтобы получить доступ в URL -адресе, который приходит назад, у меня просто нет их в моем заявлении, чтобы продолжить...
Что мне не хватает?
Совершенно очевидно, что мне здесь не хватает чего-то важного - я просто не знаю, что это такое, и исследования в Интернете мне не помогут. Я мог бы найти кусочки здесь и там, но я все еще должен найти краткую инструкцию о том, что делать в моем случае для моего приложения MacOS.
Среда
- Xcode 10.1
- Swift 4.2
- Какао приложение
- Интеграция команд Cisco Webex с URL аутентификации
Изменить: изменения в AppDelegate
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application)
NSAppleEventManager.shared().setEventHandler(self, andSelector: #selector(self.handleAppleEvent(event:replyEvent:)), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func application(_ application: NSApplication, open urls: [URL]) {
print("got answer")
}
@objc
func handleAppleEvent(event: NSAppleEventDescriptor, replyEvent: NSAppleEventDescriptor) {
print("got answer in event handler")
}
}
Редактировать 2: обновить до AppDelegate (чтобы отразить советы и подсказки от NoHalfBits)
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application)
}
func applicationWillFinishLaunching(_ notification: Notification) {
NSAppleEventManager.shared().setEventHandler(self, andSelector: #selector(self.handleAppleEvent(event:replyEvent:)), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func application(_ application: NSApplication, open urls: [URL]) {
print("got answer")
}
@objc
func handleAppleEvent(event: NSAppleEventDescriptor, replyEvent: NSAppleEventDescriptor) {
print("got answer in event handler")
}
}
3 ответа
Оказывается, песочница действительно была проблемой. После отключения Sandboxing - это будет небольшой помощник в моей компании, ничего особенного и, конечно, ничего для любого магазина - это сработало сразу.
Если понадобится, мне придется посмотреть, как NSAppTransportSecurity
потребовалось бы для реализации - спасибо @NoHalfBits за то, что подтолкнули меня в правильном направлении.
Так что теперь у меня есть
- пользовательский URL зарегистрирован
- Песочница в приложении отключена
func application(_ application: NSApplication, open urls: [URL])
реализовано в моем AppDelegate (оказывается, этого действительно достаточно, как говорил @Aaron Raimist
Спасибо за вашу помощь; надеюсь, это поможет кому-то другому (или моему будущему себе) в будущем:-)
В Info.plist укажите схему URL в массиве под CFBundleURLSchemes
ключ без ://
суффикс (ch.appfros.webexoauthwokflowprototype
вместо ch.appfros.webexoauthwokflowprototype://
).
Кстати, Apple рекомендует использовать идентификатор стиля обратного DNS для CFBundleURLName
(название, а не сама схема).
Я настроил минимальный тестовый проект: Xcode 10.1, шаблон приложения Какао Swift. Часть Info.plist, определяющая пользовательскую схему:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>no.half.bits</string>
<key>CFBundleURLSchemes</key>
<array>
<string>nohalfbits</string>
</array>
</dict>
</array>
Делегат приложения просто:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
func application(_ application:NSApplication, open urls: [URL]) {
print("openURLs:", urls)
}
}
Это работает, как и ожидалось, при тестировании с небольшим инструментом командной строки:
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[])
{
@autoreleasepool
{
NSURL* url = [NSURL URLWithString:@"nohalfbits://hello.world"];
// is there app that handles the scheme, and where is it
NSLog(@"appURL = %@", [NSWorkspace.sharedWorkspace URLForApplicationToOpenURL:url]);
// actually open the url; the app should log this
[NSWorkspace.sharedWorkspace openURL:url];
}
return 0;
}
Я также добавил WKWebView в проект и позволил ему загружать минимальную веб-страницу с сервера, просто содержащую ссылку с пользовательской схемой - как и ожидалось, нажатие на эту ссылку запускает метод openURL с пользовательской схемой (пришлось добавить необходимую NSAppTransportSecurity
словарь в Info.plist и включить исходящие соединения в настройках песочницы проекта).
В прошлом я видел, как некоторые сторонние браузеры блокировали пользовательские схемы, содержащие дефисы и точки. Для WKWebView и базовой пользовательской схемы URL в ОС это, похоже, не проблема; no.half-bits
вместо nohalfbits
работает как положено при тестировании с использованием методов NSWorkspace и WKWebView.
Извините за публикацию этого ответа, но у меня недостаточно репутации Stackru, чтобы оставить комментарий
В ответ на этот комментарий: пользовательский URI перенаправления в приложение MacOS не работает
У меня была точно такая же проблема. Для меня, что исправило это, как бы глупо это не звучало, это очистить папку сборки. После этого мой код заработал сразу.
Ответ на этот комментарий: пользовательский URI перенаправления в приложение MacOS не работает
Вам вообще не нужна регистрация обработчика, если вы делаете это современным способом с помощью https://developer.apple.com/documentation/appkit/nsapplicationdelegate/2887193-application вместо старого способа (пример: https://github.com/gittower/custom-url-schemes).