美文网首页android 集结号Android经验和架构Android知识
谈谈WebView的使用【从零开始搭建android框架系列(5

谈谈WebView的使用【从零开始搭建android框架系列(5

作者: 程序员Anthony | 来源:发表于2016-05-12 16:37 被阅读13084次

    本篇文章项目github地址:MVPCommon
    本文章原地址:简书博客

    项目效果

    1 前言

    这篇文章将从webview的基础,介绍到项目中的真实使用。以及怎么样通过注入js脚本的方式来改变网页内容,从而在本地展示新闻体育列表。制作出一个像模像样的app。
    严正声明,网页数据来自 虎扑体育,仅作学习用途,请勿在任何商业用途中使用。

    2 webview基础

    WebView是手机中内置了一款高性能 webkit 内核浏览器,在 SDK 中封装的一个组件。没有提供地址栏和导航栏,WebView只是单纯的展示一个网页界面。在开发中经常都会用到。

    Android4.4(API版本19)引入了新的一个基于Chromium版本的新版本WebView。该变化提高了WebView的性能,并且和最新的Web浏览器支持最新的HTML5,CSS3样式以及Javascript标准。当在 Android 4.4或者更高的版本上面运行时,任何使用WebView的application会继承使用这些特性。本文章主要描述了一下WebView的新特性。如果你设置targetSdkVersion为19或者更高时,那你就需要特别的注意。这里不做过多讲解,参考** Migrating to WebView in Android 4.4(官网)**

    2.1 添加webview到应用中

    直接将webview添加到layout文件中

    <?xml version="1.0" encoding="utf-8"?>
    <WebView  xmlns:android="http://schemas.android.com/apk/res/android"    
    android:id="@+id/webview"   
     android:layout_width="fill_parent"    
    android:layout_height="fill_parent"/>
    

    使用webview加载url使用loadUrl方法:

    WebView myWebView = (WebView) findViewById(R.id.webview);
    myWebView.loadUrl("http://www.example.com");
    

    AndroidManifest.xml 中必须添加访问网络权限。

    <manifest ... >   
     <uses-permission android:name="android.permission.INTERNET" />  
      ...
    </manifest>
    
    2.2 支持javascript

    如果访问的页面中有 Javascript,则 WebView 初始化的时候必须设置支持 Javascript。(WebSetting中提供了很多有用的api, 点击链接查看)

    WebView myWebView = (WebView) findViewById(R.id.webview);
    WebSettings webSettings = myWebView.getSettings();
    webSettings.setJavaScriptEnabled(true);
    

    通过创建JavaScript的接口可以让JavaScript和安卓客户端进行交互。比如说JavaScript可以调用本地的安卓代码展示一个Dialog而不是使用JavaScript的alter()方法。通过addJavascriptInterface()方法创建接口。
    示例:
    定义一个“接口”类

    public class WebAppInterface {
        Context mContext;
    
        /** Instantiate the interface and set the context */
        WebAppInterface(Context c) {
            mContext = c;
        }
    
        /** Show a toast from the web page */
        @JavascriptInterface
        public void showToast(String toast) {
            Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
        }
    }
    

    在addJavascriptInterface方法中创建接口

    WebView webView = (WebView) findViewById(R.id.webview);
    webView.addJavascriptInterface(new WebAppInterface(this), "Android");
    

    在HTML的JavaScript中调用WebView显示toast消息,

    <input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
    
    <script type="text/javascript">
        function showAndroidToast(toast) {
            Android.showToast(toast);
        }
    </script>
    

    注意:
    1 addJavascriptInterface方法中要绑定的Java对象及方法运行在另外的线程中,而不是运行在构造他的线程中。
    2 使用addJavascriptInterface将会使javaScript可以操控安卓本地代码。因此有可能导致安全性问题,请确保所有HTML代码都是你所知道的。
    3 如果targetSdkVersion是17或者更高(android 4.2以上),必须使用 @JavascriptInterface 注解,才能让网页访问到本地代码。

    2.3 webview页面处理

    当用户点击webview中的网页链接的时候,安卓系统默认会启动一个新的应用专门成立url的跳转。如果希望点击链接继续在当前webview中响应,而不是新开Android的系统browser中响应该链接,必须覆盖 WebView的WebViewClient对象. 并重写shouldOverrideUrlLoading方法。

    WebView myWebView = (WebView) findViewById(R.id.webview);
    myWebView.setWebViewClient.(new WebViewClient();
    private class MyWebViewClient extends WebViewClient {
       @Override
       public boolean shouldOverrideUrlLoading(WebView view, String url) {
           if (Uri.parse(url).getHost().equals("www.example.com")) {
               // This is my web site, so do not override; let my WebView load the page
               return false;
           }
           // Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
           Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
           startActivity(intent);
           return true;
       }
    }
    
    2.4 webview的页面导航处理

    当webview的url进行跳转的时候,自动回记录进入历史界面,可以使用goBack()方法和goForward()方法,进行返回和前进。
    webview的canGoBack方法将会判断历史记录中是否还有页面,如果还有上一级页面,将会返回true。

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        // Check if the key event was the Back button and if there's history
        if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
            myWebView.goBack();
            return true;
        }
        // If it wasn't the Back key or there's no web page history, bubble up to the default
        // system behavior (probably exit the activity)
        return super.onKeyDown(keyCode, event);
    }
    

    3 webview在项目中使用

    如果还需要了解更多,推荐4 参考链接中的深入讲解Webview(上,下)。
    这里接着介绍WebView在我项目中的使用。

    3.1 需求是什么?

    当然在我项目中,最开始想做的一个体育新闻资讯,但是苦于自己没有服务器,所以一开始都是模拟的数据。网上的开源api也是将所有新闻数据糅合在一起的,怎么分开呢?比如nba,英超,欧冠,各种不同的新闻数据在哪里获取呢?作为一个体育爱好者,经常会去的虎扑体育,然后找到了手机版的 虎扑体育。这不就是我想要的体育新闻数据嘛,O(∩_∩)O哈哈~。
    但是我不想要这个头部和底部呢 ,接下来分析怎么处理,很简单的实现。


    3.2 效果怎么样?

    看看运行效果,还是有模有样的


    3.3 怎么做?

    主要就是进行了新闻网页的展示,并且去掉了头部和底部。

    public class WebViewFragment extends AbsTitleFragment {
      ......
    
            R.layout.fragment_web_view;
      ......
    
        @Override
        protected void initViewsAndEvents(View rootView) {
            mWebView.setVisibility(View.INVISIBLE);
            toggleShowLoading(true, "loading");
    
            setWebViewOption(mWebView);
            if (getFragmentUrl() != null) {
                mWebView.loadUrl(getFragmentUrl());
            }
        }
    
        private void setWebViewOption(WebView webview) {
         ......
            //设置是否支持运行JavaScript,仅在需要时打开
            webview.getSettings().setJavaScriptEnabled(true);
    
            ......
            //设置WebViewClient
            webview.setWebViewClient(new MyWebViewClient());
            webview.setWebChromeClient(new MyWebChromeClient());
        }
    
        private class MyWebViewClient extends WebViewClient {
    
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
    //            view.loadUrl(url);
                Intent intent = new Intent(mContext, WebViewActivity.class);
                intent.putExtra(WebViewActivity.WEB_VIEW_URL, url);
                startActivity(intent);
                return true;
            }
      ......
    
            @Override
            public void onPageFinished(WebView view, String url) {
    
                super.onPageFinished(view, url);
                toggleShowLoading(false, "");
                if (view.getVisibility() == View.INVISIBLE) {
                    view.setVisibility(View.VISIBLE);
                }
            }
    
       ......
        }
    
    
        private class MyWebChromeClient extends WebChromeClient {
        ......
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                if (newProgress > 25) {
                    injectJS(view);
                }
                
                super.onProgressChanged(view, newProgress);
            }
        }
    
    
        private void injectJS(WebView webview) {
            webview.loadUrl("javascript:(function() " +
                    "{ " +
                    "document.getElementsByClassName('m-top-bar')[0].style.display='none'; " +
                    "document.getElementsByClassName('m-footer')[0].style.display='none';" +
                    "document.getElementsByClassName('m-page')[0].style.display='none';" +
                    "})()");
        }
    }
    

    可以看到WebView的初始化在setWebViewOption方法中进行。其中需要关注的有下面三行代码



    上面在WebSetting方法中WebViewClient的初始化,这里主要是点击新闻进行页面跳转的处理。


    提供WebViewClient并重写shouldOverrideUrlLoading方法,并返回true
    webview的返回键必须做处理,如果当前webview支持返回(不是点进来的第一个webview,而是再次跳转的),则返回。如果不支持返回(第一个webview界面),则finish当前的页面。

    初始化WebView的时候也进行了WebChromeClient的初始化。其中主要是在当进度超过百分之25的时候注入了一段javaScript代码。通过javascript代码去掉了当前网页的头部和底部。


    3.4 为什么这么做?

    上面就是通过对网页信息注入js的形式,隐藏了相应的属性。
    如图,去掉标题栏,在网页中通过F12打开开发者工具,发现顶部栏的class的名字是m-top-bar,所以通过注入脚本的时候直接调用了这个class并且将display置为none。对这方面不了解的可以学习一下Html5相关的知识。



    至于为什么是在进度条进行25之后进行注入,这里主要是在界面加载完成后再进行注入js就会有一定的卡顿闪屏现象。可以自己实践一下。

    本篇文章项目github地址:MVPCommon

    注意:由于项目构建的需要,关于webview在本项目中利用js注入实现网页列表的效果将在本项目中移除。(2016.7.22)

    4 参考链接

    Web Apps(官网)
    ->1 Supporting Different Screens from Web Apps(官网)
    ->2 Building Web Apps in WebView(官网)
    ->3 Migrating to WebView in Android 4.4(官网)
    ->4 Debugging Web Apps(官网)
    ->5 Best Practices for Web Apps(官网)

    深入讲解WebView-上
    深入讲解WebView-下

    相关文章

      网友评论

      • IceDeeew:如果想把 下面想替换成自己的导航栏 怎么实现那
      • 666swb:你好,这个github上的地址好像不是哦? 请指教
      • 王人冉:楼主,直接导入as中报错,什么原因
        E:\Users\xxx\Ant-master\rxapp\build.gradle
        Error:(105, 0) CreateProcess error=2, 系统找不到指定的文件。
        <a href="openFile:E:\Users\wqx\AndroidStudioProjects\Ant-master\rxapp\build.gradle">Open File</a>
      • VH2016:好好,懂的好多,谢谢
      • v3sona:· if (newProgress > 25) {
        injectJS(view);

        这样写大于25的时候 岂不是调用了75次injectJs(view)?
        程序员Anthony:@vsona 代码的参考,只是说希望能够给大家介绍怎么使用注入js,但是使用的方法可能欠妥,这边我在实际中也不会这么使用, 可能还要考虑一下。
      • 4b5a49c9c63c: :blush: 这个不错,比网上很多其他的资料要详细得多。
      • 程序员Anthony:下面是不同的网页,上面tab的是根据不同的网页信息,自己写的栏目名称
      • 8587af06ce05:请问外面列表的数据如何获取?
      • Daly:myWebView.setWebViewClient.(new WebViewClient();
        private class MyWebViewClient extends WebViewClient {

        请问这个代码是几个意思?
      • 小菜啊:活捉一只jr
        程序员Anthony:@哥特复兴 :grin:
      • starryZzz:你好,请问你的虎扑接口从哪儿获取的,文中的链接失效了
        程序员Anthony:@starryZzz m.hupu.com 。就是一个网页而已。不是数据接口

      本文标题:谈谈WebView的使用【从零开始搭建android框架系列(5

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