Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 1 | page.title=Building Web Apps in WebView |
| 2 | @jd:body |
| 3 | |
| 4 | <div id="qv-wrapper"> |
| 5 | <div id="qv"> |
| 6 | <h2>Quickview</h2> |
| 7 | <ul> |
| 8 | <li>Use {@link android.webkit.WebView} to display web pages in your Android application |
| 9 | layout</li> |
| 10 | <li>You can create interfaces from your JavaScript to your client-side Android code</li> |
| 11 | </ul> |
| 12 | |
| 13 | <h2>In this document</h2> |
| 14 | <ol> |
| 15 | <li><a href="#AddingWebView">Adding a WebView to Your Application</a></li> |
| 16 | <li><a href="#UsingJavaScript">Using JavaScript in WebView</a> |
| 17 | <ol> |
| 18 | <li><a href="#EnablingJavaScript">Enabling JavaScript</a></li> |
| 19 | <li><a href="#BindingJavaScript">Binding JavaScript code to Android code</a></li> |
| 20 | </ol> |
| 21 | </li> |
| 22 | <li><a href="#HandlingNavigation">Handling Page Navigation</a> |
| 23 | <ol> |
| 24 | <li><a href="#NavigatingHistory">Navigating web page history</a></li> |
| 25 | </ol> |
| 26 | </li> |
| 27 | </ol> |
| 28 | |
| 29 | <h2>Key classes</h2> |
| 30 | <ol> |
| 31 | <li>{@link android.webkit.WebView}</li> |
| 32 | <li>{@link android.webkit.WebSettings}</li> |
| 33 | <li>{@link android.webkit.WebViewClient}</li> |
| 34 | </ol> |
| 35 | |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 36 | </div> |
| 37 | </div> |
| 38 | |
| 39 | <p>If you want to deliver a web application (or just a web page) as a part of a client application, |
| 40 | you can do it using {@link android.webkit.WebView}. The {@link android.webkit.WebView} class is an |
| 41 | extension of Android's {@link android.view.View} class that allows you to display web pages as a |
| 42 | part of your activity layout. It does <em>not</em> include any features of a fully developed web |
| 43 | browser, such as navigation controls or an address bar. All that {@link android.webkit.WebView} |
| 44 | does, by default, is show a web page.</p> |
| 45 | |
| 46 | <p>A common scenario in which using {@link android.webkit.WebView} is helpful is when you want to |
| 47 | provide information in your application that you might need to update, such as an end-user agreement |
| 48 | or a user guide. Within your Android application, you can create an {@link android.app.Activity} |
| 49 | that contains a {@link android.webkit.WebView}, then use that to display your document that's |
| 50 | hosted online.</p> |
| 51 | |
| 52 | <p>Another scenario in which {@link android.webkit.WebView} can help is if your application provides |
| 53 | data to the user that |
| 54 | always requires an Internet connection to retrieve data, such as email. In this case, you might |
| 55 | find that it's easier to build a {@link android.webkit.WebView} in your Android application that |
| 56 | shows a web page with all |
| 57 | the user data, rather than performing a network request, then parsing the data and rendering it in |
| 58 | an Android layout. Instead, you can design a web page that's tailored for Android devices |
| 59 | and then implement a {@link android.webkit.WebView} in your Android application that loads the web |
| 60 | page.</p> |
| 61 | |
| 62 | <p>This document shows you how to get started with {@link android.webkit.WebView} and how to do some |
| 63 | additional things, such as handle page navigation and bind JavaScript from your web page to |
| 64 | client-side code in your Android application.</p> |
| 65 | |
| 66 | |
| 67 | |
| 68 | <h2 id="AddingWebView">Adding a WebView to Your Application</h2> |
| 69 | |
| 70 | <p>To add a {@link android.webkit.WebView} to your Application, simply include the {@code |
| 71 | <WebView>} element in your activity layout. For example, here's a layout file in which the |
| 72 | {@link android.webkit.WebView} fills the screen:</p> |
| 73 | |
| 74 | <pre> |
| 75 | <?xml version="1.0" encoding="utf-8"?> |
| 76 | <WebView xmlns:android="http://schemas.android.com/apk/res/android" |
| 77 | android:id="@+id/webview" |
| 78 | android:layout_width="fill_parent" |
| 79 | android:layout_height="fill_parent" |
| 80 | /> |
| 81 | </pre> |
| 82 | |
| 83 | <p>To load a web page in the {@link android.webkit.WebView}, use {@link |
| 84 | android.webkit.WebView#loadUrl(String) loadUrl()}. For example:</p> |
| 85 | |
| 86 | <pre> |
| 87 | WebView myWebView = (WebView) findViewById(R.id.webview); |
| 88 | myWebView.loadUrl("http://www.example.com"); |
| 89 | </pre> |
| 90 | |
| 91 | <p>Before this will work, however, your application must have access to the Internet. To get |
| 92 | Internet access, request the {@link android.Manifest.permission#INTERNET} permission in your |
| 93 | manifest file. For example:</p> |
| 94 | |
| 95 | <pre> |
| 96 | <manifest ... > |
| 97 | <uses-permission android:name="android.permission.INTERNET" /> |
| 98 | ... |
| 99 | </manifest> |
| 100 | </pre> |
| 101 | |
| 102 | <p>That's all you need for a basic {@link android.webkit.WebView} that displays a web page.</p> |
| 103 | |
| 104 | |
| 105 | |
| 106 | |
| 107 | <h2 id="UsingJavaScript">Using JavaScript in WebView</h2> |
| 108 | |
| 109 | <p>If the web page you plan to load in your {@link android.webkit.WebView} use JavaScript, you |
| 110 | must enable JavaScript for your {@link android.webkit.WebView}. Once JavaScript is enabled, you can |
| 111 | also create interfaces between your application code and your JavaScript code.</p> |
| 112 | |
| 113 | |
| 114 | <h3 id="EnablingJavaScript">Enabling JavaScript</h3> |
| 115 | |
| 116 | <p>JavaScript is disabled in a {@link android.webkit.WebView} by default. You can enable it |
| 117 | through the {@link |
| 118 | android.webkit.WebSettings} attached to your {@link android.webkit.WebView}. You can retrieve {@link |
| 119 | android.webkit.WebSettings} with {@link android.webkit.WebView#getSettings()}, then enable |
| 120 | JavaScript with {@link android.webkit.WebSettings#setJavaScriptEnabled(boolean) |
| 121 | setJavaScriptEnabled()}.</p> |
| 122 | |
| 123 | <p>For example:</p> |
| 124 | |
| 125 | <pre> |
| 126 | WebView myWebView = (WebView) findViewById(R.id.webview); |
| 127 | WebSettings webSettings = myWebView.getSettings(); |
| 128 | webSettings.setJavaScriptEnabled(true); |
| 129 | </pre> |
| 130 | |
| 131 | <p>{@link android.webkit.WebSettings} provides access to a variety of other settings that you might |
| 132 | find useful. For example, if you're developing a web application |
| 133 | that's designed specifically for the {@link android.webkit.WebView} in your Android application, |
| 134 | then you can define a |
| 135 | custom user agent string with {@link android.webkit.WebSettings#setUserAgentString(String) |
| 136 | setUserAgentString()}, then query the custom user agent in your web page to verify that the |
| 137 | client requesting your web page is actually your Android application.</p> |
| 138 | |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 139 | <h3 id="BindingJavaScript">Binding JavaScript code to Android code</h3> |
| 140 | |
| 141 | <p>When developing a web application that's designed specifically for the {@link |
| 142 | android.webkit.WebView} in your Android |
| 143 | application, you can create interfaces between your JavaScript code and client-side Android code. |
| 144 | For example, your JavaScript code can call a method in your Android code to display a {@link |
| 145 | android.app.Dialog}, instead of using JavaScript's {@code alert()} function.</p> |
| 146 | |
| 147 | <p>To bind a new interface between your JavaScript and Android code, call {@link |
| 148 | android.webkit.WebView#addJavascriptInterface(Object,String) addJavascriptInterface()}, passing it |
| 149 | a class instance to bind to your JavaScript and an interface name that your JavaScript can call to |
| 150 | access the class.</p> |
| 151 | |
| 152 | <p>For example, you can include the following class in your Android application:</p> |
| 153 | |
| 154 | <pre> |
Scott Main | cc91d6b | 2012-11-05 11:21:38 -0800 | [diff] [blame] | 155 | public class WebAppInterface { |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 156 | Context mContext; |
| 157 | |
| 158 | /** Instantiate the interface and set the context */ |
Scott Main | dc2c1a0 | 2012-12-18 16:07:36 -0800 | [diff] [blame] | 159 | WebAppInterface(Context c) { |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 160 | mContext = c; |
| 161 | } |
| 162 | |
| 163 | /** Show a toast from the web page */ |
Scott Main | cc91d6b | 2012-11-05 11:21:38 -0800 | [diff] [blame] | 164 | @JavascriptInterface |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 165 | public void showToast(String toast) { |
| 166 | Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show(); |
| 167 | } |
| 168 | } |
| 169 | </pre> |
| 170 | |
Scott Main | 40f7a51 | 2012-12-05 12:25:42 -0800 | [diff] [blame] | 171 | <p class="caution"><strong>Caution:</strong> If you've set your <a |
Scott Main | cc91d6b | 2012-11-05 11:21:38 -0800 | [diff] [blame] | 172 | href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a> |
| 173 | to 17 or higher, <strong>you |
| 174 | must add the {@code @JavascriptInterface} annotation</strong> to any method that you want |
Scott Main | 488c81a | 2013-02-20 15:32:30 -0800 | [diff] [blame] | 175 | available to your JavaScript (the method must also be public). If you do not provide the |
| 176 | annotation, the method is not accessible by your web page when running on Android 4.2 or |
Scott Main | cc91d6b | 2012-11-05 11:21:38 -0800 | [diff] [blame] | 177 | higher.</p> |
| 178 | |
| 179 | <p>In this example, the {@code WebAppInterface} class allows the web page to create a {@link |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 180 | android.widget.Toast} message, using the {@code showToast()} method.</p> |
| 181 | |
| 182 | <p>You can bind this class to the JavaScript that runs in your {@link android.webkit.WebView} with |
| 183 | {@link android.webkit.WebView#addJavascriptInterface(Object,String) addJavascriptInterface()} and |
| 184 | name the interface {@code Android}. For example:</p> |
| 185 | |
| 186 | <pre> |
| 187 | WebView webView = (WebView) findViewById(R.id.webview); |
Scott Main | cc91d6b | 2012-11-05 11:21:38 -0800 | [diff] [blame] | 188 | webView.addJavascriptInterface(new WebAppInterface(this), "Android"); |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 189 | </pre> |
| 190 | |
| 191 | <p>This creates an interface called {@code Android} for JavaScript running in the {@link |
| 192 | android.webkit.WebView}. At this point, your web application has access to the {@code |
Scott Main | cc91d6b | 2012-11-05 11:21:38 -0800 | [diff] [blame] | 193 | WebAppInterface} class. For example, here's some HTML and JavaScript that creates a toast |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 194 | message using the new interface when the user clicks a button:</p> |
| 195 | |
| 196 | <pre> |
| 197 | <input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" /> |
| 198 | |
| 199 | <script type="text/javascript"> |
| 200 | function showAndroidToast(toast) { |
| 201 | Android.showToast(toast); |
| 202 | } |
| 203 | </script> |
| 204 | </pre> |
| 205 | |
| 206 | <p>There's no need to initialize the {@code Android} interface from JavaScript. The {@link |
| 207 | android.webkit.WebView} automatically makes it |
| 208 | available to your web page. So, at the click of the button, the {@code showAndroidToast()} |
Scott Main | cc91d6b | 2012-11-05 11:21:38 -0800 | [diff] [blame] | 209 | function uses the {@code Android} interface to call the {@code WebAppInterface.showToast()} |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 210 | method.</p> |
| 211 | |
| 212 | <p class="note"><strong>Note:</strong> The object that is bound to your JavaScript runs in |
| 213 | another thread and not in the thread in which it was constructed.</p> |
| 214 | |
| 215 | <p class="caution"><strong>Caution:</strong> Using {@link |
| 216 | android.webkit.WebView#addJavascriptInterface(Object,String) addJavascriptInterface()} allows |
| 217 | JavaScript to control your Android application. This can be a very useful feature or a dangerous |
| 218 | security issue. When the HTML in the {@link android.webkit.WebView} is untrustworthy (for example, |
| 219 | part or all of the HTML |
| 220 | is provided by an unknown person or process), then an attacker can include HTML that executes |
| 221 | your client-side code and possibly any code of the attacker's choosing. As such, you should not use |
| 222 | {@link android.webkit.WebView#addJavascriptInterface(Object,String) addJavascriptInterface()} unless |
| 223 | you wrote all of the HTML and JavaScript that appears in your {@link android.webkit.WebView}. You |
| 224 | should also not allow the user to |
| 225 | navigate to other web pages that are not your own, within your {@link android.webkit.WebView} |
| 226 | (instead, allow the user's |
| 227 | default browser application to open foreign links—by default, the user's web browser |
| 228 | opens all URL links, so be careful only if you handle page navigation as described in the |
| 229 | following section).</p> |
| 230 | |
| 231 | |
| 232 | |
| 233 | |
| 234 | <h2 id="HandlingNavigation">Handling Page Navigation</h2> |
| 235 | |
| 236 | <p>When the user clicks a link from a web page in your {@link android.webkit.WebView}, the default |
| 237 | behavior is |
| 238 | for Android to launch an application that handles URLs. Usually, the default web browser opens and |
| 239 | loads the destination URL. However, you can override this behavior for your {@link |
| 240 | android.webkit.WebView}, |
| 241 | so links open within your {@link android.webkit.WebView}. You can then allow the user to navigate |
| 242 | backward and forward through their web page history that's maintained by your {@link |
| 243 | android.webkit.WebView}.</p> |
| 244 | |
| 245 | <p>To open links clicked by the user, simply provide a {@link |
| 246 | android.webkit.WebViewClient} for your {@link android.webkit.WebView}, using {@link |
| 247 | android.webkit.WebView#setWebViewClient(WebViewClient) setWebViewClient()}. For example:</p> |
| 248 | |
| 249 | <pre> |
| 250 | WebView myWebView = (WebView) findViewById(R.id.webview); |
| 251 | myWebView.{@link android.webkit.WebView#setWebViewClient(WebViewClient) setWebViewClient}(new WebViewClient()); |
| 252 | </pre> |
| 253 | |
| 254 | <p>That's it. Now all links the user clicks load in your {@link android.webkit.WebView}.</p> |
| 255 | |
| 256 | <p>If you want more control over where a clicked link load, create your own {@link |
| 257 | android.webkit.WebViewClient} that overrides the {@link |
| 258 | android.webkit.WebViewClient#shouldOverrideUrlLoading(WebView,String) |
| 259 | shouldOverrideUrlLoading()} method. For example:</p> |
| 260 | |
| 261 | <pre> |
| 262 | private class MyWebViewClient extends WebViewClient { |
| 263 | @Override |
| 264 | public boolean {@link android.webkit.WebViewClient#shouldOverrideUrlLoading(WebView,String) shouldOverrideUrlLoading}(WebView view, String url) { |
| 265 | if (Uri.parse(url).getHost().equals("www.example.com")) { |
| 266 | // This is my web site, so do not override; let my WebView load the page |
| 267 | return false; |
| 268 | } |
| 269 | // Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs |
| 270 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); |
| 271 | startActivity(intent); |
| 272 | return true; |
| 273 | } |
| 274 | } |
| 275 | </pre> |
| 276 | |
| 277 | <p>Then create an instance of this new {@link android.webkit.WebViewClient} for the {@link |
| 278 | android.webkit.WebView}:</p> |
| 279 | |
| 280 | <pre> |
| 281 | WebView myWebView = (WebView) findViewById(R.id.webview); |
| 282 | myWebView.{@link android.webkit.WebView#setWebViewClient(WebViewClient) setWebViewClient}(new MyWebViewClient()); |
| 283 | </pre> |
| 284 | |
| 285 | <p>Now when the user clicks a link, the system calls |
| 286 | {@link android.webkit.WebViewClient#shouldOverrideUrlLoading(WebView,String) |
| 287 | shouldOverrideUrlLoading()}, which checks whether the URL host matches a specific domain (as defined |
| 288 | above). If it does match, then the method returns false in order to <em>not</em> override the URL |
| 289 | loading (it allows the {@link android.webkit.WebView} to load the URL as usual). If the URL host |
| 290 | does not match, then an {@link android.content.Intent} is created to |
| 291 | launch the default Activity for handling URLs (which resolves to the user's default web |
| 292 | browser).</p> |
| 293 | |
| 294 | |
| 295 | |
| 296 | |
| 297 | <h3 id="NavigatingHistory">Navigating web page history</h3> |
| 298 | |
| 299 | <p>When your {@link android.webkit.WebView} overrides URL loading, it automatically accumulates a |
| 300 | history of visited web |
| 301 | pages. You can navigate backward and forward through the history with {@link |
| 302 | android.webkit.WebView#goBack()} and {@link android.webkit.WebView#goForward()}.</p> |
| 303 | |
Scott Main | cf9fe43 | 2012-01-31 19:14:35 -0800 | [diff] [blame] | 304 | <p>For example, here's how your {@link android.app.Activity} can use the device <em>Back</em> button |
| 305 | to navigate backward:</p> |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 306 | |
| 307 | <pre> |
| 308 | @Override |
| 309 | public boolean {@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown}(int keyCode, KeyEvent event) { |
Scott Main | cf9fe43 | 2012-01-31 19:14:35 -0800 | [diff] [blame] | 310 | // Check if the key event was the Back button and if there's history |
Scott Main | e30d31c | 2013-01-07 15:54:30 -0800 | [diff] [blame] | 311 | if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.{@link android.webkit.WebView#canGoBack() canGoBack}()) { |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 312 | myWebView.{@link android.webkit.WebView#goBack() goBack}(); |
| 313 | return true; |
| 314 | } |
Scott Main | cf9fe43 | 2012-01-31 19:14:35 -0800 | [diff] [blame] | 315 | // If it wasn't the Back key or there's no web page history, bubble up to the default |
Scott Main | 65e62f4 | 2010-09-20 12:46:34 -0700 | [diff] [blame] | 316 | // system behavior (probably exit the activity) |
| 317 | return super.onKeyDown(keyCode, event); |
| 318 | } |
| 319 | </pre> |
| 320 | |
| 321 | <p>The {@link android.webkit.WebView#canGoBack()} method returns |
| 322 | true if there is actually web page history for the user to visit. Likewise, you can use {@link |
| 323 | android.webkit.WebView#canGoForward()} to check whether there is a forward history. If you don't |
| 324 | perform this check, then once the user reaches the end of the history, {@link |
| 325 | android.webkit.WebView#goBack()} or {@link android.webkit.WebView#goForward()} does nothing.</p> |
| 326 | |
| 327 | |
| 328 | |
| 329 | |
| 330 | |
| 331 | |