OAuthSwift WKWebView 不断循环打开和关闭

OAuthSwift WKWebView opens and closes in a constant loop

我正在尝试使用 OAuth2 通过 Spotify API 对 iOS 应用程序进行身份验证。 为此,我使用 OAuthSwift.

当我的应用程序加载时,我被重定向到 Spotify,我可以登录并允许我的应用程序访问我的帐户。

然而,当我被重定向回我的应用程序时,WebView 被关闭,但立即在上一页重新打开,自行关闭并重新打开。

这将无限期地循环下去。

我想知道这是否与在 viewDidAppear 中调用我的 initAuthFlow 函数有关,但是将其移动到 viewDidLoad 会抱怨

Warning: Attempt to present <OAuthKeyChainApp.WKWebViewController: 0x7fb42b505160> on <OAuthKeyChainApp.HomeController: 0x7fb42b50cf30> whose view is not in the window hierarchy!

控制器从未出现。

HomeController.swift

class HomeController: OAuthViewController {

    let oauthSwift = OAuth2Swift(
        consumerKey: "xxxxxx",
        consumerSecret: "xxxxxx",
        authorizeUrl: "https://accounts.spotify.com/en/authorize",
        accessTokenUrl: "https://accounts.spotify.com/api/token",
        responseType: "code"
    )

    lazy var internalWebViewController: WKWebViewController = {
        let controller = WKWebViewController()
        controller.view = UIView(frame: UIScreen.main.bounds)
        controller.loadView()
        controller.viewDidLoad()
        return controller
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .purple
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        initAuthFlow()
    }

    fileprivate func initAuthFlow() -> Void {

        oauthSwift.authorizeURLHandler = internalWebViewController

        guard let callbackURL = URL(string: "oauthkeychainapp://oauthkeychain-callback") else { return }

        oauthSwift.authorize(
            withCallbackURL: callbackURL,
            scope: "user-library-modify",
            state: generateState(withLength: 20),
            success: { (credential, response, params) in
                print(credential)
            }) { (error) in
            print(error.localizedDescription)
        }
    }
}

extension HomeController: OAuthWebViewControllerDelegate {
    func oauthWebViewControllerDidPresent() { }
    func oauthWebViewControllerDidDismiss() { }
    func oauthWebViewControllerWillAppear() { }
    func oauthWebViewControllerDidAppear() { }
    func oauthWebViewControllerWillDisappear() { }
    func oauthWebViewControllerDidDisappear() { oauthSwift.cancel() }
}

WKWebViewController.swift

import UIKit
import WebKit
import OAuthSwift

class WKWebViewController: OAuthWebViewController {
    var webView: WKWebView!
    var targetURL: URL?

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func handle(_ url: URL) {
        targetURL = url
        super.handle(url)
        loadAddressURL()
    }

    func loadAddressURL() {
        guard let url = targetURL else { return }
        let req = URLRequest(url: url)

        self.webView?.load(req)
    }
}

extension WKWebViewController: WKUIDelegate, WKNavigationDelegate {
    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.allowsBackForwardNavigationGestures = true
        webView.uiDelegate = self
        webView.navigationDelegate = self
        view = webView
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("loaded")
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        // Check for OAuth Callback
        if let url = navigationAction.request.url, url.scheme == "oauthkeychainapp" {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
            self.dismiss(animated: true, completion: nil)
            decisionHandler(.cancel)
            return
        }

        // Restrict URL's a user can access
        if let host = navigationAction.request.url?.host {
            if host.contains("spotify") {
                decisionHandler(.allow)
                return
            } else {
                // open link outside of our app
                UIApplication.shared.open(navigationAction.request.url!)
                decisionHandler(.cancel)
                return
            }
        }

        decisionHandler(.cancel)

    }
}

您没有做任何更改应用程序状态的事情。因为这个 initAuthFlow 被再次调用,我假设 Spotify 对你有一个有效的会话,所以控制器被关闭并且循环重复。

在您的 oauthSwift.authorize 调用成功结束时,您应该将令牌放入钥匙串或安全的地方,并确保仅在该状态无效时才调用 initAuthFlow