yashiganiの英傑になるまで死ねない日記

週末はマスターバイクでハイラルを走り回ります

Share ExtensionでOpen URLするとかなんとか

注意: beta 5時点での情報です

iOS8で追加される待望のApp Extensionですが,あくまでExtensionなのでContaining appを呼び出したくなることがあると思います. App Extension Programming Guideにもあるように,App ExtensionとContaining appとの連携にはShared resourcesのほかにOpen URLを利用します. Open URLというと従来より形式化された手法ですので,とくにはまりどころは無いと思っていたのですが,はまりどころがあったので紹介させていただきます.

App ExtensionにはUIApplicationが無い

Open URLといえばご存知のようにUIApplicationを取得すればお気楽に実装できるのですが,App ExtensionにはUIApplicationopenURL:メソッドが存在しません.

// UIApplication.h より抜粋
- (BOOL)openURL:(NSURL*)url NS_EXTENSION_UNAVAILABLE_IOS("");

見事に隠されてますね. したがって,Open URLを実装したければ,別の方法を取る必要があります.

App ExtensionではNSExtensionContextを使う

ここで登場するのがNSExtensionContextopenURL:completionHander:です. Share Extensionの場合,エンドポイントとなるSLComposeServiceViewControllerNSExtensionContextを持っていますので,以下のように実装することが考えられます.

// `NSExtensionContext`を使ってopenURLする
NSURL *URL = [NSURL URLWithString:@"myapp://login"];
[self.extensionContext openURL:URL
             completionHandler:^(BOOL success) {
                 // successが`YES`なら成功
             }];

これで安心と思いきや,そうは問屋がおろしません. なんだそれは!と思われるかもしれませんが,openURL:completionHandler:はToday Extension以外で動作しません. 動作を確認してみたとき,successNOが得られて,てっきりContaining appを呼び出すCustom URL Schemeを間違っているのかと思いましたが,どうやらそうではないようです.

それでも絶対Open URLしたい!

我々にはUIWebViewがあります. Zero RectのUIWebViewを作成し,開きたいURLをloadRequest:すると当然のように動作します. もちろんロードが完了するまでUIWebViewを保持する必要がありますのでSLComposeServiceViewControllerに貼り付けておきましょう. 余談ですが,SLComposeServiceViewControllerは特別な存在なのかなあと思ったら,わりと普通にUIViewControllerのサブクラスです.

// Share Extensionでの真のOpen URL
UIWebView *webView = UIWebView.new;
[self.view addSubview:webView]; // ロード完了まで保持しておきたいので適当に貼り付けておく
NSURL *URL = [NSURL URLWithString:@"myapp://login"];
[webView loadRequest:[NSURLRequest requestWithURL:URL]];

まとめ

UIWebViewこそ人類に残された最後の希望.

関連