WebView 放弃 rel= 到活动管理器的外部链接

发布于 2024-12-25 17:24:13 字数 1104 浏览 3 评论 0原文

我有一个 WebView,其中我希望带有 rel=external 的锚标记在 Android 浏览器中打开,但所有其他链接都保留在 WebView 中。

因此,如果用户点击标记如下所示的链接,内容将在 WebView 中加载:

<a href="http://example.com/">Whatever</a>

但如果用户点击标记如下所示的链接,内容将在 Android 浏览器中加载:

<a href="http://example.com/" rel="external">Whatever</a>

这是我的WebViewClient 代码中的相关代码(用注释标识的一位伪代码):

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (! rel=external) {   //  <-- That condition...how do I do that?
        view.loadUrl(url);
        return false;
    } else {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(url));
        startActivity(intent);
        return true;
    }

确定是否存在 rel=external 属性/值的最佳方法是以某种方式使用addJavascriptInterface() 并让 JavaScript 通知 Java 是否存在 rel 属性以及该属性的值是什么?

或者有更好的方法吗?

(我正在寻找一种不涉及检查 URL 域的解决方案,因为有任意数量的域需要被视为内部域,并且我无法提前知道或轻松即时确定。)

I have a WebView wherein I would like anchor tags with rel=external to open in the Android browser but all other links to stay in the WebView.

So the content will load within the WebView if the user taps a link whose markup looks like this:

<a href="http://example.com/">Whatever</a>

But the content will load in the Android browser if the user taps a link whose markup looks like this:

<a href="http://example.com/" rel="external">Whatever</a>

Here's my relevant code (with one bit of pseudocode identified with a comment) in the WebViewClient code:

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (! rel=external) {   //  <-- That condition...how do I do that?
        view.loadUrl(url);
        return false;
    } else {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(url));
        startActivity(intent);
        return true;
    }

Would the best way to determine whether there is a rel=external attribute/value be to somehow use addJavascriptInterface() and have JavaScript inform Java whether or not there is a rel attribute and what the value is?

Or is there a better way?

(I am looking for a solution that does not involve checking the domain of the URL because there are an arbitrary number of domains that need to be treated as internal and that I cannot know in advance or determine easily on-the-fly.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

雨后咖啡店 2025-01-01 17:24:13

我认为如果您不想修改现有的 URL,那么您最初建议的变体可能是最好的。

使用 addJavaScriptInterface 添加一个类来处理外部 URL 加载。内部类可能如下所示:

public class JavaScriptInterface {
    public void viewExternalUrl(String url) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(url));
        startActivity(intent);
        return true;
    }
}

当然添加它:

webView.addJavascriptInterface(new JavaScriptInterface(), "Android");

注入 JavaScript 以添加点击处理程序,以在页面加载后通过 loadUrl 调用 JavaScript 接口(为简单起见,使用 JQuery)。您可以通过创建自定义 WebViewClient 来检测页面加载完成情况 并覆盖 onPageFinished

webView.setWebViewClient(new WebViewClient() {
    private static final String sJs = "javascript:" +
        Uri.encode("$('a[@rel$='external']').click(function(){ Android.viewExternalUrl($(this).attr('href')); });");

    @Override
    public void onPageFinished(WebView view, String url) {
        webView.loadUrl(sJs);
    }
}

我还没有测试过任何这段代码,但它应该可以工作,假设您在页面中加载了 JQuery。如果没有,您可能可以想出一些 JavaScript 来在没有它的情况下操作 DOM,或者您可以使用 loadUrl 在加载 JavaScript 之前先手动加载 JQuery。

请注意,此方法完全放弃了 shouldOverrideUrlLoading 的任何使用

I think a variation of your original suggestion is probably best if you don't want to modify the existing URL.

Use addJavaScriptInterface to add a class to handle your external URL loading. An inner class might look like this:

public class JavaScriptInterface {
    public void viewExternalUrl(String url) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(url));
        startActivity(intent);
        return true;
    }
}

