Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

WebView手记

panwj edited this page Oct 11, 2017 · 21 revisions

有用的链接

学习javascript : http://blog.csdn.net/faithmy509/article/details/42078233

facebook 相关链接 : https://developers.facebook.com/docs/javascript/examples

重点看改链接 : http://www.jianshu.com/p/e3965d3636e7

WebView使用方式

1,将WebView作为控件或布局加入应用, 例如:

<?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 myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");
//添加网络权限
<manifest ... >
 <uses-permission android:name="android.permission.INTERNET" />
 ...
</manifest>

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常用方法总结

1,//与Javascript配合使用 void addJavascriptInterface (Object object, String name)

2,//webview是否有历史记录 boolean canGoBack ()

3,//webview是否可以跳转到设置页面在(历史缓存页面) boolean canGoBackOrForward (int steps) canGoForward

4,//webview是否可以放大 boolean canZoomIn ()

5,//webview是否可以缩小 boolean canZoomOut ()

6,//清除缓存,true:包含磁盘文件 void clearCache (boolean includeDiskFiles)

7//清楚历史记录 void clearHistory ()

8, void clearMatches ()

9, //清除SSL证书 clearSslPreferences

10, //销毁webview void destroy ()

11, WebSettings getSettings ()

12, String getUrl ()

13, void goBack ()

14, void goBackOrForward (int steps)

15, void goForward ()

16, //String: the MIME type of the data, e.g. 'text/html'

17, void loadData (String data, String mimeType, String encoding)

18, void loadUrl (String url)

19, void savePassword (String host, String username, String password)

20, void setWebChromeClient (WebChromeClient client)

21, void setWebViewClient (WebViewClient client)

//激活WebView为活跃状态,能正常执行网页的响应 webView.onResume() ;

//当页面被失去焦点被切换到后台不可见状态,需要执行onPause //通过onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。 webView.onPause();

//当应用程序(存在webview)被切换到后台时,这个方法不仅仅针对当前的webview而是全局的全应用程序的webview //它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。 webView.pauseTimers() //恢复pauseTimers状态 webView.resumeTimers();

//销毁Webview //在关闭了Activity时,如果Webview的音乐或视频,还在播放。就必须销毁Webview //但是注意:webview调用destory时,webview仍绑定在Activity上 //这是由于自定义webview构建时传入了该Activity的context对象 //因此需要先从父容器中移除webview,然后再销毁webview: rootLayout.removeView(webView); webView.destroy();

注意部分

1,JavaScript相关:如果加载的网页中包含JavaScrip,我们需要允许使用JavaScript, 例如:

WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);

2,JavaScript代码与Android代码相结合使用,例如: 首先需要在android应用中添加接口:

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();
 }
}
WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
javascript
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
<script type="text/javascript">
 function showAndroidToast(toast) {
 Android.showToast(toast);
 }
</script>

注意:如果应用的 targetSdkVersion 大于等于17,必须要在接口方法添加注释 @JavascriptInterface 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.

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.

3,WebView中有跳转链接 webview中有需要跳转的链接,如果我们不做处理,android应用会自行处理(如果设置默认浏览器,使用默认的打开,否则弹出系统选择框),作处理,会在该webview中打开,自己处理需使用setWebViewClient(), 示例如下:

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient());
private class MyWebViewClient extends WebViewClient {
 @Override
 public boolean shouldOverrideUrlLoading(WebView view, String url) {
 /** false: 在webview中处理, true: android自行处理 */
 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;
 }
}

4处理导航

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.

5, 浏览网址安全提示(当打开网页不安全时,会先给出浏览网页不安全提醒)

<manifest>
 <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
 android:value="true" />
 ...
 <application> ... </application>
</manifest>

6,WebView渲染器崩溃: 当系统内存不足时,可能引起webview 渲染器崩溃,那么这时与该渲染器绑定的webview对象是不能重复使用的。当崩溃时有两种处理情况,可以允许程序继续执行或者不。如果继续执行,那么之前的webview对象必须从视图层次结构中删除实例,并将该实例销毁以继续执行,然后需要创建一个新的webview对象,继续加载网页(但是load相同网页也可能继续崩溃)

Caution: If your app continues executing after the renderer process goes away, the associated instance of WebView cannot be reused, no matter whether the renderer process is killed or crashes. Your app must remove the instance from the view hierarchy and destroy the instance to continue executing. Your app must then create an entirely new instance of WebView to continue rendering web pages.

public class MyRendererTrackingWebViewClient extends WebViewClient {
 private WebView mWebView;
 @Override
 public boolean onRenderProcessGone(WebView view,
 RenderProcessGoneDetail detail) {
 if (!detail.didCrash()) {
 // Renderer was killed because the system ran out of memory.
 // The app can recover gracefully by creating a new WebView instance
 // in the foreground.
 Log.e("MY_APP_TAG", "System killed the WebView rendering process " +
 "to reclaim memory. Recreating...");
 if (mWebView != null) {
 ViewGroup webViewContainer =
 (ViewGroup) findViewById(R.id.my_web_view_container);
 webViewContainer.removeView(mWebView);
 mWebView.destroy();
 mWebView = null;
 }
 // By this point, the instance variable "mWebView" is guaranteed
 // to be null, so it's safe to reinitialize it.
 return true; // The app continues executing.应用继续执行
 }
 // Renderer crashed because of an internal error, such as a memory
 // access violation.
 Log.e("MY_APP_TAG", "The WebView rendering process crashed!");
 // In this example, the app itself crashes after detecting that the
 // renderer crashed. If you choose to handle the crash more gracefully
 // and allow your app to continue executing, you should 1) destroy the
 // current WebView instance, 2) specify logic for how the app can
 // continue executing, and 3) return "true" instead.
 return false;
 }
}

