web-dev-qa-db-ja.com

SafariのUIWebViewの外部でtarget = "_blank"リンクを開きます

私のiOSアプリケーション内には、UIWebViewがあります。

ここで、属性target = "_ blank"を持つすべてのリンクを、WebViewの内部ではなく、Safariの外部で開くようにします。

これどうやってするの?

20
Norwald2

Wedoのソリューションの問題は、すべてのリンクがSafariで開くことです。

2つの解決策:

1-target = "_ blank"の場合のObjective-CへのJavaScriptコールバック
問題を解決するには、すべてのリンクにJavaScriptを追加する必要があります。リンクに_blank属性があるかどうかを確認し、JavaScriptから目的のCコードを呼び出して実行します。

[[UIApplication sharedApplication] openURL:myUrl];

個人的には、このソリューションは多くのコード、コールバック、複雑さ、そして少し難しいので、好きではありません...

2-URLパラメータを確認しています
HTMLコードにアクセスできる場合(両方のソリューションでHTMLにアクセスする必要があることに注意してください)、target = "_ blank"を削除し、パラメーター?openInSafari = trueを追加することをお勧めします。

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

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if (navigationType == UIWebViewNavigationTypeLinkClicked) {
        NSURL *url = [request URL];
        NSDictionary *param = [url queryParameters];
        NSString *openIsSafari = [param objectForKey:@"openInSafari"];

        if ( openIsSafari!= nil && ([openIsSafari isEqualToString:@"true"] ||  [openIsSafari isEqualToString:@"1"])){
            [[UIApplication sharedApplication] openURL:url];
            return NO;
        }
    }
    return YES;
}

このソリューションの良い(悪い?)ポイントは、リンクxレベルが深い場合でも、サファリブラウザへのリンクを開くことができるということです

<a href="http://www.google.com?openInSafari=true">Google in Safari</a>


常にURL(http、https ...)にプロトコルを追加してください

4
Martin Magakian

マーティンマガキアンへの称賛!以下は、spankmaster79の提案に基づく変更です。

- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest: (NSURLRequest *)request navigationType: (UIWebViewNavigationType)navigationType {
    if (navigationType == UIWebViewNavigationTypeLinkClicked) {
        NSURL *url = [request URL];
        NSString *param = [url query];

        if ([param rangeOfString: @"openInSafari=true"].location != NSNotFound){
            [[UIApplication sharedApplication] openURL: url];
            return NO;
        }
    }
    return YES;
}
3
mpemburn

これを試して。

UIApplication *app = [UIApplication sharedApplication];
NSURL         *url = navigationAction.request.URL;

if (!navigationAction.targetFrame) {
    if ([app canOpenURL:url]) {
        [app openURL:url];
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
}
if ([url.scheme isEqualToString:@"mailto"])
{
    if ([app canOpenURL:url])
    {
        [app openURL:url];
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
}

decisionHandler(WKNavigationActionPolicyAllow);
1
Sujith Sreedhar

私は同じ質問をしましたが、残念ながらこれらの答えは私を完全に間違った非常に複雑な方法で引き起こしました。実際、この質問に対する答えは「WebViewPolicyDelegateProtocolを使用する必要がある」という単純なものです。

ビューコントローラ実装の-viewDidLoadで、次のように記述します。

[myWebView setPolicyDelegate:self];

ビューコントローラクラスインターフェイスで、次の2つの項目を追加する必要があります。

- (void)webView:(WebView *)webView 
decidePolicyForNavigationAction:(NSDictionary *)actionInformation 
        request:(NSURLRequest *)request 
          frame:(WebFrame *)frame 
decisionListener:(id<WebPolicyDecisionListener>)listener;
- (void)webView:(WebView *)webView 
decidePolicyForNewWindowAction:(NSDictionary *)actionInformation 
        request:(NSURLRequest *)request 
   newFrameName:(NSString *)frameName 
decisionListener:(id<WebPolicyDecisionListener>)listener;

そして、それらを次のように簡単に実装します。

- (void)webView:(WebView *)webView 
decidePolicyForNavigationAction:(NSDictionary *)actionInformation 
        request:(NSURLRequest *)request 
          frame:(WebFrame *)frame 
decisionListener:(id<WebPolicyDecisionListener>)listener {
    // just the default behavior, though you're free to add any url filtering you like...
    [listener use];
}
- (void)webView:(WebView *)webView 
decidePolicyForNewWindowAction:(NSDictionary *)actionInformation 
        request:(NSURLRequest *)request 
   newFrameName:(NSString *)frameName 
decisionListener:(id<WebPolicyDecisionListener>)listener {
    // frameName is your "target" parameter value
    if([frameName isEqualToString:@"_blank"]) {
      [[NSWorkSpace sharedWorkSpace] loadURL:[request URL]];
    } else {
        [listener use];
    }
}

Apple docs も参照してください。

私はプロジェクトでこの方法を使用しました。フレームセットはルートHTMLで使用され、WebViewにロードされます。別の既存のフレームを指すすべてのクロスリンクは2番目のメッセージ呼び出しを引き起こさないため、ここでは新しい(外部)ターゲットのみが処理されます。私にとっては問題ありません。

0
DeadlineX