概要
URL Schemeで他アプリと連携して、callbackで自分のアプリに戻ってくる処理を実装しています。
iOS12まではAppDelegate
の下記メソッドでリクエストを受け取っていましたが、iOS13で受け取れなくなっていました。
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool
「SceneDelegate
を代わりに使用する」ということはすぐわかったのですが、
まだSceneDelegateを導入していなかったこともあり少々手こずりました...
内容としてはあまり多くないですが備忘録としてまとめます。
環境
- iOS 13.2.3
- Xcode 11.2.1
- Swift5
実装
iOS12まで
これまでのURL Schemeのリクエスト受取はAppDelegateで以下のように実装していました。
アプリのURLを外部からアクセスされた時にapplication(_:open:options:)
が実行されます。
sourceapplicationでURLリクエストを送信したアプリのBundleIdを判定して、
どの画面の処理へ遷移させるか分岐させていました。
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
{
// 省略
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
guard let sourceApplication = options[.sourceApplication] as? String else {
return false
}
if sourceApplication.hasPrefix("--他アプリのBundleId--") {
// クエリパラメータを受けて色々処理
// ...
}
return true
}
}
iOS13から
1. SceneDelegateを呼べるように設定
SceneDelegateをそもそも用意していなかったので、自分はまずそこからやりました。
AppDelegate、Info.plistへの追記、SceneDelegateのベース作成は
下記の記事で分かりやすくまとめてありましたのでご参考ください!
2. SceneDelegateに追記
SceneDelegateのscene(_:openURLContexts:)が代わりに呼ばれるメソッドということで、ここに処理を書いていきます。
import UIKit
@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate
{
// ↓----以下追加----↓
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>)
{
// リクエストURLの取得
guard let url = URLContexts.first?.url else {
return
}
let sourceApplication = URLContexts.first?.options.sourceApplication
// あれ....?
}
}
あれ....。
AppDelegateと同じようにsourceApplication
を取得しようとしましたがなぜかnilで返ってくる...
うまくいかない。さてどうしたものか。
3. コールバックURLを識別できるものに変更
コールバックURLをユニークにすることで、レスポンスを受けた後にどの処理をするか判定できるだろう!
ということで例としてcall_test
というホスト名をつけてみました。
let callbackURL = URL(string: "myapp://call_test")!
4. SceneDelegateに改めて追記
call_test
というホストでリクエストが来ているか判定するために、
URLComponentsからホスト名を取得します。
@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate
{
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>)
{
// コールバックで来たURLの取得
guard let url = URLContexts.first?.url else {
return
}
// ↓----以下追加----↓
// ホスト名の取得
guard let components = URLComponents(string: url.absoluteString), let host = components.host else {
return
}
if host == "call_test" {
// クエリパラメータを受けて色々処理
// ...
}
}
}
これでURL Schemeの対応ができました!
参考
- canOpenURL fails on iOS 13 |Apple Developer Forums
- 【iOS13】xcode11上でswifterを用いた際のcallback URLのSceneDelegateへの記述 - Qiita
追記(2019.12.17)
あとでわかったこと。
AppDelegateのapplication(_:open:options:)はiOS13以降も動いておりました...
動かなくなっていたと思ったのはココ↓
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
{
// 省略
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
// ↓コレ
guard let sourceApplication = options[.sourceApplication] as? String else {
return false
}
if sourceApplication.hasPrefix("--他アプリのBundleId--") {
// クエリパラメータを受けて色々処理
// ...
}
return true
}
}
SceneDelegateでもそうでしたが、sourceApplication
が受け取れなくなっていただけのようです...
理由はまだ調査しきれておりませんが。
大変失礼しました...