WebView使用

一、WebView

1.概述

WebView是View的子类,用于在布局中部分展现网页。常用的地方,比如购物app的商品详情页面,就可以使用WebView。

2.使用

布局:

<?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 mWebView = (WebView) findViewById(R.id.webview);
mWebView.loadUrl("https://www.baidu.com/");
注意需要网络权限。

3.使用JavaScript

JavaScript默认是不可用的,需要通过WebView的WebSettings调用setJavaScriptEnabled()方法来设置。

WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
之后可以通过addJavaScriptInterface()定义JavaScript访问Android的接口,比如启动拨号,使用Dialog等等。

public class WebAppInterface {
    Context mContext;

    WebAppInterface(Context c) {
        mContext = c;
    }

    /** 显示toast */
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}
注意:如果targetSdkVersion 为17或以上,必须使用注解@JavascriptInterface表明该接口可以被JavaScript获取。不提供就无法访问。这块主要是出于对安全的考虑。之后使用addJavaScriptInterface()添加该接口,并指定其名称。

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "android");
之后在html中使用:

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">
    function showAndroidToast(toast) {
        Android.showToast(toast);
    }
</script>
WebView会自动将接口载入。

注意:由于addJavascriptInterface会让js来控制应用,因此,安全问题很重要。所以,不要轻易链接到不安全的地址,一般不要轻易的addJavaScriptInterface()。

4.导航

WebView中的url链接,点击之后会默认的启动浏览器来打开,而不是在webView中。可以通过设置WebViewClient使其仍在WebView中打开。

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());
重写WebViewClient:

private class MyWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (Uri.parse(url).getHost().equals("www.example.com")) {
            // 让WebView加载页面
            return false;
        }
        // 否则,启动别的浏览器应用
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        startActivity(intent);
        return true;
    }
}
点击链接,系统调用shouldOverrideUrlLoading()方法,检测是是否要处理,返回false,则WebView处理,true,则选择其他应用处理。

5.导航页面历史

当webView加载多个页面时,其会保存浏览记录。通过goBack()以及goForward()进行后退和前进操作。

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    // 点击了返回键且WebView有历史记录,则可以返回
    if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
        myWebView.goBack();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

二、Android4.4中WebView变化

API19之后,新引入的WebView是基于Chromium浏览器的,使其能有更好的性能,更好的支持h5,css3,以及JavaScript。

1.用户代理

用户代理,简单说,就是浏览器给服务器提供的关于自身的信息,包括操作系统信息,浏览器信息等。如果服务内容是基于用户代理的,则用户代理字符串应为:

Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16H) AppleWebKit/537.36
(KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36
如果不需要存储UserAgent或不需要实例化WebView,可以用静态方法getDefaultUserAgent()获取用户代理,如果要重写WebView的用户代理字符串,使用getUserAgentString()获取。

2.多线程以及线程阻塞

如果在非UI线程调用WebView的方法,使用runOnUiThread()方法。同时,不要去阻塞线程,比如等待js的回调。

// This code is BAD and will block the UI thread
webView.loadUrl("javascript:fn()");
while(result == null) {
  Thread.sleep(100);
}
可以使用evaluateJavascript()异步运行js。

3.自定义URL处理

新WebView对使用自定义协议的url增加了限制。只有合法的url才会触发shouldOverrideUrlLoading()和shouldInterceptRequest()方法。如果一定要使用自定义URL或者base URL,需要确保请求的URL符合RFC 3968标准。例如:<a href="showProfile">Show Profile</a>将不会调用回调。

如果加载的页面调用loadData()或loadDataWidthBaseUrl()使用不合法或空base URL,将不会回调shouldOverrideUrlLoading()。如果一定要使用不合法或空base URL,需要指定绝对路径。

如果用loadUrl()或loadDataWithBaseURL()使用合法的Base URL加载页面,将可以收到shouldOverrideUrlLoading()回调,且获得的URL相对于当前页面是绝对路径。例如,会收到“http://www.example.com/showProfile”而不是showProfile。可以使用自定义协议来代替简单字符串,例如上面的可以改为:<a href="example-app:showProfile">Show Profile</a>。这样shouldOverrideUrlLoading()将会被回调:

// 该URL协议应该是非层次的(没有后面的斜杠/)
private static final String APP_SCHEME = "example-app:";

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.startsWith(APP_SCHEME)) {
        urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8");
        respondToData(urlData);
        return true;
    }
    return false;
}
如果不能修改HTML,可以使用loadDataWithBaseUrl()并且设置base URL,其由自定义协议,和一个有效主机组成,形如:“example-app://host/”。

例:

webView.loadDataWithBaseURL("example-app://example.co.uk/", HTML_DATA,
        null, "UTF-8", null);
有效主机名应该符合RFC 3986标准,并且最后包括尾部的/,否则可能会丢弃来自加载的页面的任何请求。

4.Viewport 变化

1)不支持target-densitydpi,建议使用图像或者css;

2)以前版本的WebView,如果Viewport宽度设置为小于或等于“320”的值,会被设为“device-width”,如果Viewport高度为小于或等于WebView高度的值将设为“device-height”。 但是,当在新的WebView中运行时,WebView会放大以填充屏幕宽度。

3)默认缩放弃用;

5.样式变化

1)background会覆盖background-size属性,重置为默认字体大小。只需要先定义background,后定义background-size即可;

2)尺寸为Css像素,而不是屏幕像素;

3)不支持NARROW_COLUMNS和SINGLE_COLUMN;

三、在JavaScript中处理TouchEvents

如果网页直接处理WebView中的TouchEvents,要确保也处理了touchcancel事件。有以下两种可能:

1.元素被触摸(touchstart和touchmove被调用),页面滚动,touchcancel被抛出;

2.元素被触摸(touchstart被调用),但没调用event.preventDefault(),从而足够早就触发了事件(WebView会假设你不想消耗触摸事件)。

四、最佳实践

1.重定向到手机专用页面;

一般是根据用户代理中确定移动页面,其可以识别是否移动端,甚至是Android版本。

2.使用适合移动端的有效标记DOCTYPE;

官方解释是,最适合的标记语言是XHTML Basic,确保移动设备有效的展现页面,比如哪些HTML框架不适用于移动端。务必给文档声明适当的字符编码,如utf-8.如:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
    "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">

3.使用Viewport元数据正确调整网页大小;

在文档的head中提供元数据,指定浏览器的Viewport如何呈现网页,例如宽高,初始网页缩放,目标屏幕密度。如:

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">

4.避免多个文件请求;

由于移动端连接速度远低于PC,所以应尽可能快地加载网页。其中一种方法就是避免在head中加载额外的文件,如css和js文件。而应该在head中直接提供样式和js,或者在body末尾提供(对于加载完之前不需要执行的脚本)。还可以使用工具来压缩文件,优化其大小和加载速度。

5.使用垂直布局;

避免浏览的网页左右滑动,要倾向于手机的用户体验。

关于移动端网页,官方推荐的几个学习资料:W3C的移动web最佳实践;其他指南和加速相关,YAhoo的指南Exceptional Performance以及谷歌的速度指南,Let's make the web faster(要翻墙).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值