目的

WebView是一个比较常用的控件功能上也比较单一,就是用来加载网页的,可以加载远程的网页,也可以加载本地网页文件简单来说就相当于一个浏览器。这篇文章将对WebView使用相关内容做个简单记录

官方文档https://developer.android.google.cn/guide/webapps

基础使用

WebView控件使用寄来挺简单,无非是在视图添加该控件,然后代码设置控件相关属性加载加载的网页,最后需要开启相关权限。下面是个简单的示例

activity_main.xml 文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 省略若干... &gt;

    <!-- 添加WebView对象 --&gt;
    <WebView
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" /&gt;

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.java 文件:

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.webkit.WebSettings;
import android.webkit.WebView;

public class MainActivity extends AppCompatActivity {

    @SuppressLint("SetJavaScriptEnabled") // 忽略使能JS警告
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); //隐藏状态栏
        setContentView(R.layout.activity_main);

		WebView myWebView = findViewById(R.id.webview); // 获取WebView控件
        WebSettings webSettings = myWebView.getSettings();
        webSettings.setJavaScriptEnabled(true); // 使加载的网页可以运行JS代码
        myWebView.loadUrl("https://html5test.com/"); // 加载网页链接
        // https://html5test.com/是一个测试Html功能兼容性的网站
        // 你要是喜欢也可以使用https://www.baidu.com/等
    }
}

AndroidManifest.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest 省略若干... >

	<!-- 下面一行使APP可以访问网络内容 -->
    <uses-permission android:name="android.permission.INTERNET" />

    <application
    	<!-- 使用没有标题栏主题来去除标题栏 -->
    	android:theme="@style/Theme.AppCompat.NoActionBar"
    	<!-- 下面一行使WebView可以访问基于HTTP协议的明文内容 -->
        android:usesCleartextTraffic="true"
        <!-- 省略若干... -->
    </application>

</manifest>

在这里插入图片描述

WebView使用基本上要涉及的东西都在上面演示中展示了,主要分为三个方面:

前面演示中配置加载的网页可以使用JS代码,通常来说现在的网页为了获得更好效果或是更多的功能通常都会有JS代码,所以这个功能基本上都需要打开需要注意的是这会降低安全性,具体使用时需要根据实际情况来设置。

上面的 WebSettings 除了可以用来设置是否启用JS外,还有非常多的功能可以设置,比如是否可以缩放,是否可以跨域,是否可以缓存功能,这些都可能是在一定应用比较重要的功能。详细的内容可以参考下面链接
https://developer.android.google.cn/reference/kotlin/android/webkit/WebSettings

处理网页导航

WebView使用上比较常用的需要考虑的就是处理网页导航

在上面的演示中,如果网页中有别的链接点击这些链接默认调用系统浏览器打开这些链接。很多时候我们可能比想要通过浏览器打开,而是通过当前的WebView来打开这些链接,这就需要在代码中对WebView控件进行一些设置了:

import android.webkit.WebViewClient;

WebView myWebView = findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient()); // 就是这一行

当进行上面设置后WebView就像浏览器一样可以在页面跳转,这写操作都会留下历史访问记录我们可以使用WebView控件的 goBack()goForward() 方法来向后或向前浏览历史记录。在Android中因为Android设备返回键,所以通常将返回键和 goBack() 方法绑定使用,比如下面这样:

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class MainActivity extends AppCompatActivity {

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        WebView myWebView = findViewById(R.id.webview);
        myWebView.setWebViewClient(new WebViewClient()); // 在当前WebView打开链接
        WebSettings webSettings = myWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        myWebView.loadUrl("https://blog.csdn.net/Naisu_kun");
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        WebView myWebView = findViewById(R.id.webview);

        // 如果点击返回键,并且myWebView当前可以返回,则执行goBack()方法
        if ((keyCode == KeyEvent.KEYCODE_BACK) &amp;&amp; myWebView.canGoBack()) {
            myWebView.goBack();
            return true;
        }

        // 不满足前面条件执行系统默认行为
        return super.onKeyDown(keyCode, event);
    }
}

在这里插入图片描述

上面的 WebViewClient 封装了WebView控件各个事件的回调,比如其中的 shouldOverrideUrlLoading 就是来处理url跳转相关事务

加载本地网页

加载本地网页最简单的就是以字符串形式加载:

String html = "<html><body><p>Hello world</p></body></html>";
String encodedHtml = Base64.encodeToString(html.getBytes(), Base64.NO_PADDING);
myWebView.loadData(encodedHtml, "text/html", "base64");

或者下面形式:

String html = "<html><body><p>Hello world</p></body></html>";
String baseUrl = "https://example.com/";
myWebView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl);

当然上面方式通常只是简单的页面才用用,更多的是把网页文件打包项目中,然后直接把文件加载到WebView中。比如我们可以在项目项目目录/app/src/main/ 下建立 assets 目录然后将网页文件都放在该目录下,然后在代码中使用下面式来加载:

myWebView.loadUrl("file:///android_asset/index.html");
// 上面的file:///android_asset/这个路径默认指的就是 项目目录/app/src/main/assets/ 

在这里插入图片描述
上面方式因为同源策略跨域默认情况下是不允许JS加载其它资源的,得进行设置:

// 设置在WebView内部是否允许通过file url加载的 Js代码读取其他的本地文件
// webSettings.setAllowFileAccessFromFileURLs(true);
// 设置WebView内部是否允许通过 file url 加载的 Javascript 可以访问其他的源(包括httphttps等源)
webSettings.setAllowUniversalAccessFromFileURLs(true);

