android hybird 实现:自定义schema

android hybird 与h5 app区别

hybird 与h5 app是不同的,之前对这二者理解有所误解,在实际开发中也并未真正采用hybird,而是使用h5+app外壳实现移动端应用。虽然开发出来的应用实现了无需升级app实现主功能更新,可是交互体验上较原生相差甚多。
Hybrid App(混合模式移动应用)是指介于web-app、native-app这二者之间的app,兼具“Native App良好用户交互体验的优点”和“Web App跨平台开发的优点”(摘自百度百科)
通常hybird app会将须要动态更新页面及功能内置到app中,也就是将web页面预置到本地,android端经过加载本地html页面实现快速加载,因为不须要通过网络,速度上会有极大的提高。而须要升级是,则需在服务器上创建对应的资源包,并将服务器资源包与本地html版本作对比,若不一致则从服务器加载资源压缩包,并下载到本地,从而实现不须要从新安装app快速升级迭代的目的。此功能适用于须要频繁更新,又对性能要求较高的场景,例如新闻头条页等。若用h5实现,则体验上会相差很多。javascript

android 与js混合调用方式

1.一般android与js混合调用的方式是android端定义webView,并设置以下代码html

WebSettings settings = mWebView.getSettings();

    settings.setJavaScriptEnabled(true);
    //设置本应用加载网页
   mWebView.setWebViewClient(new WebViewClient(){
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url)     {
                view.loadUrl(url)
                return true;
            }
        });
       mWebView.loadUrl("***.html");

此处传入url并开启访问网络权限便可实现打开页面.AndroidManifest.xmljava

<uses-permission android:name="android.permission.INTERNET"></uses-permission>

下面正式开始JS调用android方式
须要创建一个桥,以下android

import android.content.Context;
import android.webkit.JavascriptInterface;
import android.widget.Toast;

public class JsInterface {
    private Context mContext;
    public JsInterface(Context context){
        mContext = context;
    }
    //必须加注解,为了安全性考虑,4.2后强制
    @JavascriptInterface
    public void showToast(String params){
        Toast.makeText(mContext,"Hello"+params,Toast.LENGTH_LONG).show();
    }

}


//MainActivity中
        JsInterface jsInterface = new JsInterface(MainActivity.this);
        myWebView.addJavascriptInterface(jsInterface,"bridge");
 //js中,使用以下代码
    document.getElementById('#btn').addEventListener("click",function(){
        if(window.bridge){
            window.bridge.showToast('from js methods');
        }
    })

此时js能够成功 调用到android中原生方法,可是回调会很麻烦,4.4中有evaluatejavascript能够实现,可是未兼容到4.4如下。至此,由于本文中的重点,hybird的实现方案及js与android交互方案。web

hybird中的实现方式

原理与android中原生schema协议相似,经过拦截URl形式实现。能够经过自定义协议名称,而后webView中拦截这个schema,并解析其中参数与回调函数,js调用android方法,并实现回调。
首先定义协议,即须要拦截的scheme ,我在这里定义 myschema://utils,这个协议名能够是任意的,只要拦截统一便可。
封装的js方法以下安全

function invoke(action, data, callback) {
        // 拼装 schema 协议,action对应须要实现的方法名
        var schema = 'myshema://utils/' + action

        // 拼接参数 data对应参数 
        schema += '?a=a'
        var key
        for (key in data) {
            if (data.hasOwnProperty(key)) {
                schema += '&' + key +"="+ data[key];
            }
        }

        // 处理 callback
        var callbackName = ''
        if (typeof callback === 'string') {
            callbackName = callback
        } else {
            callbackName = action + Date.now()
            window[callbackName] = callback
        }
        schema += '&callback='+callbackName;
        //最终拼接出来应该是zhezhong这种形式 myshema://utils/actioin?a=a&key=value&callback=callbackName
        // 触发
        var iframe = document.createElement('iframe')
        iframe.style.display = 'none'
        iframe.src = schema  // 重要!此处会发送链接,会被webviwe捕获到
        var body = document.body
        body.appendChild(iframe)
        setTimeout(function () {
            body.removeChild(iframe)
            iframe = null
        })
    }

index中服务器

document.getElementById('btn1').addEventListener('click', function () {
            // invokeScan()
            invoke('showToast',{name:'js'},function(res){
                console.log("回调成功",res)'
            })
            //location.href="http://www.baidu.com";
        })

android中,将js文件与index文件放置与assets文件夹下,webView加载此index,并设置拦截,代码以下网络

myWebView.setWebViewClient(new WebViewClient(){
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                //重要,此处实现拦截,可解析参数,根据action名称调用不一样方法,此处未演示
                if(url.contains("myshema://utils/")){
                    Toast.makeText(MainActivity.this,"调用成功",Toast.LENGTH_LONG).show();
                    String callback = "";
                    Map<String,String> params = UriUtil.URLRequest(url);
                    if(params.containsKey("callback")){
                        view.loadUrl("javascript:"+params.get("callback")+"()");
                    }

                }else{
                    view.loadUrl(url);
                }
                return true;
            }
        });
        myWebView.loadUrl("file:///android_asset/index.html");

至此,实现了经过自定义schema实现js拦截调用android原生方法的方案,此方案好处是能够隐藏调用细节,将调用细节封装到内部,更安全,并且兼容性更好.
如有问题,欢迎提问并与我联系,转载请注明做者!app

相关文章
相关标签/搜索