Android Native APP开发笔记:使用WebView控件加载网页
文章目录
- 目的
- 基础使用
- 处理网页导航
- 加载本地网页
- Web和Native之间交互
- 调试Web应用
- 处理页面重绘
- 总结
目的
WebView是一个比较常用的控件,功能上也比较单一,就是用来加载网页的,可以加载远程的网页,也可以加载本地网页文件。简单来说就相当于一个浏览器。这篇文章将对WebView使用相关内容做个简单记录。
官方文档:https://developer.android.google.cn/guide/webapps
基础使用
WebView控件使用寄来挺简单,无非是在视图中添加该控件,然后在代码中设置控件相关属性并加载要加载的网页,最后需要开启相关权限。下面是个简单的示例:
activity_main.xml
文件:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 省略若干... ><!-- 添加WebView对象 --><WebViewandroid:id="@+id/webview"android:layout_width="match_parent"android:layout_height="match_parent" /></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警告@Overrideprotected 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使用基本上要涉及的东西都在上面演示中展示了,主要分为三个方面:
- 在界面中放置WebView控件;
- 在代码中设置WebView功能及需要加载的内容;
- 在APP配置中启用相关权限;
前面演示中配置加载的网页可以使用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")@Overrideprotected 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");}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {WebView myWebView = findViewById(R.id.webview);// 如果点击了返回键,并且myWebView当前可以返回,则执行其goBack()方法if ((keyCode == KeyEvent.KEYCODE_BACK) && 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 可以访问其他的源(包括http、https等源)
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")@Overrideprotected 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 < 21public 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");}@Overridepublic 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 {@JavascriptInterfacepublic void webToNative(String str) {System.out.println(str);}@JavascriptInterfacepublic 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()");// 传入数值
webView.loadUrl("javascript:console.log(233)");// 传入字符串
String str = "Hello Naisu!";
webView.loadUrl("javascript:console.log('" + str + "')");
调试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;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// ...if (savedInstanceState == null) {myWebView.loadUrl("...");}}@Overrideprotected void onSaveInstanceState(Bundle outState){super.onSaveInstanceState(outState);myWebView.saveState(outState); // 保存状态}@Overrideprotected void onRestoreInstanceState(Bundle savedInstanceState){super.onRestoreInstanceState(savedInstanceState);myWebView.restoreState(savedInstanceState); // 恢复状态}
}
总结
WebView控件控件的使用比较简单,大多数会遇到的问题都是与安全相关的各种权限问题,基本上都只要打开相关的权限即可。更多内容可以参考官方文档。
虽然文章标题说了Native APP,不过我其实是准备用WebView来做Hybrid App的。
Android Native APP开发笔记:使用WebView控件加载网页相关推荐
- Android使用webview控件加载本地html,通过Js与后台Java实现数据的传递
1.在布局文件中加WebView控件,在java中获取WebView对象. 2.加载本地html文件. webView.loadUrl("file:///android_asset/andr ...
- Android Native APP开发笔记:从新建到打包流程记录
文章目录 目的 下载与安装 新建项目与运行调试 更换名称和图标 打包应用 applicationId 版本控制 真机调试 总结 题外话 目的 安卓是现在移动端平台占有率最大的平台,如果进行移动端用户应 ...
- Android Native APP开发笔记:文件存储与访问
文章目录 目的 基础说明 应用专属存储空间 共享存储 其它 总结 目的 APP开发与使用过程中免不了和文件打交道,对于Windows或Linux而言文件的存储与访问操作都很方便,直接通过文件系统路径和 ...
- Android Native APP开发笔记:双击返回键退出应用单击返回键返回桌面
文章目录 目的 基础说明 双击返回键退出应用 单击返回键回到桌面 总结 目的 双击返回键退出应用 很早之前就是Android中非常常见的一种功能,而目前好多安卓应用为了应用常驻都改为使用 单击返回键返 ...
- 【Android】App首页上下滚动快报控件 通知控件 类似京东快报控件(一)
前言 快过年了,对于大伙来说手头上的事情做完没有呢,马上也该让自己轻松一阵子了,哈哈哈.好,说正事,由于公司App这个版本首页的改版,新增了很多新的控件,类似于京东快报这种控件的话我在写之前也去找了一 ...
- paip.gui控件tabs控件加载内容的原理以及easyui最佳实现
paip.gui控件tabs控件加载内容的原理以及easyui最佳实现 //tabs控件的加载 同form窗体一样,俩个方式 两个方式:一个是url,简单的文本可以使用这个,不适合事件的情形.. 一个 ...
- imageview控件加载图片
** 1.scaleType扩大类型: ** (1).android:scaleType="fitXy" 实现铺满整个控件 将原图进行横方向(即XY方向)的拉伸后绘制的. 效果: ...
- Picture Control 控件 加载图片 画线
编程中遇到问题,如何在已有图片上添加 虚线,图片使用Picture控件显示 参考网页https://bbs.csdn.net/topics/10044979 其中参考程序段如下: 这是我画线的程序: ...
- Android移动APP开发笔记——最新版Cordova 5.3.1(PhoneGap)搭建开发环境
引言 简单介绍一下Cordova的来历,Cordova的前身叫PhoneGap,自被Adobe收购后交由Apache管理,并将其核心功能开源改名为Cordova.它能让你使用HTML5轻松调用本地AP ...
最新文章
- Pytorch Bi-LSTM + CRF 代码详解
- 20172304 《程序设计与数据结构》第九周学习总结
- 【转知乎】人工智能会是泡沫吗?
- C++学习总结(函数、类与对象)
- codeforces 1017E
- VirtualBox 虚拟机复制
- pc版android sd卡,告别瓶颈:安卓闪存(SD卡)I/O优化
- 线性代数:矩阵运算之乘法?
- matlab预测ARMA-GARCH 条件均值和方差模型
- Web开发——PHP vs Java
- matlab ip 大端,MATLAB格式化输出控制
- java.util.zip 用法,Java压缩文件工具类ZipUtil使用方法代码示例
- 电话号码正则表达式(标准)
- 卓有成效的管理者—第二章 掌握自己的时间
- 解决谷歌地图alert出现“此页面无法正确加载 Google 地图“
- 【使用TIFF库对tif图片的读写】
- 干货丨应聘Java开发工程师的基本要求是什么?
- elasticsearch7.5.0 集群搭建
- 怎么批量在多个文件夹名称后面加上数字序号或者日期时间序号?
- 印象笔记(evernote)支持MarkDown语法