zoukankan      html  css  js  c++  java
  • WebView

     转自:WebView你真的熟悉吗?看了才知道

    在Android手机中内置了一款高性能webkit内核浏览器,在SDK中封装为一个叫做WebView组件。下面总结一下使用webview遇到的那些事、那些坑。

    目录

    一、webview的基本使用方法

    二、webview与js的交互(附上示例项目完整源码)

    1.js与android的交互
    2.android调用js无参无返回值函数
    3.android调用js有参无返回值函数
    4.android调用js有参有返回值函数(4.4之前)
    5.android调用js有参有返回值函数(4.4之后)
    6.获取网页图片进行放大

    三、webview遇到的那些坑与解决方法**

    一、webview的基本使用方法

    1. 添加权限:AndroidManifest.xml中设置权限"android.permission.INTERNET",否则会出Web page not available错误。

    2. 在要Activity中生成一个WebView组件:WebView webView = new WebView(this);或者可以在activity的layout文件里添加webview控件

    3. 设置WebView基本信息:

    mWebView = (WebView) findViewById(R.id.wb);
    mWebView.getSettings().setJavaScriptEnabled(true);//支持javascript
    mWebView.requestFocus();//触摸焦点起作用mWebView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);//取消滚动条
    mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);//设置允许js弹出alert对话框
    //load本地
    mWebView.loadUrl("file:///android_asset/hellotest.html");
    //load在线
    //mWebView.loadUrl("http://www.google.com");
    //js访问android,定义接口
    mWebView.addJavascriptInterface(new JsInteration(), "control");
    //设置了Alert才会弹出,重新onJsAlert()方法return true可以自定义处理信息
    mWebView.setWebChromeClient(new WebChromeClient() {    
    @Override    
    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {        
    //return super.onJsAlert(view, url, message, result);        
    Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();        
    return true;  
      }});

    4. 设置WevView要显示的网页:互联网用:webView.loadUrl("http://www.google.com"); 本地文件用:webView.loadUrl("file:///android_asset/XX.html"); 本地文件存放在:assets文件中

    5. 如果希望点击链接由自己处理,而不是新开Android的系统browser中响应该链接。给WebView添加一个事件监听对象(WebViewClient)并重写其中的一些方法: shouldOverrideUrlLoading:对网页中超链接按钮的响应。当按下某个连接时WebViewClient会调用这个方法,并传递参数

    public boolean shouldOverrideUrlLoading(WebView view,String url){
           view.loadUrl(url);
           return true;          
            }

    6. 处理https请求
    webView默认是不处理https请求的,页面显示空白,需要进行如下设置:

    webView.setWebViewClient(new WebViewClient() { 
    @Override public void onReceivedSslError(WebView view, 
    SslErrorHandler handler, SslError error) { 
    handler.proceed(); 
    // handler.cancel(); 
    // handler.handleMessage(null); } });
    onReceivedSslError为webView处理ssl证书设置

    其中handler.proceed();表示等待证书响应
    handler.cancel();表示挂起连接,为默认方式
    handler.handleMessage(null);可做其他处理
    另外还有其他一些可重写的方法
    1,接收到Http请求的事件onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)
    2,载入页面完成的事件public void onPageFinished(WebView view, String url){ }
    同样道理,我们知道一个页面载入完成,于是我们可以关闭loading条,切换程序动作。
    3,载入页面开始的事件public void onPageStarted(WebView view, String url, Bitmap favicon) { }
    这个事件就是开始载入页面调用的,通常我们可以在这设定一个loading的页面,告诉用户程序在等待网络响应。 通过这几个事件,我们可以很轻松的控制程序操作,一边用着浏览器显示内容,一边监控着用户操作实现我们需要的各种显示方式,同时可以防止用户产生误操作。

    7. 如果用webview点链接看了很多页以后,如果不做任何处理,点击系统“Back”键,整个浏览器会调用finish()而结束自身,如果希望浏览的网页回退而不是退出浏览器,需要在当前Activity中处理并消费掉该Back事件。 覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法。

     @Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {  
      if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {    
        webView.goBack();// 返回前一个页面   
         return true;   
     }    
    return super.onKeyDown(keyCode, event);
    }

    二、webview与js的交互(相互调用参数、传值)

    前端网页全部代码,文章最后有示例项目完整源码

    <!DOCTYPE html><html><head>    <meta charset="utf-8">    
    <title>jaydenxiao遇上了webview</title>    
    <script>
    function sayHello() {
    alert("我是无参无返回toast") 
    }
    function alertMessage(message) { 
    alert(message)  
    }
    function toastMessage(message) {
    window.control.toastMessage(message)
    }
    function sumToJava(number1, number2){
    window.control.onSumResult(number1 + number2)
    }
    function sumToJava2(number1, number2) {
    return number1 + number2;
    }    
    </script>
    </head><body>
    <button type="button" id="button" onclick="toastMessage('js调用了android方法')">js访问android中方法</button>
    </body>
    </html>

    调用示例:

    js调用Java

    调用格式为window.jsInterfaceName.methodName(parameterValues)
    此例中我们使用的是control作为注入接口名称。

    function toastMessage(message) { 
    window.control.toastMessage(message) 
    }
     function sumToJava(number1, number2){ 
    window.control.onSumResult(number1 + number2)
     }
    Java调用JS

    webView调用js的基本格式为webView.loadUrl(“javascript:methodName(parameterValues)”)
    1. android调用js无参无返回值函数

    final String call = "javascript:sayHello()";
    mWebView.post(new Runnable() {    
    @Override    
    public void run() { 
           mWebView.loadUrl(call);    
    }});

    2. android调用js有参无返回值函数

    final String call = "javascript:alertMessage("" + "我是android传过来的内容,hey man" + "")";
    mWebView.post(new Runnable() {    
    @Override    
    public void run() { 
           mWebView.loadUrl(call);    
    }});

    3. android调用js有参有返回值函数(4.4之前)
    Android在4.4之前并没有提供直接调用js函数并获取值的方法,所以在此之前,常用的思路是 java调用js方法,js方法执行完毕,再次调用java代码将值返回。
    (1).android调用js代码

    final String call = "javascript:sumToJava(1,2)";
    mWebView.post(
    new Runnable() {  
      @Override   
     public void run() {       
     mWebView.loadUrl(call);   
     }});

    (2).js函数处理,并将结果通过调用android方法返回
    网页端:

    function sumToJava(number1, number2){ 
    window.control.onSumResult(number1 + number2) 
    }

    (3).android在回调方法中获取js函数返回值

    @JavascriptInterfacepublic void onSumResult(int result) {   
     Toast.makeText(getApplicationContext(), "我是android调用js方法(4.4前),入参是1和2,js返回结果是" + result, Toast.LENGTH_LONG).show();
    }

    4. android调用js有参有返回值函数(4.4以上):
    Android 4.4以上使用evaluateJavascript即可。这里展示一个简单的交互示例 具有返回值的js方法
    js代码如下:

    function sumToJava2(number1, number2) {
    return number1 + number2;
    }

    android代码如下:

    @TargetApi(Build.VERSION_CODES.KITKAT)
    public void Android2JsHaveParmHaveResult2(View view) { 
     mWebView.evaluateJavascript("sumToJava2(3,4)", new ValueCallback<String>() {
    @Override 
    public void onReceiveValue(String Str) {   
    Toast.makeText(getApplicationContext(), "我是android调用js方法(4.4后),入参是3和4,js返回结果是" + Str, Toast.LENGTH_LONG).show(); 
      }    
    });}

    三、webview遇到的那些坑与解决方法

    1. WebView的内存泄露。
    这个问题,很难清晰描述,你在谷歌里搜 webview lead memory 能搜到很多结果 甚至还有给谷歌提交的issue 哈哈,我也无法给出一个清晰的答案 在什么时候 什么版本那些手机上一定会出现内存泄露,
    但是根据一些monkey结果来看,有时,webview内存泄露的情况还是很严重的,尤其是当你加载的页面比较庞大的时候。解决方案参考下微信和qq的做法,试了一下是目前效果最好的,
    就是 当你要用webview的时候,记得最好 另外单独开一个进程 去使用webview 并且当这个 进程结束时,请手动调用System.exit(0)。
    这是目前对于webview 内存泄露 最好的解决方案。使用此方法 所有因为webview引发的 资源无法释放等问题 全部可以解决。

    2. getSettings().setBuiltInZoomControls(true) 引发的crush。
    这个方法调用以后 如果你触摸屏幕 弹出那个提示框还没消失的时候 你如果activity结束了 就会报错了。3.0以上 4.4以下很多手机会出现这种情况
    所以为了规避他,我们通常是在activity的onDestroy方法里手动的将webiew设置成 setVisibility(View.GONE)

    3.onPageFinished 函数到底有用没有?
    多数开发者都是参考的http://stackoverflow.com/questions/3149216/how-to-listen-for-a-webview-finishing-loading-a-url-in-android 这个上面的高票答案。
    但其实根据我自己观察,这个函数并没有什么卵用,有的时候是提前结束,有的时候就迟迟无法结束,你信这个函数 还不如信上帝,甚至于onProgressChanged这个函数
    都比onPageFinished 要准一些。如果你的产品经理坚持你一定要实现这种功能的话,我建议你 提早结束他,否则卡在那用户迟迟动不了 这种体验不好。
    有空的同学可以跟一下源码,onPageFinished 在不同的内核里 调用的时机都不一样。说实话 我也很醉。。。这个问题 有完美解决方案的 请知会我一下。。。

    4.后台无法释放js 导致耗电。
    这个可能很少有人知道,你如果webview加载的html里 有一些js 一直在执行比如动画之类的东西,如果此刻webview 挂在了后台
    这些资源是不会被释放,用户也无法感知,导致一直占有cpu 耗电特别快,所以大家记住了,如果遇到这种情况 请在onstop和onresume里分别把setJavaScriptEnabled();
    给设置成false和true。

    5.如果实在不想用开额外进程的方式解决webview 内存泄露的问题,那么下面的方法很大程度上可以避免这种情况

    public void releaseAllWebViewCallback() { 
     if (android.os.Build.VERSION.SDK_INT < 16) { 
     try { 
     Field field = WebView.class.getDeclaredField("mWebViewCore"); 
    field = field.getType().getDeclaredField("mBrowserFrame"); 
     field = field.getType().getDeclaredField("sConfigCallback");
    field.setAccessible(true); 
     field.set(null, null);
     } catch (NoSuchFieldException e) {
     if (BuildConfig.DEBUG) {
      e.printStackTrace();
      }
     } catch (IllegalAccessException e) {
     if (BuildConfig.DEBUG) {
      e.printStackTrace();
      }
      }
     } else {
     try {
     Field sConfigCallback = Class.forName("android.webkit.BrowserFrame").getDeclaredField("sConfigCallback");
     if (sConfigCallback != null) {
     sConfigCallback.setAccessible(true);
     sConfigCallback.set(null, null);
      }
     } catch (NoSuchFieldException e) {
    if (BuildConfig.DEBUG) {
      e.printStackTrace();
      }
     } catch (ClassNotFoundException e) {
     if (BuildConfig.DEBUG) {
      e.printStackTrace();
      }
     } catch (IllegalAccessException e) {
     if (BuildConfig.DEBUG) {
      e.printStackTrace();
      }
      }
      }
     }

    在webview的 destroy方法里 调用这个方法就行了。

    最后附上示例源码,欢迎fork and star

  • 相关阅读:
    POJ 1251 Jungle Roads
    1111 Online Map (30 分)
    1122 Hamiltonian Cycle (25 分)
    POJ 2560 Freckles
    1087 All Roads Lead to Rome (30 分)
    1072 Gas Station (30 分)
    1018 Public Bike Management (30 分)
    1030 Travel Plan (30 分)
    22. bootstrap组件#巨幕和旋转图标
    3. Spring配置文件
  • 原文地址:https://www.cnblogs.com/xinmengwuheng/p/5795934.html
Copyright © 2011-2022 走看看