您的位置:首页 > 移动开发

Android 入门第八讲01-WebView(WebView概述,基本用法(加载远程网页,加载本地网页),进阶用法(前进返回,清除缓存,网页自适应屏幕,缩放),WebView的三个子类)

2020-08-06 00:48 976 查看

Android 入门第八讲01-WebView(WebView概述,基本用法(加载远程网页,加载本地网页),进阶用法(前进返回,清除缓存,网页自适应屏幕,缩放),WebView的三个子类)

  • 2.加载本地网页
  • 3.WebView的进阶用法
  • 4.WebView的子类
  • 1.WebView概述-加载网页

    Android里面有很多页面,是可以用网页来写的,通过我们学习的web,写成html网页,来充当安卓中的一个页面,其实在我们很多应用程序里都用到了WebView,例如我们的公众号,小程序,很多的页面都不是用安卓来写的,其实是加载了一个网页。
    1.Android WebView在Android平台 上是一个特殊的View, 它能用来显示网页,这个WebView类可以被用来在app中仅仅显示一张在线的网页,当然还可以用来开发浏览器。

    2.WebView内部实现是采用渲染引擎(WebKit)来展示view的内容,提供网页前进后退、网页放大、缩小、搜索等功能。

    3.WebView是一个基于webKit引擎. 展现Web页面的控件, Androi d的WebView在低版本和高版本采用了不同的webKit版本内核。

    4.Android的Webview在低版本和高版本采用了不同的webkit版本内核, 4.4后直接使用了Chrome.

    WebView的优处

    1.节省工作量,节约人力成本

    打个比方,假设我们要写一个登录功能,对于不同系统ios和Android的话就要写两种登录方式,但是通过写一个网页然后再用webview来加载的话就只需要写一个登录界面,也就是说减少了一半的工作量

    2.开发的内容可以动态修改

    我们用安卓写的应用程序,安装在用户手机以后,那些控件就不能进行修改了,除非更新重新安装新的版本应用程序,但是我们的WebView,只需要修改网页上的内容,用户在下一次加载就可以更新页面内容,就例如我们在腾讯新闻,每天可以在同一个控件里却可以看到不同的新闻,

    WebView的缺处
    1.web网页的写法比安卓的写法慢(大概慢30%)

    2.WebView的基本用法

    第一步,添加权限

    在mainifests里添加权限代码

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

    在<application结点下添加

    android:usesCleartextTraffic="true"

    第二步,添加控件

    布局文件中添加WebView控件

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    
    <WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>

    第三步,获取网页

    1.加载远程网页

    1.一般网页
    public class MainActivity extends AppCompatActivity {
    
    WebView mWebView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mWebView=findViewById(R.id.webview);
    mWebView.loadUrl("https://me.csdn.net/qq_46526828");
    }
    }

    2.特殊网页(会调用系统浏览器)

    我们看这样一个例子

    我们可以发现,我们的应用程序并没有加载网页,而是调用了系统的浏览器去加载这个网页

    解决方法:我们可以通过重写shouldOverrideUrlLoading这个方法来使网页在程序内加载

    public class MainActivity extends AppCompatActivity {
    
    WebView mWebView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mWebView=findViewById(R.id.webview);
    
    mWebView.loadUrl("http://jd.com");
    mWebView.setWebViewClient(new WebViewClient(){
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
    view.loadUrl(url);
    return true;
    }
    });
    }
    }

    2.加载本地网页

    这里因为是使用本地数据,所以传入的url需要做些处理,例如:
    a.如果html文件存于assets:则加前缀:file:///android_asset/
    b.如果html文件存于data/data/包名目录:则加前缀:file:///data/data/包名/

    1.assets目录

    第一步,创建Assets文件夹

    第二步,创建 test.html 页面文件
    编写网页

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">//自适应屏幕
    <title>Document</title>
    </head>
    <body>
    <h1>标题1</h1>
    <h2>标题2</h2>
    <div>div content</div>
    </body>
    </html>

    第三步,加载本地网页

    public class MainActivity extends AppCompatActivity {
    
    WebView mWebView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mWebView=findViewById(R.id.webview);
    
    mWebView.loadUrl("file:///android_asset/test.html");}
    }


    修改运行

    2.data/data/包名目录

    第一步,复制之前assets文件的路径(按住ctrl+左键进入文件位置)
    第二步,将文件上传到data/data/包名 目录

    为什么要这样添加?因为复制粘贴没用,我试了嘿嘿

    第三步,加载网页

    public class MainActivity extends AppCompatActivity {
    WebView mWebView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mWebView=findViewById(R.id.webview);
    
    mWebView.loadUrl("file:///data/data/com.c201801020224.myapplication/test.html");
    }
    }

    我们用的比较多的本地加载页面通常是第二种方法,因为第一种方法会随着我们的apk一起打包给用户,而第二种方法是只有用户需要使用时,才会远程的去下载这个网页文件,所以比起第一种方法可以节省应用程序apk的内存大小

    3.WebView的进阶用法

    1.前进返回按钮的实现

    第一步,布局文件中添加按钮

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    
    <Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    android:layout_marginLeft="10dp"
    android:text="返回"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_marginTop="10dp"/>
    <Button
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintRight_toRightOf="parent"
    android:layout_marginRight="10dp"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_marginTop="10dp"
    android:text="前进"/>
    
    <WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>


    第二步,给button添加点击事件

    Button button=findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    mWebView.goBack();//返回
    }
    });
    
    Button button2=findViewById(R.id.button2);
    button2.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    mWebView.goForward();//前进
    }
    });


    运行

    补充:

    mWebView.goBack();//跳到上个页面
    mWebView.goForward();//跳到下个页面
    mWebView.canGoBack();//是否可以跳到上一页(如果返回false,说明已经是第一页)
    mWebView.canGoForward();//是否可以跳到下一页(如果返回false,说明已经是最后一页)
    //以当前的index为起始点前进或者后退到历史记录中指定的steps
    //如果steps为负数则为后退,正数则为前进
    //  mWebView.goBackOrForward(3);
    //  mWebView.goBackOrForward(-3);
    mWebView.goBackOrForward(intsteps);
    //重新加载当前请求
    mWebView.reload();

    2.清除缓存

    //清除网页访问留下的缓存
    //由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
    mWebView.clearCache(true);
    //清除当前webview访问的历史记录
    //只会webview访问历史记录里的所有记录除了当前访问记录
    mWebView.clearHistory();
    //这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据
    mWebView.clearFormData();

    3.网页自适应屏幕,缩放

    子类1-WebSettings类

    WebSettings webSettings = mWebView.getSettings();
    //如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
    webSettings.setJavaScriptEnabled(true);//js开关默认不打开,网页中的所有js方法就无法执行,如果我们把这个方法设置为ture,网页中搞得js方法才可以执行
    //设置自适应屏幕
    webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
    webSettings.setLoadWithOverviewMode(false); // 缩放至屏幕的大小
    //缩放操作
    webSettings.setSupportZoom(false); //支持缩放,默认为true。是下面那个的前提。
    webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
    webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件


    补充:

    //其他细节操作
    //缓存模式如下:
    //LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
    //LOAD_DEFAULT: (默认)根据cache-control决定是否从网络上取数据。
    //LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
    //LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据
    webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //webview缓存设置
    webSettings.setAllowFileAccess(true); //设置可以访问文件
    webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
    webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
    webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式

    4.WebView的子类

    1.子类1-WebSettings类

    2.子类2-WebViewClient类

    该类作用:处理各种通知 & 请求事件

    常见方法

    • onPageStarted(WebView view, String url, Bitmap favicon):WebView 开始加载页面时回调,一次Frame加载对应一次回调。

    • onPageFinished(WebView view, String url):WebView 完成加载页面时回调,一次Frame加载对应一次回 调。

    • onLoadResource(WebView view, String url):WebView 加载页面资源时会回调,每一个资源产生的一次网络加载,除非本地有当前 url 对应有缓存,否则就会加载。

    • shouldInterceptRequest(WebView view, String url):WebView 可以拦截某一次的 request 来返回我们自己加载的数据,这个方法在后面缓存会有很大作用。

    • shouldOverrideUrlLoading(WebView view, String url):是否在 WebView 内加载页面

    • onReceivedSslError(WebView view, SslErrorHandler handler, SslError error):WebView ssl
      访问证书出错,handler.cancel()取消加载,handler.proceed()对然错误也继续加载。

    • onReceivedError(WebView view, int errorCode, String description, String failingUrl):WebView 访问 url 出错

    这里重点讲下这几种方法
    1.onPageStarted和onPageFinished方法
    –用于监控网页的开始和结束–可以适用于加载网页时的进度条


    2.shouldOverrideUrlLoading

    –所有加载的页面都会经过这个方法–可以用来拦截加载的网页

    3.onReceivedError
    –可以检测到加载异常的网络–从而可以返回一个我们自定义写好的错误界面,对用户体验会好很多

    因为我的模拟器版本偏低,所以这里我用的旧版本写法
    这里补充一下,新旧版本都兼容的写法:

    // 旧版本,会在新版本中也可能被调用,所以加上一个判断,防止重复显示
    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
    super.onReceivedError(view, errorCode, description, failingUrl);
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
    return;
    }
    // 在这里显示自定义错误页
    }
    
    // 新版本,只会在Android6及以上调用
    @TargetApi(Build.VERSION_CODES.M)
    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
    super.onReceivedError(view, request, error);
    if (request.isForMainFrame()){ // 或者: if(request.getUrl().toString() .equals(getUrl()))
    // 在这里显示自定义错误页
    }
    }

    3.子类3-WebChromeClient类

    该类作用:辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等

    常用方法

    • onConsoleMessage(String message, int lineNumber,String sourceID):输出Web 端日志
    • onProgressChanged(WebView view, int newProgress):当前 WebView 加载网页进度。
    • onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result):处理 JS 中的 Prompt对话框
    • onJsAlert(WebView view, String url, String message, JsResult result): Js 中调用 alert() 函数,产生的对话框。
    • onReceivedTitle(WebView view, String title):接收web页面的 Title。
    • onReceivedIcon(WebView view, Bitmap icon):接收web页面的icon。

    我们先添加一下新网页,
    这里面有三个不同的弹框 -prompt,alert,confirm

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebView Study</title>
    <script>
    function clickPrompt() {
    prompt("prompt");
    }
    function clickAlert() {
    alert("alert");
    }
    function clicConfirm() {
    confirm("Confirm");
    }
    </script>
    </head>
    <body>
    <button type="button" onclick="clickPrompt()">Prompt调用</button>
    <button type="button" onclick="clickAlert()">Alert调用</button>
    <button type="button" onclick="clicConfirm()">Confirm调用</button>
    </body>
    </html>

    修改加载网页代码

    mWebView.loadUrl("file:///android_asset/test.html");

    运行

    1.对js按钮的监听

    mWebView.setWebChromeClient(new WebChromeClient(){
    
    @Override
    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    Log.i("Main","------onJsAlert");
    return super.onJsAlert(view, url, message, result);
    
    }
    
    @Override
    public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
    Log.i("Main","------onJsConfirm");
    return super.onJsConfirm(view, url, message, result);
    }
    
    @Override
    public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
    Log.i("Main","------onJsPrompt");
    return super.onJsPrompt(view, url, message, defaultValue, result);
    }
    });

    2.在js中自定义安卓弹框

    在监听方法中加入代码

    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this)
    .setIcon(R.mipmap.ic_launcher)
    .setTitle("title")
    .setMessage("message")
    .setPositiveButton("确定",
    new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    Toast.makeText(MainActivity.this, "确定按钮", Toast.LENGTH_LONG).show();
    }
    }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
    Toast.makeText(MainActivity.this, "关闭按钮", Toast.LENGTH_LONG).show();
    dialogInterface.dismiss();
    }
    });
    builder.create().show();
    
    return true;//屏蔽默认的js弹框

    ok 因为知识讲了挺多的,为了更好的消化,.本讲关于WebView的知识就先讲到这里啦,谢谢您的阅读,下一讲讲WebView的高级用法
    Android入门第八讲02-WebView的高级用法(Android调用 JS 代码( loadUrl 方法,案例练习),JS调用 Android 代码,流行框架总结,跨平台技术)

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: