背景
经过这么多的发展,目前的android应用开发模式已经有了很多的改变,除了有原来的原生应用开发模式,随着Html5等前端技术的进步,也催生了多种开
发模式。比如说目前非常火爆的native+web混合模式,其实就是在开发某个页面的时候,经常会更改,我们就可以使用网页的形式将页面的内容展示,应
用使用网页进行交互。本质上来说,还是内嵌了一个网页。
这种做法有什么优势呢?
1 开发方便,网页开发的成本要比原生开发应用的成本低
2 发布方便,如果我们的app上线后,我们有了新的业务需求,开发完成后,我们只能更新客户端或者使用热修复等技术,但是使用web的方式开
发的页面,直接将新的页面放上线上即可。
有优势的同时肯定也有劣势:
1 用户体验差,由于目前的前端技术暂时无法和原生的应用相比,所以开发出来的页面与原生的页面还是有差距
2 流量使用的多。
适合的场景:
1 信息展示的页面。Html+css提供了强大的排版能力,能够很方便的开发出需要的页面。
2 电商行业的活动页面。因为经常性的更改,网页的灵活性非常适合这种情况。
基本使用
布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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="com.junx.x5webview.WebViewActivity">
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="300dp" android:layout_marginLeft="8dp"
android:layout_marginRight="8dp" android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="0.352"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
代码:
public class MainActivity extends AppCompatActivity {
private WebView wv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
setWebView();
}
private void initView() {
wv = (WebView) findViewById(R.id.wv);
}
private void setWebView() {
WebSettings webSettings = wv.getSettings();
//设置WebView属性,能够执行Javascript脚本
webSettings.setJavaScriptEnabled(true);
//设置可以访问文件
webSettings.setAllowFileAccess(true);
//设置支持缩放
webSettings.setBuiltInZoomControls(true);
//加载需要显示的网页
wv.loadUrl("http://www.baidu.com");
//设置Web视图,不设置的话点击跳转网页则会打开默认浏览器
wv.setWebViewClient(new WebViewClient());
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && wv.canGoBack()) {
wv.goBack(); //goBack()表示返回WebView的上一页面
return true;
}
finish();//结束退出程序
return false;
}
}
请记得添加网络权限
assets目录详解
创建assets目录:
在android视图下,选中整个module,右键>new>folder>assets folder
与res的区别:
在开发android应用的过程中,需要使用大量的资源文件,如果我们放置在res文件下,它会生成一个独立的id,而在assets文件夹下不会
如果我们需要获取assets的文件,我们可以使用getAssets().open打开一个文件。
加载assets目录下的文件的demo:
private String getAssetsHtml(){
StringBuilder builder=new StringBuilder();
InputStream inputStream=null;
InputStreamReader reader=null;
BufferedReader bufferedReader=null;
try {
inputStream=getAssets().open("Image.html");
reader=new InputStreamReader(inputStream);
bufferedReader=new BufferedReader(reader);
String cache ;
while((cache = bufferedReader.readLine())!=null){
builder.append(cache);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (inputStream!=null)
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (reader!=null)
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
if (bufferedReader!=null)
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return builder.toString();
}
加载本地网页
使用电脑的浏览器,随便打开一个网页 ctrl+S,保存为html格式,复制到assets目录下
//通过file:///android_asset/文件名,加载网页 注意是asset而不是assets
wv.loadUrl("file:///android_asset/xxx.html");
加载动态网页
<html>
<head lang="en">
<title></title>
<h3>android,中文支持</h3>
</style>
</head>
<body>
</body>
<img class="image" src="https://ss0.bdstatic.com
/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png">
</html>
将上述创建为一个字符串htmlString
加载字符串网页
//如果网页中有中文的话可能会乱码
wv.loadData(assetsHtml,"text/html,"UTF-8");
//设置文字的编码格式,方式乱码
wv.loadData(assetsHtml,"text/html;charset=UTF-8","UTF-8");
相对路径
将图片中的路径
<img class="image" src="https://ss0.bdstatic.com
/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png">
改为
<img class="image" src="
/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png">
改变后的路径是相对路径
那么,该如何加载相对路径的图片呢
//最后一个参数是历史url,如果为null当点击打开其他网页并返回时就为空白页面
wv.loadDataWithBaseURL("https://ss0.bdstatic.com",assetsHtml,"text/html;charset=UTF-8","UTF-8",null);
webview的事件监听
wv.setWebViewClient(new WebViewClient(){
//网页加载各种资源的回调,比如你的网页使用了各种图片和css与js文件
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
}
//开始加载网页
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
showProgress();
}
//加载网页完成
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
hideProgress();
Log.v("meee",getClass()+":\n"+"加载完成");
}
//加载页面出错时的回调 api6.0以上
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
hideProgress();
//加载自己的错误页面
//wv.loadUrl("file:///android_asset/error.html");
}
//5.1以下时错误的回调
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
hideProgress();
}
//在这里处理网页内部的跳转
//1.当没有设webclient时,跳转到默认浏览器
//2.return true,url被拦截,webview也不处理跳转,需要自己进行loadurl
//3.return false,webview自行处理,同super
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return super.shouldOverrideUrlLoading(view, request);
}
});
WebView参数的设置
private void setSetting(WebView webView){
WebSettings settings = webView.getSettings();
//是否允许使用file协议访问网页,默认true
settings.setAllowFileAccess(true);
//是否开始缩放功能
settings.setBuiltInZoomControls(false);
//设置页面字体的大小
settings.setDefaultFontSize(30);
//是否开启js支持
settings.setJavaScriptEnabled(true);
//是否开启两种数据库的支持
/*html5支持数据库的功能,数据库有两种第一种官方的规范,DOM Storage,另外一种是第三方api ,Web SQL Database。我们先来讲讲这两种数
据库存储方式。对于以前来说,一个Web应用要存储数据,大多会放置cookie中,但是cookie有一个限制,就是内容只能4K,且容易被篡改。所以
在Html5内增加存储的概念,这个就是DOM Storage,DOM Storage 分为 sessionStorage 和 localStorage。 localStorage 对象和 sessionStorage
对象使用方法基本相同,它们的区别在于作用的范围不同。sessionStorage 用来存储与页面相关的数据,它在页面关闭后无法使用。而
localStorage 则持久存在,在页面关闭后也可以使用。*/
settings.setDatabaseEnabled(true);
settings.setDomStorageEnabled(true);
//设置返回键时缓存的处理
/*LOAD_DEFAULT(先从cache加载,没有且没有过期,再去网络加载),
LOAD_CACHE_ELSE_NETWORK(先从cache加载,如果存在,不管有没有过期,都不会再去网络加载)
, LOAD_NO_CACHE(不使用cache)
,LOAD_CACHE_ONLY(只使用cache)*/
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
}
WebView的基本使用
a.加载网页
wv.load("url");
//加载本地网页
wv.loadUrl("file:///android_asset/my.html");//asset目录下,my.html
asset放在main目录下
//调用js
wv.getSettings().setJavaScriptEnabled(true); //开启js
webView.loadUrl("javascript:go()"); //调用js中的go();
//直接调用html代码
String data="<html><head></head><body>你好啊</body></html>";
wv.loadDataWithBaseURL(null,data,null,"utf-8",null);
//F5
wv.reload();
//后退
wv.canGoBack();
wv.goBack();
WebViewClient //WebView的辅助类,主要用于对WebView的监听
- onLoadResource:加载网页中的各种资源(比如:图片、css)时的回调
- onPageStarted:网页开始加载时的回调
- onPageFinished:网页结束加载时的回调
- onReceiverdError:网页加载失败时的回调
- shouldOverrideUrlLoading(WebView view, String url)//处理网页内部的跳转,比如请求www.bbbb.com,网页会请求到其他的页面,此时通过该方法就能进行处理。url的是过时的方法,但主要使用的也是它;return true离开页面并处理自身的url,false只做监听不做跳转
- shouldInterceptRequest(WebView view, String url/*资源的url*/):拦截网页中的请求。//return 就是返回的数据.思路:对url进行判断,对需要拦截的请求返回自定义的WebResourceResponse
WebChromeClient //主要用与页面交互
//js 的confirm
function display_confirm()
{
var r=confirm("Press a button")
if (r==true)
{
document.write("You pressed OK!")
}
else
{
document.write("You pressed Cancel!")
}
}
//js 的prompt
function display_prompt()
{
var name=prompt("请输入你的名字","老司机")
if (name!=null && name!="")
{
document.write("Hello " + name + "!")
}
}
//js 的页面跳转
function go()
{
window.location = "api://userId";
}
//js java调用
function jsCallJava()
{
window.demo.startPage();
}
wv.setWebChromeClient(new WebChromeClient(){
//js中对alert方法进行监听
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
uu(message);//log对话框中的信息
return super.onJsAlert(view, url, message, result);
}
//确认框监听
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
//prompt :进阶的输入框
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
return super.onJsPrompt(view, url, message, defaultValue, result);
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
}
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
}
});
WebSetting
//获取Setting的方法
wv.getSettings();
//设置是否开启网页的JS
setting.setJavaScriptEnabled(boolean flag):设置是否执行页面中的js方法
//是否需要是否允许访问file文件
setting.setAllowFileAccess(boolean allow);常用于访问assets和raw文件夹下面的网页
//设置是否使用webView自带的缩放功能
setting.setBuiltInZoomControls(boolean enabled);
//设置页面的文字大小
setting.setDefaultFontSize(int size)
//
setting.setCacheMode(int);
LOAD_DEFAULT(只有缓存不存在或者已经过期时才会从网络加载)
LOAD_CACHE_ELSE_NETWORK(不论缓存是否过期,只有缓存不存在时才会从网络加载)
LOAD_CACHE_ONLY
- setBuiltInZoomControls(boolean enabled):
Java页面交互
//通过控制跳转的方式来实现java页面交互
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("http:")) {
} else if (url.startsWith("data")) {
//todo 开启一个新的页面
}
return true;//true不能加载网页
}
//在html中调用java方法
@JavascriptInterface
test();//在某一个类中具有的方法,需要添加注解@JavascriptInterface
//在java中关联html
wv.addJavaScriptInterface(MainActivity.this/*方法的实例*/,"instance"/*该类的昵称*/);instance
//在html中添加方法 window.传入的类的昵称.方法();
function callJava()
{
window.instance.toast();
}
List 并没有实现seriable,所以