WebView,在Android开发中,我们总是会遇到,它是Google封装的,使用WebKit渲染引擎加载显示网页。接下来,我们就详细看看WebView的介绍以及使用。本文是通过Android官网的文档来解释说明。(不喜欢的勿喷) 1.WebView A View that displays web pages. This class is the basis upon which you can roll your own web browser or simply display some online content within your Activity. It uses the WebKit rendering engine to display web pages and includes methods to navigate forward and backward through a history, zoom in and out, perform text searches and more. Note that, in order for your Activity to access the Internet and load web pages in a WebView, you must add the INTERNET permissions to your Android Manifest file: <uses-permission android:name="android.permission.INTERNET" /> This must be a child of the element. For more information, read Building Web Apps in WebView. 显示网页的一个View。这个类是基于在你滚动你自己的web浏览器或者在Activity总显示一些网上内容上的。它使用的是WebKit 渲染引擎来显示网页和包含浏览历史、放大和缩小、执行搜索文本等等一些方法。 需要注意的时,为了在Activity中使用网络权限和在WebView中加载网页,你必须在你的Android Manifest file.xml文件中添加使用网络的权限:... 这必须是一个子元素。 获取更多的信息,请阅读 Building Web Apps in WebView 。(需要翻墙) Basic usage By default, a WebView provides no browser-like widgets, does not enable JavaScript and web page errors are ignored. If your goal is only to display some HTML as a part of your UI, this is probably fine; the user won't need to interact with the web page beyond reading it, and the web page won't need to interact with the user. If you actually want a full-blown web browser, then you probably want to invoke the Browser application with a URL Intent rather than show it with a WebView. For example: Uri uri = Uri.parse("http://www.example.com"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); See Intent for more information. 基本使用 默认情况下,一个WebView提供的是不像浏览器的控件,没有开启JavaScript并且忽略网页错误。如果你的目的是仅仅显示一些HTML作为你的UI的一部分,那显示可能是没有问题的(显示正常),用户不需要交互的网页无法阅读,并且网页不需要和用户交互。如果你真的想要一个完整的Web浏览器,那你可能需要调用浏览器应用程序通过一个URL Intent而不是显示一个WebView,例如:... 查看 Intent 的更多信息。 To provide a WebView in your own Activity, include a <WebView> in your layout, or set the entire Activity window as a WebView during onCreate(): WebView webview = new WebView(this); setContentView(webview); Then load the desired web page: // Simplest usage: note that an exception will NOT be thrown // if there is an error loading this page (see below). webview.loadUrl("http://slashdot.org/"); // OR, you can also load from an HTML string: String summary = "<html><body>You scored <b>192</b> points.</body></html>"; webview.loadData(summary, "text/html", null); // ... although note that there are restrictions on what this HTML can do. // See the JavaDocs for loadData() and loadDataWithBaseURL() for more info.在你的Activity中提供一个WebView,可以在你的布局文件中包含<WebView>或者在Activity的onCreate()中设置窗口是一个WebView;代码如下:... 然后加载所需的网页:... A WebView has several customization points where you can add your own behavior. These are: Creating and setting a WebChromeClient subclass. This class is called when something that might impact a browser UI happens, for instance, progress updates and JavaScript alerts are sent here (see Debugging Tasks). Creating and setting a WebViewClient subclass. It will be called when things happen that impact the rendering of the content, eg, errors or form submissions. You can also intercept URL loading here (via shouldOverrideUrlLoading()). Modifying the WebSettings, such as enabling JavaScript with setJavaScriptEnabled(). Injecting Java objects into the WebView using the addJavascriptInterface (Object, String) method. This method allows you to inject Java objects into a page's JavaScript context, so that they can be accessed by JavaScript in the page. WebView有几个可以自定义的地方,你可以添加属于你自己的行为。这些有: 创建和设置一个WebChromeClient 子类。这个类被调用时,可能会影响浏览器UI的,例如,进度更新和发送JavaScript 警告(见调试任务)。 创建和设置一个WebViewClient 子类,这将被调用时对渲染内容产生影响,例如,错误或者表单提交。你可以拦截URL加载在这儿(via shouldOverrideUrlLoading())。 修改WebSettings,例如开启JavaScript 通过setJavaScriptEnabled()。 注入Java对象到WebView通过addJavascriptInterface(Object, String)方法。这个方法允许你注入一个Java对象到网页的JavaScript 的上下文,以便它们访问在页面中的JavaScript 。 Here's a more complicated example, showing error handling, settings, and progress notification: // Let's display the progress in the activity title bar, like the // browser app does. getWindow().requestFeature(Window.FEATURE_PROGRESS); webview.getSettings().setJavaScriptEnabled(true); final Activity activity = this; webview.setWebChromeClient(new WebChromeClient() { public void onProgressChanged(WebView view, int progress) { // Activities and WebViews measure progress with different scales. // The progress meter will automatically disappear when we reach 100% activity.setProgress(progress * 1000); } }); webview.setWebViewClient(new WebViewClient() { public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show(); } }); webview.loadUrl("http://developer.android.com/"); 这里有一些更复杂的例子,显示错误处理、设置和进度通知:... Zoom To enable the built-in zoom, set WebSettings.setBuiltInZoomControls(boolean) (introduced in API level CUPCAKE). NOTE: Using zoom if either the height or width is set to WRAP_CONTENT may lead to undefined behavior and should be avoided. 缩放 启用内置的缩放,需要设置WebSettings.setBuiltInZoomControls(boolean)(包含的api版本是CUPCAKE)。 注:使用缩放如果宽高都设置为WRAP_CONTENT,可能会导致不可预知的行为,所以应当避免。 Cookie and window management For obvious security reasons, your application has its own cache, cookie store etc. —it does not share the Browser application's data. By default, requests by the HTML to open new windows are ignored. This is true whether they be opened by JavaScript or by the target attribute on a link. You can customize your WebChromeClient to provide your own behaviour for opening multiple windows, and render them in whatever manner you want. The standard behavior for an Activity is to be destroyed and recreated when the device orientation or any other configuration changes. This will cause the WebView to reload the current page. If you don't want that, you can set your Activity to handle the orientation and keyboardHidden changes, and then just leave the WebView alone. It'll automatically re-orient itself as appropriate. Read Handling Runtime Changes for more information about how to handle configuration changes during runtime. Cookie 和窗口管理 出于安全的原因,你的应用程序有它的缓存、cookie 存贮等。-它不共享浏览器应用程序的数据。 默认情况下,通过HTML 请求打开一个新窗口是被忽略的,不管是通过JavaScript 打开还是通过目标属性连接,这都是对的。你可以定制你的WebChromeClient 用来提供你自己的行为为打开多个窗口,并使其以任何你想要的方式。一个Activity 的标准行为是销毁和重建当设备屏幕方向发生变化或者其他配置改变时。这将引起WebView 去重新加载当前的页面。如果你不想这样,那么你可以设置Activity 去处理orientation 和keyboardHidden 改变,仅仅留下WebView 。它会自动重定向合适的自己。读取处理运行时更改更过信息关于如何处理在运行时配置改变。 Building web pages to support different screen densities The screen density of a device is based on the screen resolution. A screen with low density has fewer available pixels per inch, where a screen with high density has more — sometimes significantly more — pixels per inch. The density of a screen is important because, other things being equal, a UI element (such as a button) whose height and width are defined in terms of screen pixels will appear larger on the lower density screen and smaller on the higher density screen. For simplicity, Android collapses all actual screen densities into three generalized densities: high, medium, and low. By default, WebView scales a web page so that it is drawn at a size that matches the default appearance on a medium density screen. So, it applies 1.5x scaling on a high density screen (because its pixels are smaller) and 0.75x scaling on a low density screen (because its pixels are bigger). Starting with API level ECLAIR, WebView supports DOM, CSS, and meta tag features to help you (as a web developer) target screens with different screen densities. 构建网页适配不同屏幕密度 一个设备的屏幕密度是基于屏幕分辨率。一个低密度的屏幕每英寸有较少的像素,一个高密度的屏幕有较多-有时候更多-每英寸的像素。一个平面的密度是很重要的,在其他的条件相同下,一个UI元素(例如一个按钮)在定义高度和宽度时,通过设置屏幕像素,在低密度的屏幕显示较大,而在高密度的屏幕显示较小。为了简单,Android 定义所有屏幕密度为三个广义的密度:高,中,低。 默认情况下,WebView 缩放一个网页是为了画一个大小匹配默认显示中等密度屏幕。因此,它适用于1.5倍比例在高密度屏幕(因为它的像素比较小),0.75倍的比例在低密度屏幕(因为它的像素较大)。从ECLAIR的API开始,WebView 支持DOM、CSS和meta 标签帮助你(作为一个网页开发者)实现屏幕适配在不同屏幕密度。 Here's a summary of the features you can use to handle different screen densities: The window.devicePixelRatio DOM property. The value of this property specifies the default scaling factor used for the current device. For example, if the value of window.devicePixelRatio is "1.0", then the device is considered a medium density (mdpi) device and default scaling is not applied to the web page; if the value is "1.5", then the device is considered a high density device (hdpi) and the page content is scaled 1.5x; if the value is "0.75", then the device is considered a low density device (ldpi) and the content is scaled 0.75x. The -webkit-device-pixel-ratio CSS media query. Use this to specify the screen densities for which this style sheet is to be used. The corresponding value should be either "0.75", "1", or "1.5", to indicate that the styles are for devices with low density, medium density, or high density screens, respectively. For example: <link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio:1.5)" href="hdpi.css" /> The hdpi.css stylesheet is only used for devices with a screen pixel ration of 1.5, which is the high density pixel ratio. 这是一个处理不同屏幕密度的功能摘要: window.devicePixelRatio DOM的属性,它的属性值用于指定当前设备的默认缩放比例。例如,window.devicePixelRatio的值是1.0,那么设备被认为是一个中密度(mdpi)设备并且默认缩放不适配与网页;如果,它的值是1.5,那么设备被认为是一个高设备(hdpi)并且网页内容放大1.5倍;如果它的值是0.75,那么设备被认为是低密度设备(ldpi)并且内容是0.75倍。 -webkit-device-pixel-ratio CSS媒体查询。使用这个来指定屏幕密度使用该样式表。相应的值是0.75,1,1.5,分别来表示设备的样式是低密度、中密度和高密度。例如:... hdpi.css 样式仅仅用于设备像素比例是1.5,是一个高密度像素比例。 HTML5 Video support In order to support inline HTML5 video in your application you need to have hardware acceleration turned on. HTML5视频支持 为了支持HTML5视频在你的应用程序中,你需要打开一个硬件加速开关。 Full screen support In order to support full screen — for video or other HTML content — you need to set a WebChromeClient and implement both onShowCustomView(View, WebChromeClient.CustomViewCallback) and onHideCustomView(). If the implementation of either of these two methods is missing then the web contents will not be allowed to enter full screen. Optionally you can implement getVideoLoadingProgressView() to customize the View displayed whilst a video is loading. 全屏支持
为了支持全屏-一个视频或者HTML 内容-你需要设置一个WebChromeClient 并且实现onShowCustomView(View, WebChromeClient.CustomViewCallback)和onHideCustomView()。如果这方法有任何一个没有实现,那么网页内容不会允许进入全屏。你也可以实现getVideoLoadingProgressView()在定义View的时候同时加载视频。 If you want to deliver a web application (or just a web page) as a part of a client application, you can do it using WebView. The WebView class is an extension of Android's View class that allows you to display web pages as a part of your activity layout. It does not include any features of a fully developed web browser, such as navigation controls or an address bar. All that WebView does, by default, is show a web page. 如果你想用一个web应用(或者一个网页)作为一个客户端应用的一部分,那么你可以使用WebView。WebView类继承了android的View,它允许你显示网页作为你的Activity布局的一部分。它不包含一个完全开发的web浏览器,例如导航栏和地址栏。所有的WebView,默认情况下,显示的都是一个网页。 A common scenario in which using WebView is helpful is when you want to provide information in your application that you might need to update, such as an end-user agreement or a user guide. Within your Android application, you can create an Activity that contains a WebView, then use that to display your document that's hosted online. 一个常见的场景,使用WebView时有用的,当你想提供在你的应用中,你可能需要更新,例如最终用户协议或者用户指南。在你的应用中,你可以创建一个Activity包含一个WebView,用它来显示你的文档在主机。 Another scenario in which WebView can help is if your application provides data to the user that always requires an Internet connection to retrieve data, such as email. In this case, you might find that it's easier to build a WebView in your Android application that shows a web page with all the user data, rather than performing a network request, then parsing the data and rendering it in an Android layout. Instead, you can design a web page that's tailored for Android devices and then implement a WebView in your Android application that loads the web page. 另为一个场景,WebView可以帮助如果你的应用提供数据为用户,那么它总是需要网络连接请求来获取数据,例如email.在这种情况下,你可能会发现在你的Android应用中建立一个WebView更容易显示网页为所有的用户数据,而不是执行一个网络请求,解析数据和渲染Android布局。相反的,你可以设计一个网页专为Android设备并且实现一个WebView在你的应用中来加载网页。 This document shows you how to get started with WebView and how to do some additional things, such as handle page navigation and bind JavaScript from your web page to client-side code in your Android application. 这篇文章显示你如何开始使用WebView,以及做一些额外的事情,例如处理网页导航和结合JavaScript从你的网页客户端代码在你的Android应用。 Adding a WebView to Your Application To add a WebView to your Application, simply include the <WebView> element in your activity layout. For example, here's a layout file in which the WebView fills the screen: <?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在你的应用 添加一个WebView在你的应用中,简单包含一个WebView元素在你的activity布局中。例如,这个布局文件的WebView充满整个屏幕。... To load a web page in the WebView, use loadUrl(). For example: WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadUrl("http://www.example.com"); 在WebView中加载一个网页,使用loadUrl()方法,例如:... Before this will work, however, your application must have access to the Internet. To get Internet access, request the INTERNET permission in your manifest file. For example: <manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest> That's all you need for a basic WebView that displays a web page. 然而,在将要工作前,你的应用必须有网络权限。为了得到网络权限,需要在你的manifest文件中有网络请求。例如:... 这是所有你需要的一个基本的WebView显示一个网页。 Using JavaScript in WebView If the web page you plan to load in your WebView use JavaScript, you must enable JavaScript for your WebView. Once JavaScript is enabled, you can also create interfaces between your application code and your JavaScript code.</span> 在WebView中使用JavaScript 如果你计划的网页加载在你的WebView要使用JavaScript,那么你必须在WebView中开启JavaScript。一旦JavaScript开启,你就可以在你的应用代码和你的JavaScript代码创建接口。 Enabling JavaScript JavaScript is disabled in a WebView by default. You can enable it through the WebSettings attached to your WebView. You can retrieve WebSettings with getSettings(), then enable JavaScript with setJavaScriptEnabled(). For example: WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true); 开启JavaScript 在WebView中JavaScript默认是禁止的。你要开启可以通过WebSettings附属在你的WebView。你可以通过getSettings()方法获取到WebSettings,通过setJavaScriptEnabled()开启JavaScript。例如:... WebSettings provides access to a variety of other settings that you might find useful. For example, if you're developing a web application that's designed specifically for the WebView in your Android application, then you can define a custom user agent string with setUserAgentString(), then query the custom user agent in your web page to verify that the client requesting your web page is actually your Android application. WebSettings 提供了大量的其他设置,你可能会使用到。例如,如果你开发一个web应用专为WebView在你的Android应用,那么你可以自定义用户代理字符串通过setUserAgentString(),然后在你的网友中查询自定义用户代理来验证客户端请求在你的网页实际上是你的Android应用。 Binding JavaScript code to Android code When developing a web application that's designed specifically for the WebView in your Android application, you can create interfaces between your JavaScript code and client-side Android code. For example, your JavaScript code can call a method in your Android code to display a Dialog, instead of using JavaScript's alert() function. 构建JavaScript代码在Android代码
如果你开发一个web应用专为WebView在你的Android应用,你可以在你的应用代码和你的JavaScript代码创建接口。例如,你的JavaScript代码能调用一个方法在你的Android To bind a new interface between your JavaScript and Android code, call addJavascriptInterface(), passing it a class instance to bind to your JavaScript and an interface name that your JavaScript can call to access the class. For example, you can include the following class in your Android application: public class WebAppInterface { Context mContext; /** Instantiate the interface and set the context */ WebAppInterface(Context c) { mContext = c; } /** Show a toast from the web page */ @JavascriptInterface public void showToast(String toast) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show(); } } Caution: If you've set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface annotation to any method that you want available to your JavaScript (the method must also be public). If you do not provide the annotation, the method is not accessible by your web page when running on Android 4.2 or higher. In this example, the WebAppInterface class allows the web page to create a Toast message, using the showToast() method. 为了绑定一个新接口在JavaScript 和Android代码,需要调用addJavascriptInterface()方法,它传递一个类的实例来绑定你的JavaScript并且接口的名字是你的JavaScript可以调用访问类。例如,在你的Android应用中包含一个下面这个类:... 注意:如果你设置你的targetSdkVersion 是17或者更高,那么你必须添加@JavascriptInterface注释在任何你想提供给你的JavaScript的方法(方法必须是公用的)。如果你不能提供这个注释,那么该方法不能访问在你的网页中当运行在Android4.2或者更高版本。这个例子,WebAppInterface类运行网页创建一个Toast消息,使用showToast()方法。 You can bind this class to the JavaScript that runs in your WebView with addJavascriptInterface() and name the interface Android. For example: WebView webView = (WebView) findViewById(R.id.webview); webView.addJavascriptInterface(new WebAppInterface(this), "Android"); This creates an interface called Android for JavaScript running in the WebView. At this point, your web application has access to the WebAppInterface class. For example, here's some HTML and JavaScript that creates a toast message using the new interface when the user clicks a button: <input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" /> <script type="text/javascript"> function showAndroidToast(toast) { Android.showToast(toast); } </script> There's no need to initialize the Android interface from JavaScript. The WebView automatically makes it available to your web page. So, at the click of the button, the showAndroidToast() function uses the Android interface to call the WebAppInterface.showToast() method. Note: The object that is bound to your JavaScript runs in another thread and not in the thread in which it was constructed. Caution: Using addJavascriptInterface() allows JavaScript to control your Android application. This can be a very useful feature or a dangerous security issue. When the HTML in the WebView is untrustworthy (for example, part or all of the HTML is provided by an unknown person or process), then an attacker can include HTML that executes your client-side code and possibly any code of the attacker's choosing. As such, you should not use addJavascriptInterface() unless you wrote all of the HTML and JavaScript that appears in your WebView. You should also not allow the user to navigate to other web pages that are not your own, within your WebView (instead, allow the user's default browser application to open foreign links—by default, the user's web browser opens all URL links, so be careful only if you handle page navigation as described in the following section). 你可以绑定这个类的JavaScript在运行你的WebView通过addJavascriptInterface()和接口名称是Android。例如,... 这个创建了一个接口调用Android的JavaScript运行WebView时,在这一点上,你的web应用可以访问WebAppInterface 类。例如,下面是一些HTML 和 JavaScript在创建一个toast消息使用新接口当用户点击按钮:... 这里没有必要初始化Android的JavaScript接口。WebView自动编译时你的网页可以使用。因此,在点击按钮的时候,showAndroidToast()方法使用Android接口去调用WebAppInterface.showToast()方法。 注:对象绑定在你的JavaScript 运行在另外的一个线程,不是一个构建的线程。
警告:使用addJavascriptInterface()方法运行JavaScript来控制你的Android应用。这可能是一个非常有用的功能或者一个危险的安全问题。当WebView的HTML是一个不可信赖的(例如,HTML的一部分或者全部的提供者是一个不可知的人或者进程),然后,攻击者可以包含HTML去执行你的客户端一边的代码和攻击者选择的任何代码 Handling Page Navigation When the user clicks a link from a web page in your WebView, the default behavior is for Android to launch an application that handles URLs. Usually, the default web browser opens and loads the destination URL. However, you can override this behavior for your WebView, so links open within your WebView. You can then allow the user to navigate backward and forward through their web page history that's maintained by your WebView. To open links clicked by the user, simply provide a WebViewClient for your WebView, using setWebViewClient(). For example: WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new WebViewClient()); That's it. Now all links the user clicks load in your WebView. If you want more control over where a clicked link load, create your own WebViewClient that overrides the shouldOverrideUrlLoading() method. For example: private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (Uri.parse(url).getHost().equals("www.example.com")) { // This is my web site, so do not override; let my WebView load the page return false; } // Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(intent); return true; } } Then create an instance of this new WebViewClient for the WebView: WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new MyWebViewClient()); Now when the user clicks a link, the system calls shouldOverrideUrlLoading(), which checks whether the URL host matches a specific domain (as defined above). If it does match, then the method returns false in order to not override the URL loading (it allows the WebView to load the URL as usual). If the URL host does not match, then an Intent is created to launch the default Activity for handling URLs (which resolves to the user's default web browser). 页面导航处理 当用户从网页上点击一个连接在你的WebView,默认行为,Android会启动一个应用去处理这个URLs。然而,你可以重新这个方法,使连接通过你的WebView打开。你可以允许用户向前或者向后浏览保存在你的WebView中历史。
用户打开连接,只是提供一个WebViewClient在你的WebView,使用setWebViewClient()。例如:... 如果你想要更多的控制点击连接加载,那么创建你自己的WebViewClient,并重写shouldOverrideUrlLoading()方法,例如:... 在WebView创建WebViewClient 实例:... 现在当用户点击连接时,系统调用shouldOverrideUrlLoading(),校验 URL主机是否能够匹配一个特定的域( 如上所述 )。如果它不匹配,那么方法返回false,为了不重新 URL加载(允许WebView像通常一样加载 URL )。如果URL 主机不匹配,那么将创建一个Intent 来启动默认的Activity来处理URLs(该用户的默认web浏览器)。 Navigating web page history When your WebView overrides URL loading, it automatically accumulates a history of visited web pages. You can navigate backward and forward through the history with goBack() and goForward(). For example, here's how your Activity can use the device Back button to navigate backward: @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // Check if the key event was the Back button and if there's history if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) { myWebView.goBack(); return true; } // If it wasn't the Back key or there's no web page history, bubble up to the default // system behavior (probably exit the activity) return super.onKeyDown(keyCode, event); } The canGoBack() method returns true if there is actually web page history for the user to visit. Likewise, you can use canGoForward() to check whether there is a forward history. If you don't perform this check, then once the user reaches the end of the history, goBack() or goForward() does nothing. 网页导航历史 当你的WebView重写URL加载,它会自动累积浏览历史。你可以向后或者向前导航历史通过goBack()和goForward()。 例如,这是如何在你的Activity中使用设备硬件返回按钮去导航返回:... canGoBack()这个方法true,如果用户浏览网页历史。同样,你可以使用canGoForward()检查是否有一个向前的历史。如果你执行这个检查,一旦用户达到历史结尾,那么goBack() 和goForward()就没什么用。 (责任编辑:好模板) |