使用 WebView
提供 Web 应用
或网页作为客户端应用的一部分。WebView
类是一个
Android View
类的扩展,可让
您将网页作为 activity 布局的一部分显示。不包含
功能完善的网络浏览器的功能,如导航控件或
地址栏。默认情况下,所有 WebView
均会显示网页。
WebView
可以帮助您在应用中提供完成以下操作所需的信息
例如最终用户协议或用户指南。在 Android 应用中
您可以创建一个 Activity
,并在其中包含
WebView
,然后使用它来显示在线托管的文档。
WebView
应用还会向用户提供需要
以检索电子邮件等数据。在这种情况下,您可以
发现在 Android 应用中构建 WebView
来显示网站
而不是执行网络请求
解析数据并在 Android 布局中呈现这些数据。您可以改为设计
专门为采用 Android 的设备打造的网页,然后实现
在用于加载网页的 Android 应用中设置 WebView
。
本文档介绍了如何开始使用 WebView
,以及如何在
将 JavaScript 从您的网页中传递到 Android 应用中的客户端代码,如何
处理页面导航,以及如何在使用 WebView
时管理窗口。
在早期版本的 Android 上使用 WebView
若要在您的应用设备上安全地使用较新的 WebView
功能
请添加 AndroidX
Webkit 库。这是一个静态
库,您可以使用android.webkit
适用于早期平台版本。
将其添加到 build.gradle
文件中,如下所示:
Kotlin
dependencies { implementation("androidx.webkit:webkit:1.8.0") }
Groovy
dependencies { implementation ("androidx.webkit:webkit:1.8.0") }
探索WebView
示例
。
向应用添加 WebView
如需向应用添加 WebView
,您可以在<WebView>
活动布局,或者将整个Activity
窗口设置为WebView
onCreate()
。
在 activity 布局中添加 WebView
如需在布局中向应用添加 WebView
,请将以下代码添加到
activity 的布局 XML 文件:
<WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" />
如需在 WebView
中加载网页,请使用
loadUrl()
,采用
如以下示例中所示:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.loadUrl("http://www.example.com")
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadUrl("http://www.example.com");
在 onCreate() 中添加 WebView
如需在 activity 的 onCreate()
方法中向应用添加 WebView
,请改用
逻辑类似于:
Kotlin
val myWebView = WebView(activityContext) setContentView(myWebView)
Java
WebView myWebView = new WebView(activityContext); setContentView(myWebView);
然后加载页面:
Kotlin
myWebView.loadUrl("http://www.example.com")
Java
myWebView.loadUrl("https://www.example.com");
或者通过 HTML 字符串加载网址:
Kotlin
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. val unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; val encodedHtml = Base64.encodeToString(unencodedHtml.toByteArray(), Base64.NO_PADDING) myWebView.loadData(encodedHtml, "text/html", "base64")
Java
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. String unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(), Base64.NO_PADDING); myWebView.loadData(encodedHtml, "text/html", "base64");
您的应用必须能够访问互联网。要获取互联网访问权限,请
INTERNET
权限
清单文件,如以下示例所示:
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
您可以通过执行以下任一操作来自定义 WebView
:
- 使用以下代码启用全屏支持
WebChromeClient
。此课程 当WebView
需要相应权限才能更改托管应用的界面时,也会调用此方法。 例如创建或关闭窗口,或者将 JavaScript 对话框发送到 用户。如要详细了解如何在上述情况下进行调试,请参阅调试网站 应用。 - 处理影响内容呈现的事件,例如表单错误
提交或导航
WebViewClient
。您还可以使用 来拦截网址加载。 - 通过修改来启用 JavaScript
WebSettings
。 - 使用 JavaScript 访问已注入的 Android 框架对象
转换为
WebView
。
在 WebView 中使用 JavaScript
如果您要在 WebView
中加载的网页使用 JavaScript,则必须
为 WebView
启用 JavaScript。启用 JavaScript 后,您可以执行以下操作:
在应用代码和 JavaScript 代码之间创建接口。
启用 JavaScript
JavaScript 在 WebView
中默认处于停用状态。您可以通过
WebSettings
已附加到您的WebView
。使用以下字段检索 WebSettings
:
getSettings()
,然后启用
JavaScript 与
setJavaScriptEnabled()
。
请参阅以下示例:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.settings.javaScriptEnabled = true
Java
WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true);
您可以通过WebSettings
访问其他各种设置
实用。例如,如果您要开发一款
WebView
,则您可以定义一个自定义
用户代理字符串中,
setUserAgentString()
,
然后在您的网页中查询自定义用户代理,以验证客户端
就是您的 Android 应用
将 JavaScript 代码绑定到 Android 代码
在开发专为 WebView
设计的 Web 应用时
可以在您的 JavaScript 代码与
客户端 Android 代码例如,您的 JavaScript 代码可以调用
您的 Android 代码以显示 Dialog
,
而不是使用 JavaScript 的 alert()
函数。
要在 JavaScript 和 Android 代码之间绑定新接口,请调用
addJavascriptInterface()
、
向其传递一个类实例以绑定到您的 JavaScript 和一个接口名称
即可访问该类
例如,您可以在 Android 应用中包含以下类:
Kotlin
/** Instantiate the interface and set the context. */ class WebAppInterface(private val mContext: Context) { /** Show a toast from the web page. */ @JavascriptInterface fun showToast(toast: String) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show() } }
Java
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(); } }
在此示例中,WebAppInterface
类允许网页创建
Toast
消息,使用 showToast()
方法。
您可以使用以下代码将此类绑定到在 WebView
中运行的 JavaScript。
addJavascriptInterface()
,如以下示例所示:
Kotlin
val webView: WebView = findViewById(R.id.webview) webView.addJavascriptInterface(WebAppInterface(this), "Android")
Java
WebView webView = (WebView) findViewById(R.id.webview); webView.addJavascriptInterface(new WebAppInterface(this), "Android");
这将创建一个名为 Android
的接口,用于在
WebView
。此时,您的 Web 应用可以访问
WebAppInterface
类。例如,以下是一些
在用户点按按钮时,使用新界面创建消息框消息:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" /> <script type="text/javascript"> function showAndroidToast(toast) { Android.showToast(toast); } </script>
无需从 JavaScript 初始化 Android
接口。通过
WebView
会自动将其提供给您的网页。因此,当用户
点按按钮,showAndroidToast()
函数使用 Android
界面
调用 WebAppInterface.showToast()
方法。
处理网页导航
默认情况下,当用户在 WebView
中点按网页中的链接时
启动处理网址的应用。通常情况下,默认网络浏览器会打开并
加载目标网址。不过,您可以替换此行为,
WebView
,以便在您的 WebView
中打开链接。然后,您可以让用户
向后和向前浏览保留的网页历史记录
由您的WebView
提供。
如需打开用户点按的链接,请为您的 WebView
提供 WebViewClient
使用
setWebViewClient()
。
用户点按的所有链接都会加载到您的 WebView
中。如果您想进一步掌控
用于加载所点击的链接的位置,请创建您自己的 WebViewClient
以替换
shouldOverrideUrlLoading()
方法。以下示例假定 MyWebViewClient
是一个内部类
共 Activity
个。
Kotlin
private class MyWebViewClient : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { if (Uri.parse(url).host == "www.example.com") { // This is your website, so don't override. Let your WebView load // the page. return false } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply { startActivity(this) } return true } }
Java
private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { if ("www.example.com".equals(request.getUrl().getHost())) { // This is your website, so don't override. Let your WebView load the // page. return false; } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl()); startActivity(intent); return true; } }
然后,为 WebView
创建这一新 WebViewClient
的实例:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.webViewClient = MyWebViewClient()
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new MyWebViewClient());
现在,当用户点按链接时,系统会调用
shouldOverrideUrlLoading()
方法,用于检查网址主机是否匹配
特定域,如前面的示例中所定义。如果匹配,那么
该方法会返回 false,并且不会替换网址加载。它让
WebView
会照常加载网址。如果网址主机不匹配,那么
创建 Intent
以启动默认
Activity
用于处理网址,它会解析为用户的默认网络浏览器。
处理自定义网址
WebView
在请求资源和解析链接时应用限制
使用自定义网址架构的广告例如,如果您实现了
shouldOverrideUrlLoading()
或
shouldInterceptRequest()
,
然后,WebView
仅针对有效网址调用这些方法。
例如,WebView
可能不会调用您的 shouldOverrideUrlLoading()
方法
链接:
<a href="showProfile">Show Profile</a>
系统会处理无效网址(如上例所示的网址)
在 WebView
中会不一致,因此我们建议您改用格式正确的网址。
您可以为贵组织的某个网域使用自定义架构或 HTTPS 网址
控件。
与上例中那样,您可以在链接中使用简单的字符串, 使用自定义架构,如下所示:
<a href="example-app:showProfile">Show Profile</a>
然后,您可以在 shouldOverrideUrlLoading()
方法中处理此网址,例如
:
Kotlin
// The URL scheme must be non-hierarchical, meaning no trailing slashes. const val APP_SCHEME = "example-app:" override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { return if (url?.startsWith(APP_SCHEME) == true) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length), "UTF-8") respondToData(urlData) true } else { false } }
Java
// The URL scheme must be non-hierarchical, meaning no trailing slashes. 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; }
shouldOverrideUrlLoading()
API 主要用于启动 intent
。实现它时,请确保针对网址返回 false
WebView
句柄。不过,您并不仅限于启动 intent。您可以
将启动 intent 替换为上述代码中的任何自定义行为
示例。
浏览网页历史记录
当您的 WebView
替换网址加载时,它会自动累积
来记录所访问网页的历史记录您可以通过
与goBack()
和
goForward()
。
例如,以下代码展示了您的 Activity
如何使用设备“返回”
按钮向后导航:
Kotlin
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { // Check whether the key event is the Back button and if there's history. if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) { myWebView.goBack() return true } // If it isn't the Back button or there isn't web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event) }
Java
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { // Check whether the key event is the Back button and if there's history. if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) { myWebView.goBack(); return true; } // If it isn't the Back button or there's no web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event); }
如果您的应用使用 AndroidX AppCompat
1.6.0+,则可以简化之前的
片段:
Kotlin
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack() } }
Java
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack(); } }
canGoBack()
方法
若有用户访问的网页历史记录,则返回 true。同样
可以使用canGoForward()
执行以下操作:
检查是否存在向前历史记录。如果您不执行此检查,则
在用户浏览完历史记录后,goBack()
和 goForward()
会执行相应操作
什么都不用做。
处理设备配置更改
在运行时,当设备配置时,会发生 activity 状态变化
更改,例如当用户旋转设备或关闭输入法编辑器时
(IME)。这些更改会导致 WebView
对象的 activity 被销毁,并且
要创建的新 activity,这也会创建一个新的 WebView
对象,用于加载
已销毁对象的网址。如需修改 activity 的默认行为,您可以
更改它处理清单中 orientation
更改的方式。了解详情
有关在运行时处理配置更改的信息,请阅读处理配置
更改。
管理窗口
默认情况下,系统会忽略打开新窗口的请求。无论他们身在何处
由 JavaScript 或链接中的 target 属性打开。你可以自定义
您的 WebChromeClient
,以提供您自己的行为来打开多个
窗口。
为了提高应用的安全性,最好阻止弹出式窗口和新窗口
。实现此行为的最安全方法是将 "true"
传入
setSupportMultipleWindows()
但不会覆盖
onCreateWindow()
方法,后者是 setSupportMultipleWindows()
所依赖的。此逻辑可防止
链接中使用了 target="_blank"
的网页加载。