53

次のコードを追加します。

- (IBAction)done {
    // Return any edited content to the host app.
    // This template doesn't do anything, so we just echo the passed in items.

    NSURL *url = [NSURL URLWithString:@"lister://today"];
    [self.extensionContext openURL:url completionHandler:^(BOOL success) {
        NSLog(@"fun=%s after completion. success=%d", __func__, success);
    }];
    [self.extensionContext completeRequestReturningItems:self.extensionContext.inputItems completionHandler:nil];

}

アクション拡張ターゲットを作成した後。しかし、それはうまくいきません。

私の目的は、ユーザーが Photos.app (iOS のデフォルトの Photos.app またはギャラリーと呼ばれる) で写真を表示し、共有ボタンをクリックして拡張ビューを起動するときです。Photos.app から自分のアプリに画像を転送し、自分のアプリで画像を処理またはアップロードできます。

「CFBundleDocumentTypes」も試してみましたが、うまくいきません。

どんな助けでも大歓迎です。

4

17 に答える 17

25

このコードを試してください。

    UIResponder* responder = self;
    while ((responder = [responder nextResponder]) != nil)
    {
        NSLog(@"responder = %@", responder);
        if([responder respondsToSelector:@selector(openURL:)] == YES)
        {
            [responder performSelector:@selector(openURL:) withObject:[NSURL URLWithString:urlString]];
        }
    }
于 2015-04-10T06:16:11.490 に答える
20

これは仕様によるものです。カスタム アクションがアプリ ランチャーになることは望ましくありません。

于 2014-07-12T05:12:11.023 に答える
15

Swift 3.0 & 4.0 で動作するソリューション:

// For skip compile error. 
func openURL(_ url: URL) {
    return
}

func openContainerApp() {
    var responder: UIResponder? = self as UIResponder
    let selector = #selector(openURL(_:))
    while responder != nil {
        if responder!.responds(to: selector) && responder != self {
            responder!.perform(selector, with: URL(string: "containerapp://")!)
            return
        }
        responder = responder?.next
    }
}

説明:

拡張機能では、API はコンパイラによって制限され、コンテナー アプリのように openURl(:URL) を使用できません。ただし、API はまだここにあります。

そして、宣言するまでクラスでメソッドを実行することはできません。本当に必要なのは、UIApplication にこのメソッドを実行させることです。

レスポンダー チェーンへのリコール、使用できます

    var responder: UIResponder? = self as UIResponder
    responder = responder?.next

UIApplication オブジェクトにループします。

また、この方法を使用した私のアプリは審査プロセスに合格しているので、心配せずに使用してください。

于 2016-11-18T10:55:40.880 に答える
9

キーボード拡張機能の実用的なソリューション (iOS 9.2 でテスト済み) 。このカテゴリは、隠しsharedApplicationオブジェクトにアクセスするための特別なメソッドを追加し、それを呼び出しますopenURL:。(もちろんopenURL:、アプリ スキームでメソッドを使用する必要があります。)

extension UIInputViewController {

    func openURL(url: NSURL) -> Bool {
        do {
            let application = try self.sharedApplication()
            return application.performSelector("openURL:", withObject: url) != nil
        }
        catch {
            return false
        }
    }

    func sharedApplication() throws -> UIApplication {
        var responder: UIResponder? = self
        while responder != nil {
            if let application = responder as? UIApplication {
                return application
            }

            responder = responder?.nextResponder()
        }

        throw NSError(domain: "UIInputViewController+sharedApplication.swift", code: 1, userInfo: nil)
    }

}
于 2015-12-23T00:34:43.410 に答える
7

ドキュメントが言うので、それはバグのようです:

含まれているアプリを開く

場合によっては、拡張機能が含まれているアプリを開くように要求することが理にかなっている場合があります。たとえば、OS X のカレンダー ウィジェットは、ユーザーがイベントをクリックするとカレンダーを開きます。含まれているアプリがユーザーの現在のタスクのコンテキストで意味のある方法で開くようにするには、アプリとその拡張機能の両方で使用できるカスタム URL スキームを定義する必要があります。

拡張機能は、含まれているアプリを開くように直接指示しません。代わりに、NSExtensionContext の openURL:completionHandler: メソッドを使用して、含まれているアプリを開くようにシステムに指示します。拡張機能がこのメソッドを使用して URL を開くと、システムは要求を満たす前に検証します。

今日報告しました: http://openradar.appspot.com/17376354暇があれば、だまされるべきです。

于 2014-06-19T11:36:28.167 に答える
6

最新の Swift 構文を使用した Julio Bailon の回答の更新版:

let url = NSURL(string: "scheme://")!
var responder: UIResponder? = self
while let r = responder {
    if r.respondsToSelector("openURL:") {
        r.performSelector("openURL:", withObject: url)
        break
    }
    responder = r.nextResponder()
}

現在、NSObject の拡張機能は必要ありません。

注: このコードを呼び出す前に、ビューがビュー階層にアタッチされるまで待機する必要があります。そうしないと、レスポンダー チェーンを使用できません。

于 2015-10-27T11:03:38.167 に答える
6

考えられる回避策: 小さな UIWebView を作成してビューに追加し、上で設定した URL スキームを使用してそのメソッド loadRequest を実行します。これは回避策であり、Apple がこれについて何と言うかはわかりません。幸運を!

于 2014-07-07T15:45:45.130 に答える
2

再帰を使用した少し安全なオプション

func handleUrl(_ hostUrl: URL?) {
        fileUrl.map { URL(string: yourUrlSchemeId + "://" + $0.absoluteString) }.map { finalUrl in
            let selector = #selector(openURL(_:))
            func proccessNext(_ responder: UIResponder?) {
                responder.map {
                    if $0.responds(to: selector) {
                        $0.perform(selector, with: finalUrl)
                    } else {
                        proccessNext($0.next)
                    }
                }
            }
            proccessNext(self.next)
        }
    }
    @objc func openURL(_ url: URL) {
        return
    }


于 2020-08-17T08:51:09.683 に答える