当然上面方式被认为是不安全的,现在官方推荐使用 WebViewAssetLoader 来加载本地网页。这种方式原理是把WebView发出的所有请求进行拦截,然后使用 WebViewAssetLoader 来分辨处理是加载本地资源还是远程资源。对例程的代码进行调整演示:

package com.example.myapplication;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.webkit.WebViewAssetLoader;
import androidx.webkit.WebViewClientCompat;

import android.annotation.SuppressLint;
import android.net.Uri;
import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;

public class MainActivity extends AppCompatActivity {

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

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

        // WebViewClientCompat就等同于WebViewClient,封装了WebView控件各个事件的回调
        // 重写该类的shouldInterceptRequest方法,该方法对发出的请求进行拦截处理
        // 这里就将该拦截转给WebViewAssetLoader来处理
        class LocalContentWebViewClient extends WebViewClientCompat {

            private final WebViewAssetLoader mAssetLoader;

            LocalContentWebViewClient(WebViewAssetLoader assetLoader) {
                mAssetLoader = assetLoader;
            }

            @Override
            @RequiresApi(21)
            public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
                return mAssetLoader.shouldInterceptRequest(request.getUrl());
            }

            @Override
            @SuppressWarnings("deprecation") // to support API < 21
            public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
                return mAssetLoader.shouldInterceptRequest(Uri.parse(url));
            }
        }

		// 创建WebViewAssetLoader对象
		// 设置资源路径/assets/,即 项目目录/app/src/main/assets/ 
        final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
                .addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this))
                .build();

		// 加载上面处理
        myWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));

		// 这里https://appassets.androidplatform.net是个默认的路径
		// 下面最终其实访问的是 项目目录/app/src/main/assets/index.html 文件
        myWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        WebView myWebView = findViewById(R.id.webview);
        if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
            myWebView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

在这里插入图片描述

WebViewAssetLoader 也可以混合加载本地的和远程资源,比如下面这样:

final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
		.setDomain("example.com") // 远程地址域名
        .addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this))
        .build();

上面的设置下 WebViewAssetLoader 会先从本地寻找资源进行加载,如果本地找不到就从远程加载。

WebViewAssetLoader 更多内容可以参考下面链接
https://developer.android.google.cn/reference/kotlin/androidx/webkit/WebViewAssetLoader

Web和Native之间交互

Web和Native之间交互主要依赖WebView的 addJavascriptInterface 方法。参考下面演示:

class WebAppInterface {
    @JavascriptInterface
    public void webToNative(String str) {
        System.out.println(str);
    }

    @JavascriptInterface
    public String nativeToWeb() {
        return "msg: native to web";
    }
}

// 使用addJavascriptInterface方法将WebAppInterface对象传递给web的"native"对象
myWebView.addJavascriptInterface(new WebAppInterface(), "native");
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <button>传递信息给Native</button>
    <br>
    <button>从Native获取信息</button>
    <div></div>
    <script>
        btns = document.querySelectorAll('button');
        btns[0].onclick = () => {
            native.webToNative('msg: web to native');
        };

        btns[1].onclick = () => {
            let msg = native.nativeToWeb();
            document.querySelector('div').innerText = msg;
        };
    </script>
</body>
</html>

在这里插入图片描述

另外在Java中也可以直接调用web中的JS方法,主要使用下面方式

webView.loadUrl(javascript:methodName(parameterValues))

上面的 methodName 指的是绑定window 对象上的方法,可以不传入参数或者传入参数参数通常为数值或是字符串,传入字符串时需要加引号转义,比如下面例子

// 传入数值
webView.loadUrl("javascript:console.log(233)");

// 传入字符
String str = "Hello Naisu!";
webView.loadUrl("javascript:console.log('" + str  + "')");

上面方式调用JS方法是没有返回值的,可以使用 evaluateJavascript 方式调用,这样可以接收返回值:

webView.evaluateJavascript("jsfunc()", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String value) {
        // value即返回值
}});

调试Web应用

默认情况下Web中JS打印输出控制台的信息console.log() )都会在Android Studio的Logcat窗口中显示。
在这里插入图片描述
这里真机调试一直没问题,使用模拟器有时候就不行,不过一般也不会用模拟器来开啦。

处理页面重绘

默认情况下Android中页面尺寸改变或旋转视图会重新绘制,在这里通常体现为屏幕旋转时WebView加载的页面恢复为了初始状态,这很多时候不符合我们预期的需求,所以需要稍加处理:

AndroidManifest.xml 文件中添加 android:configChanges="orientation|screenSize"

<?xml version="1.0" encoding="utf-8"?>
<manifest 省略若干... >
	<!-- 省略若干... -->
    <application
        <!-- 省略若干... -->
        <activity 
        	省略若干...
        	android:configChanges="orientation|screenSize" >
			<!-- 省略若干... -->
		</activity>
    </application>
</manifest>

MainActivity.java 文件:

// ...

public class MainActivity extends AppCompatActivity {
	private WebView myWebView;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // ...

        if (savedInstanceState == null) {
            myWebView.loadUrl("...");
        }
    }
    
    @Override
    protected void onSaveInstanceState(Bundle outState)
    {
        super.onSaveInstanceState(outState);
        myWebView.saveState(outState); // 保存状态
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState)
    {
        super.onRestoreInstanceState(savedInstanceState);
        myWebView.restoreState(savedInstanceState); // 恢复状态
    }
}

总结

WebView控件控件的使用比较简单,大多数会遇到的问题都是与安全相关的各种权限问题基本上都只要打开相关的权限即可。更多内容可以参考官方文档

虽然文章标题说了Native APP,不过我其实是准备用WebView来做Hybrid App的。

原文地址:https://blog.csdn.net/Naisu_kun/article/details/127243840

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_10119.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注