Android webkit

988 阅读4分钟

一、基础

现在Android应用 层开发的方向有两种:客户端开发和HTML5移动端开发!
所谓的HTML5端就是:HTML5 + CSS + JS来构建 一个网页版的应用,而这中间的媒介就是这个WebView。
Web和网页端可以通过JS来进行交互,比如, 网页读取手机联系人,调用手机相关的API等!

  • WebChromeClient:辅助WebView处理Javascript的对话框、网站图标、网站title、加载进度等,如onJsAlert处理Js中的Alert对话框;
  • WebViewClient:辅助WebView处理各种通知与请求事件,如onPageFinished通知主程序,网页加载完毕 ;
  • WebSettings:WebView相关配置的设置,比如setJavaScriptEnabled()设置是否允许JS脚本执行; demo: java改写js里的alert方法
   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        wView = (WebView) findViewById(R.id.wView);

        //获得WebSetting对象,支持js脚本,可访问文件,支持缩放,以及编码方式
        WebSettings webSettings = wView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setAllowFileAccess(true);
        webSettings.setBuiltInZoomControls(true);
        webSettings.setDefaultTextEncodingName("UTF-8");
        //设置WebChromeClient,处理网页中的各种js事件
        wView.setWebChromeClient(new MyWebChromeClient());
        wView.setWebViewClient(new MyWebViewClient());

        wView.loadUrl("file:///android_asset/demo2.html");
    }

     //自定义回调
    class MyWebViewClient extends BridgeWebViewClient {
        public MyWebViewClient(BridgeWebView webView) {
            super(webView);
        }
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            //DialogShow.showRoundProcessDialog();
        }
        @Override
        public void onPageFinished(WebView view, String url) {
            DialogShow.closeDialog();
            addImageClickListner();
            llContent.setVisibility(View.VISIBLE);
            if (ScrollY != 0) {
                webView.scrollTo(ScrollX, ScrollY);
            }
            //这个是一定要加上那个的,配合scrollView和WebView的height=wrap_content属性使用
            int w = View.MeasureSpec.makeMeasureSpec(0,
                    View.MeasureSpec.UNSPECIFIED);
            int h = View.MeasureSpec.makeMeasureSpec(0,
                    View.MeasureSpec.UNSPECIFIED);
            //重新测量
            webView.measure(w, h);
            super.onPageFinished(view, url);
        }
    }


    //这里需要自定义一个类实现WebChromeClient类,并重写三种不同对话框的处理方法
    //分别重写onJsAlert,onJsConfirm,onJsPrompt方法
    class MyWebChromeClient extends WebChromeClient {
        @Override
        public boolean onJsAlert(WebView view, String url, String message,
                                 final JsResult result) {
            //创建一个Builder来显示网页中的对话框
            new Builder(MainActivity.this).setTitle("Alert对话框").setMessage(message)
                    .setPositiveButton("确定", new OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            result.confirm();
                        }
                    }).setCancelable(false).show();
            return true;
        }
    }

java调用js

  1. 通过WebViewloadUrl() 
  2. 通过WebViewevaluateJavascript()
  • webView.loadUrl
webView.loadUrl("javascript:methodName(parameterValues)");

String call = "javascript:alertMessage(\"" + "content" + "\")";
webView.loadUrl(call);
  • evaluateJavascript 从Android 4.4开始,Android中的WebView不再是基于WebKit的,而是开始基于Chromium
webView.evaluateJavascript("getYourCar()", new ValueCallback<String>() {
  @Override
  public void onReceiveValue(String s) {
      Log.d("findCar",s);
  }
 });

js调用java

  1. 通过WebViewaddJavascriptInterface()进行对象映射 
  2. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url 
  3. 通过 WebChromeClient 的onJsAlert()onJsConfirm()onJsPrompt()方法回调拦截JS对话框alert()confirm()prompt() 消息

addJavascriptInterface 2个步骤:
1,webview.getSettings().setJavaScriptEnabled(true);
2,webview.addJavascriptInterface(object,"name");

wView = (WebView) findViewById(R.id.wView);
wView.loadUrl("file:///android_asset/demo1.html");
WebSettings webSettings = wView.getSettings();
//①设置WebView允许调用js
webSettings.setJavaScriptEnabled(true);
webSettings.setDefaultTextEncodingName("UTF-8");
//②将object对象暴露给Js,调用addjavascriptInterface
wView.addJavascriptInterface(new MyObject(MainActivity.this), "myObj");

更多见: www.runoob.com/w3cnote/and…

二、Android webkit

image.png

  • skia : android于chrome 共同使用的图形库,图形文字绘制
  • chromium-net:chrome源码中抽离出的网络库
  • wtf:web template framework公共基础库
  • v8:js引擎,js脚本执行
  • webcore:html/css解析、排版及js的dom绑定
  • webkit:封装c++层,提供与java交互的接口
  • framework: 对外提供java的webkit api;

webkit线程结构

  • messageQueue:主线程入口一个循环loop,waitForMessage,没有消息队列则挂起,有消息则循环处理消息;
  • task传递:异步回调js的接口,调用callOnMainThread将消息放入主线程的执行队列;

资源加载

image.png

  • 主资源:载入frame的html文档。产生: java层的loadUrl和页面链接发出的请求;
  • 派生资源:js、css、image等

  • page cache:页面缓存。浏览器页面dom树、render树临时保存,加速页面返回;
  • memory cache:内存缓存。浏览器内部的缓存机制,相同的url直接返回;
  • disk cache:磁盘缓存。资源加载与服务器进行交互

webkit

image.png

  • webview:ui线程、主线程
  • webviewcore:工作线程
  • callbackProxy:为工作线程向ui线程发起事件消息回调
  • broserFrame:webcode中frame对象上层封装

网页加载

  • ui线程 setWebViewClient设置回调,然后webview.loadUrl加载网页;
  • loadUrl方法发送消息给webviewcore对象
  • webviewcore调用broserFrame,broserFrame调用jni函数nativeLoadUrl在c++层加载网页
  • c++ webframe 调用webcore加载网页 工作线程触发回调
  • webframe 收到调用
  • 通过jni调用broserFrame
  • broserFrame 的函数触发 callbackProxy 的onPageStarted回调
  • callbackProxy生成消息,发送给handleMassage消息处理函数
  • webviewClient回调被触发

js扩展接口

  • v8 binding:webcore中的dom、css等操作接口通过web IDL暴露给v8,js就可以操作dom了
  • extension

v8 api见

推荐阅读: 《JSBridge 的原理》

欢迎关注我的前端自检清单,我和你一起成长