7,全屏 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.

8,WebView高度 推荐设置WebView的高度是固定值或者march_parent,当webview的高度是march_parent时,父控件的高度不能是wrap_content,否则视图可能有问题

9,判断 WebView 是否已经滚动到页面底端 在View中有一个getScrollY()方法,可以返回当前可见区域的顶端距整个页面顶端的距离,也就是当前内容滚动的距离。 还有getHeight()或者 getBottom()方法都返回当前 View 这个容器的高度 在ViewView中还有getContentHeight() 方法可以返回整个 html 页面的高度,但并不等同于当前整个页面的高度 ,因为 WebView 有缩放功能。你可以通过如下代码来启动或关闭webview的缩放功能。

mWebView.getSettings().setSupportZoom(true); mWebView.getSettings().setBuiltInZoomControls(true); 所以当前整个页面的高度实际上应该是原始 html 的高度再乘上缩放比例. 因此,更正后的结果 ,准确的判断方法应该是:

// 如果已经处于底端 if(WebView.getContentHeight*WebView.getScale() -(webvi ew.getHeight()+WebView.getScrollY())){ //XXX }

10, WebView获取服务器中的 session 问题 接下来我们讲如下两个问题: 1、Android 中的 WebView 如何获取服务器页面的 jsessionid 的值 2、Android 的 WebView 又是如何把得到的 jsessionid 的值在 set 到服务器中,一致达到他们在同一个 jsessionid 的回话中. 其实非常非常简单,只不过是几个方法罢了:

CookieManager cm = CookieManager.getInstance(); cm.removeAllCookie(); cm.getCookie(url); cm.setCookie(url, cookie);

11, WebView清除本地cookies 首先,要清除肯定要会添加,这里给大家提供一个工具方法:

 /***
 * 如果用户已经登录,则同步本地的cookie到webview中
 */
 public void synCookies() {
 if (!CacheUtils.isLogin(this)) return;
 CookieSyncManager.createInstance(this);
 CookieManager cookieManager = CookieManager.getInstance();
 cookieManager.setAcceptCookie(true);
 cookieManager.removeSessionCookie();//移除
 String cookies = PreferenceHelper.readString(this, AppConfig.COOKIE_KEY, AppConfig.COOKIE_KEY);
 KJLoger.debug(cookies);
 cookieManager.setCookie(url, cookies);
 CookieSyncManager.getInstance().sync();
 }

在使用网页版淘宝或百度登录时,WebView会自动登录上次的帐号!(因为WebView 记录了帐号和密码的cookies) 所以,需要清除 SessionCookie也是有必要的。 那么CookieManager同样也为我们提供了清除cookie的方法 CookieManager.getInstance().removeSessionCookie();

这里顺便说一下WebView本身也是会记录html缓存的,上一篇博客中我讲了一种通过文件操作去清理缓存的方法,后来我又发现,其实webview本身就提供了清理缓存的方法,其中参数true是指是否包括磁盘文件也一并清除,传true就和我们昨天的讲的效果是一样的了:

webview.clearCache(true); webview.clearHistory();

12,在页面中先显示图片:

@Override 
public void onLoadResource(WebView view, String url) { 
 mEventListener.onWebViewEvent(CustomWebView.this, OnWebViewEventListener.EVENT_ON_LOAD_RESOURCE, url); 
 if (url.indexOf(".jpg") > 0) { 
 hideProgress(); //请求图片时即显示页面 
 mEventListener.onWebViewEvent(CustomWebView.this, OnWebViewEventListener.EVENT_ON_HIDE_PROGRESS, view.getUrl()); 
 } 
 super.onLoadResource(view, url); 
} 

13,支持flash(待测)

String temp = "<html><body bgcolor=\"" + "black" 
 + "\"> <br/><embed src=\"" + url + "\" width=\"" + "100%" 
 + "\" height=\"" + "90%" + "\" scale=\"" + "noscale" 
 + "\" type=\"" + "application/x-shockwave-flash" 
 + "\"> </embed></body></html>"; 
String mimeType = "text/html"; 
String encoding = "utf-8"; 
web.loadDataWithBaseURL("null", temp, mimeType, encoding, ""); 
源码分析:
在AwContents.java中给出了什么时候才调用shouldOverrideUrlLoading (chromium46中)
源码如下:
final boolean isLoadUrl = (transitionType & PageTransition.FROM_API) != 0;
...
if ((!isLoadUrl || isRedirect) && !isBackForward && !isReload
 && !navigationParams.isPost) {
if (!mContentsClient.hasWebViewClient()) {
ignoreNavigation = AwContentsClient.sendBrowsingIntent(mContext, url,
navigationParams.hasUserGesture
 || navigationParams.hasUserGestureCarryover,
 navigationParams.isRedirect);
} else {
ignoreNavigation = mContentsClient.shouldOverrideUrlLoading(url);
}
}
 
从上面可以看出,浏览器如下行为:前进后退(isBackForward ),刷新(isReload),Post请求(navigationParams.isPost)都不会触发shouldOverrideUrlLoading.
 
如果都不是以上行为,还要满足isRedirect或!isLoadUrl 才能触发shouldOverrideUrlLoading.
isRedirect就是重定向的url,即重定向url也会触发shouldOverrideUrlLoading;这里重点介绍以下isLoadUrl.
凡是webview.loadUrl出load页面的,isLoadUrl都是true(原因是webview.loadUrl最终会调到loadUrl(LoadUrlParams params),进而params.setTransitionType(params.getTransitionType() | PageTransition.FROM_API)).

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /