美文网首页
Web唤起App的实现及原理

Web唤起App的实现及原理

作者: 蜗牛是不是牛 | 来源:发表于2022-11-15 16:31 被阅读0次

    在工作中经常能遇到Web跳转到App容器内,其运用在大量的业务场景下,简单记录下其实现方式及实现背景。

    一、使用

    先不管唤起的原理,用一个简单的例子来描述它的使用:

    • 首先需要在 AndroidManifest.xml 中定义 scheme,scheme 不能和 http、https、ftp、sms、mailto 等已使用的相同。
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
        <!-- web 唤起添加的 filter -->
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data
                android:scheme="my.scheme"
                android:host="my.host"
                />
        </intent-filter>
    </activity></pre>
    

    下面是测试网页:

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Web 唤起 app</title>
    </head>
    <body style="text-align: center">
    <a href="my.scheme://my.host?name=xxx&title=xxx" style="font-: 27px">点击唤起 Demo app</a>
    </body>
    </html></pre>
    

    上面的链接中有 name 和 title 两个参数,app 也能接收到,所以在唤起 app 时也能传一些数据

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = getIntent();
        if (null != intent && null != intent.getData()) {
            Uri uri = intent.getData(); // uri 就相当于 web 页面中的链接
            String name = uri.getQueryParameter("name");
            String title = uri.getQueryParameter("title");
        }
    }</pre>
    

    二、实现

    scheme也不过是一个链接,它唤起App的方式其实是通过WebView的WebViewClient的shouldOverrideUrlLoading方法,基本上所有的浏览器都会有类似的实现,下面将以Android 6.0原生浏览器的 shouldOverrideUrlLoading 方法的核心实现为例。

    Android 6.0的原生浏览器的shouldOverrideUrlLoading方法的核心实现在UrlHandler类中。

    boolean shouldOverrideUrlLoading(Tab tab, WebView view, String url) {
        ...
        // The "about:" schemes are internal to the browser; don't want these to
        // be dispatched to other apps.
        if (url.startsWith("about:")) {
            return false;
        }
        ...
        if (startActivityForUrl(tab, url)) {
            return true;
        }
        if (handleMenuClick(tab, url)) {
            return true;
        }
        return false;
    }</pre>
    

    从上面第五行代码可以看到Scheme也不能为about,这是原生浏览器内部使用的,唤起App的关键在第十行的startActivityForUrl方法。

    boolean startActivityForUrl(Tab tab, String url) {
        Intent intent;
        // perform generic parsing of the URI to turn it into an Intent.
        try {
            intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
        } catch (URISyntaxException ex) {
            Log.w("Browser", "Bad URI " + url + ": " + ex.getMessage());
            return false;
        }
        // check whether the intent can be resolved. If not, we will see
        // whether we can download it from the Market.
        ResolveInfo r = null;
        try {
            r = mActivity.getPackageManager().resolveActivity(intent, 0);
        } catch (Exception e) {
            return false;
        }
        ...
        // sanitize the Intent, ensuring web pages can not bypass browser
        // security (only access to BROWSABLE activities).
        intent.addCategory(Intent.CATEGORY_BROWSABLE);
        intent.setComponent(null);
        Intent selector = intent.getSelector();
        if (selector != null) {
        selector.addCategory(Intent.CATEGORY_BROWSABLE);
        selector.setComponent(null);
        }
        ...
        try {
            intent.putExtra(BrowserActivity.EXTRA_DISABLE_URL_OVERRIDE, true);
        if (mActivity.startActivityIfNeeded(intent, -1)) { // 唤起 app 的最终代码在这里
            // before leaving BrowserActivity, close the empty child tab.
            // If a new tab is created through JavaScript open to load this
            // url, we would like to close it as we will load this url in a
            // different Activity.
            mController.closeEmptyTab();
                return true;
            }
        } catch (ActivityNotFoundException ex) {
            // ignore the error. If no application can handle the URL,
            // eg about:blank, assume the browser can handle it.
        }
        return false;
    }</pre>
    

    上面的22行intent.addCategory(Intent.CATEGORY_BROWSABLE);

    第三方的浏览器在这个地方对Scheme屏蔽,就可以打断唤起流程,微信中网也不能唤起App就是该原因。

    来自:https://www.yuque.com/pride-c5kdp/ug8e2h/qb6c6p

    相关文章

      网友评论

          本文标题:Web唤起App的实现及原理

          本文链接:https://www.haomeiwen.com/subject/nnqexdtx.html