LoginSignup
7
4

SwiftUIでASWebAuthenticationSession

Last updated at Posted at 2019-09-01

2023/11/28 追記

  • しばらく気がつきませんでしたが、SwiftUIでASWebAuthenticationSessionを利用するAPIが追加されていました
  • 利用可能なOSは限られていますが、可能であればこちらのAPIを使う方が良いでしょう

webAuthenticationSession

利用方法

  • SwiftUI用にチューニングされていて、Concurrency対応していたり既存の方法よりかなり使い勝手が良くなっています
  • 以下はApple公式の例をちょっと変えたものです
struct WebAuthenticationSessionExample: View {
    @Environment(\.webAuthenticationSession) private var webAuthenticationSession

    var body: some View {
        Button("Sign In") {
            Task {
                do {
                    // authenticateメソッドの戻り値でコールバックURLをもらえる
                    let urlWithToken = try await webAuthenticationSession.authenticate(
                        using: URL(string: "https://www.example.com")!,
                        callbackURLScheme: "x-example-app"
                    )
                    // URLComponentsで必要なパラメータを取り出す
                    let queryItems = URLComponents(string: urlWithToken.absoluteString)?.queryItems
                    // OAuth2だったらここからトークン交換をしたりする
                } catch {
                    print(error)
                }
            }
        }
    }
}

ここから追記前記事

導入

新卒でSwiftはじめて3ヶ月が経ちました。あっという間です…
今回はSwiftUIでTwitter連携させたかったとき悩んだところが解消できたのでせっかくなので記事にしたいと思います。エンジニアっぽくなってきて楽しいです:relaxed:

したかったこと

  • SwiftUIのViewで作ったボタンをポチったらASWebAuthenticationSessionでTwitterとか連携するあの画面が出てきてサインインしたら閉じるやつが作りたい(語彙力)

できたやつ

AuthPresentationContextProver クラスはこちらの記事から拝借しました。ありがとうございます:clap:

import SwiftUI
import AuthenticationServices

class AuthPresentationContextProver: NSObject, ASWebAuthenticationPresentationContextProviding {
    private weak var viewController: UIViewController!

    init(viewController: UIViewController) {
        self.viewController = viewController
        super.init()
    }

    func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
        return viewController?.view.window! ?? ASPresentationAnchor()
    }
}

struct RenkeiButton: View {
    @State var session: ASWebAuthenticationSession?
    @State var presentationContextProvider: AuthPresentationContextProver?
    // リクエストトークンもらうマン
    func postOAuthRequestToken(success: 成功した時のHandler, failure: 失敗した時)
    // リクエストトークンから連携画面表示するマン
    func authStart(requestToken: とーくん) {
        let queryUrl = tokenで作る
        let callbackURLScheme = "ちょめちょめ"

        self.session = ASWebAuthenticationSession(url: queryUrl, callbackURLScheme: callbackURLScheme, completionHandler: { (url, error) in
            // callbackURLScheme + parameters のURLが帰ってくるのでちょめちょめする
            // キャンセルの時はエラーになる
        })
        let presentationContextProvider = AuthPresentationContextProver(viewController: UIHostingController(rootView: self))
        self.session?.presentationContextProvider = presentationContextProvider
        self.presentationContextProvider = presentationContextProvider
        self.session?.start()
    }

    var body: some View {
        Button(action: {
            self.postOAuthRequestToken(
                success: { (requestToken, response) in
                    self.authStart(token: requestToken)
                }, failure: { (error) in
                })
        }, label: {
            Text("連携や!!")
        })
    }
}

悩んでたとこ

iOS13ではpresentationContextProviderASWebAuthenticationPresentationContextProvidingとかいうProtocolを満たすNSObjectを設定をしていないと連携画面のモーダルが出ません…
Controllerベースで作れば簡単にできるけど…ってなってた時に@simorgh3196さんの記事を発見して、もしやUIHostingControllerで渡してやれば同じようにできる…?となってうまくいった次第です

UIHostingControllerで渡してやらなくても…

要は現在のwindowが知りたいので@shizさんのこちらの記事を参考に…

class AuthPresentationContextProver: NSObject, ASWebAuthenticationPresentationContextProviding {
    @Environment(\.window) var window

    func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
        return window ?? ASPresentationAnchor()
    }
}

とすることもできます。(この書き方いいんでしょうか…)

おわりに

SwiftUI、iOS13 まだまだBeta段階ですのでこの書き方もいずれ使えなくなるかもなので注意です!

SwiftUIたのしい!

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4