Android中常见的Hybrid实现方法

在APP开发过程中,不可避免会遇到html与native进行交互的情况。比如,在微信公众号里看到一篇运营文章,或者在朋友圈点开某条分享的链接,在打开的页面上,文末一般都会有一些引导性的操作。点击这些按钮,往往都会将对应的APP打开并直接进入相关页面。这个体验很令人惊喜,是吗?

再或者,在APP里,点击运营活动的内容或者一些广告,在打开的页面上也有类似的引导操作。这时,点击这些操作,也会像一般的页面跳转一样跳到目标页面。丝毫没有感觉到是Web页面与Native页面的交互。对吧?

上面说的两个现象,其实都是Web页面与APP Native的交互,具体又分为:

1.APP之外的浏览器页面与APP的交互

2.APP内部Web页面与Native页面的交互

如图所示:

如何实现?

首先需要制定一个hybrid协议。再具体点,就是要制定一个Uri的拼接规则。

Web页面的跳转是以打开新的url的方式进行的。

Uri的样式为:scheme://host/path?query=jsonParams, 或者称为:[scheme][authority][path][query=jsonParams], 

以我们帮帮项目为例,uri的样式为:

/**
     * 请求协议结构
     * sherlock-bb://cn.bangbang?json-data
     * sherlock-bb(scheme)
     * cn.bangbang(host或者authority)
     * json-data(query)
     */
可以看出我们的协议里是没有定义path值的。

第二、为支持外部浏览器的调用,需要在Manifest里设置IntentFilter。通常我们会选择主页面的Activity作为被调用的Activity。

其中增加一个Data类型的IntentFilter,对数据进行下限制:

        <activity
            android:name=".MainActivity"
            android:configChanges="orientation|keyboard|keyboardHidden|fontScale|touchscreen|mcc|mnc|locale"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:screenOrientation="portrait">
            <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:host="cn.bangbang"
                    android:scheme="sherlock-bb" />
            </intent-filter>
        </activity>

2.1 首先要注意的是,需要将该Activity的启动模式设置为singleTask,原因很明显,在APP已经在后台运行的情况下,主页面不需要被android系统再次创建。

2.2其次,微信浏览器会截断query部分的数据,导致跳转异常。这里通常有两种解决办法:

2.2.1 在微信打开的该Html页面引导用户选择title右上角菜单里的“在浏览器打开”,使用其他浏览器再次打开该html页面,然后在点击引导性的操作。

2.2.2 可以通过业务合作的方式,让微信将html使用的域名加入到微信的白名单中,这样微信就不会对页面里的url做处理了。

3.对于APP内部,WebView与Native的交互,截获url的地方有两处,这里直接贴代码:

    class MyWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            Uri uri = Uri.parse(url);
            String scheme = uri.getScheme();
            if (!("http".equals(scheme) || "https".equals(scheme))) {
                String auth = uri.getAuthority();
                if (MyHtmlLink.HOST.equalsIgnoreCase(auth)) {
                    String jsonData = MyWebViewUtils.handleUrl(url);
                    if (!StringUtil.isEmpty(jsonData)) {
                        procHtmlLinkData(jsonData);
                    }
                    return true;
                }
            }
            return super.shouldOverrideUrlLoading(view, url);
        }

        @Override
        public void onLoadResource(WebView view, String url) {
            Uri uri = Uri.parse(url);
            String scheme = uri.getScheme();
            if (MyHtmlLink.SCHEME.equalsIgnoreCase(scheme)) {
                view.clearHistory();
                String jsonData = MyWebViewUtils.handleUrl(url);
                if (!StringUtil.isEmpty(jsonData)) {
                    procHtmlLinkData(jsonData);
                }
            } else {
                super.onLoadResource(view, url);
            }
        }

        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            if (handler != null) {
                handler.proceed();
            }
        }
    }

3.1 WebView的load方法是个多态方法,不仅可以load一个标准的http打头的url,而且可以传入http的header,如:

public void loadUrl(String url, Map<String, String> additionalHttpHeaders)

而且可以调用js的方法,通知到html页面。如:

mWebView.loadUrl("javascript:cn.wb.appbridge.outer.transFormatedMsg('" + fe_defined_paramSting + "')");
mWebView.loadUrl("javascript:" + fe_defined_method + "('" + paramSting + "')");
其中的fe_defined_paramSting、fe_defined_method、paramSting都是根据业务需要,由开发该html页面的FE同学指定的,APP的同学配合就好。

4.题外话,有个UriMatcher类在处理url类型的switch case时相当好用。用法也很简单:

先创建一个对象:

UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
然后将需要case的类型注册一下,这里是可以进行模糊匹配的

public void addURI(String authority, String path, int code)
最后,在需要switch case时,调用match方法,则会返回addURI中注册的match值:code,如果没有匹配到,则返回-1.
public int match(Uri uri)


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值