And of course adding it:

webView.addJavascriptInterface(new JavaScriptInterface(), "Android");

Inject JavaScript to add click handlers to call your JavaScript interface after the page is loaded (using JQuery for simplicity's sake) through loadUrl. You can detect the page load finishing by creating a custom WebViewClient and overriding onPageFinished.

webView.setWebViewClient(new WebViewClient() {
    private static final String sJs = "javascript:" +
        Uri.encode("$('a[@rel$='external']').click(function(){ Android.viewExternalUrl($(this).attr('href')); });");

    @Override
    public void onPageFinished(WebView view, String url) {
        webView.loadUrl(sJs);
    }
}

I haven't tested any of this code, but it should work, assuming you have JQuery loaded in the page. If not, you can probably come up with some JavaScript to manipulate the DOM without it or you can use loadUrl to manually load JQuery first before the loading the JavaScript.

Note that this approach completely abandons any use of shouldOverrideUrlLoading

可是我不能没有你 2025-01-01 17:24:13

我的建议是使用一种不同的方式来指定外部 URL...将该信息嵌入到 URL 中,因此与 shouldOverrideUrlLoading 函数兼容。具体来说,创建自定义方案 URL 并将真实页面作为参数传递:

myappname://external?url=encoded_real_page_url

然后在 shouldOverrideUrlLoading 函数中检查它是否是自定义方案 URL,提取 url 参数,解码然后重定向。

My suggestion is to use a different way of designating external URLs... one that embeds that info in the URL and hence is compatible with the shouldOverrideUrlLoading function. Specifically, create custom scheme URLs and pass the real page as a parameter:

myappname://external?url=encoded_real_page_url

Then in the shouldOverrideUrlLoading function check if it's a custom scheme URL, extract the url param, decode it and then redirect.

终弃我 2025-01-01 17:24:13

如果您可以控制服务器端内容,那么一定要遵循 Theo 提出的建议。由于您指示页面也应该在标准浏览器中加载,因此不要使用自定义方案,而应将 rel=external 作为您要链接/重定向到的实际网址的一部分。

通过这样做,您可以轻松解析 shouldOverrideUrlLoading(WebView view, String url) 中的 url 参数并检查上述键/值对。我建议您将其解析为 Uri 并使用 getQueryParameter(key ) 检查匹配 rel 的值。如果是外部,则触发一个 Intent。

它看起来像这样:

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    Uri uri = Uri.parse(url);
    String relValue = uri.getQueryParameter("rel");    
    if (relValue != null && !relValue.equals("external")) {
        view.loadUrl(url);
        return false;
    }
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(uri);
    startActivity(intent);
    return true;
}

旁注:不需要声明“else”,因为您已经从“if”中的方法返回。

如果用户可以使用您的 WebView 访问任何网站,并且您对其他网站出于其目的应用相同的键/值对感到偏执,那么您可以轻松添加另一个检查来确定该 url 是否位于“您的”域中。

If you have control over the server side content, then definitely go with the suggestion Theo made. Since you indicate the pages should also load in standard browers, don't use a custom scheme, but make rel=external part of the actual url you're linking/redirecting to.

By doing that, you can easily parse the url parameter in shouldOverrideUrlLoading(WebView view, String url) and check for above key/value pair. I would suggest you parse it into a Uri and use getQueryParameter(key) to check for the value matching rel. If it's external, fire off an Intent.

It would look something like this:

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    Uri uri = Uri.parse(url);
    String relValue = uri.getQueryParameter("rel");    
    if (relValue != null && !relValue.equals("external")) {
        view.loadUrl(url);
        return false;
    }
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(uri);
    startActivity(intent);
    return true;
}

On a side note: no need to declare an 'else' since you already return from the method in the 'if'.

If users can go to any site using your WebView and if you're paranoid about other sites applying the same key/value pair for their purposes, you could easily add another check to determine whether the url is on 'your' domain.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文