01.基础使用目录介绍javascript
02.优化汇总目录介绍css
03.问题汇总目录介绍html
在activity中最简单的使用前端
webview.loadUrl("http://www.baidu.com/"); //加载web资源 //webView.loadUrl("file:///android_asset/example.html"); //加载本地资源 //这个时候发现一个问题,启动应用后,自动的打开了系统内置的浏览器,解决这个问题须要为webview设置 WebViewClient,并重写方法: webview.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); //返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器 return true; } //还能够重写其余的方法 });
那些因素影响页面加载速度java
影响页面加载速度的因素有很是多,在对 WebView 加载一个网页的过程进行调试发现android
第一种方式:native 调用 js 的方法,方法为:git
//java //调用无参方法 mWebView.loadUrl("javascript:callByAndroid()"); //调用有参方法 mWebView.loadUrl("javascript:showData(" + result + ")"); //javascript,下面是对应的js代码 <script type="text/javascript"> function showData(result){ alert("result"=result); return "success"; } function callByAndroid(){ console.log("callByAndroid") showElement("Js:无参方法callByAndroid被调用"); } </script>
第二种方式:github
if (Build.VERSION.SDK_INT < 18) { mWebView.loadUrl(jsStr); } else { mWebView.evaluateJavascript(jsStr, new ValueCallback<String>() { @Override public void onReceiveValue(String value) { //此处为 js 返回的结果 } }); }
两种方式的对比web
注意问题数据库
第一种方式:经过 addJavascriptInterface 方法进行添加对象映射
mWebView.getSettings().setJavaScriptEnabled(true);
这个函数会有一个警告,由于在特定的版本之下会有很是危险的漏洞,设置完这个属性以后,Native须要定义一个类:
public class JSObject { private Context mContext; public JSObject(Context context) { mContext = context; } @JavascriptInterface public String showToast(String text) { Toast.show(mContext, text, Toast.LENGTH_SHORT).show(); return "success"; } /** * 前端代码嵌入js: * imageClick 名应和js函数方法名一致 * * @param src 图片的连接 */ @JavascriptInterface public void imageClick(String src) { Log.e("imageClick", "----点击了图片"); } /** * 网页使用的js,方法无参数 */ @JavascriptInterface public void startFunction() { Log.e("startFunction", "----无参"); } } //特定版本下会存在漏洞 mWebView.addJavascriptInterface(new JSObject(this), "yc逗比");
- JS 代码调用 - 这种方式的好处在于使用简单明了,本地和 JS 的约定也很简单,就是对象名称和方法名称约定好便可,缺点就是要提到的漏洞问题。 ``` function showToast(){ var result = myObj.showToast("我是来自web的Toast"); } function showToast(){ myObj.imageClick("图片"); } function showToast(){ myObj.startFunction(); } ```
第二种方式:利用 WebViewClient 接口回调方法拦截 url
这种方式其实实现也很简单,使用的频次也很高,上面介绍到了 WebViewClient ,其中有个回调接口 shouldOverrideUrlLoading (WebView view, String url)) ,就是利用这个拦截 url,而后解析这个 url 的协议,若是发现是咱们预先约定好的协议就开始解析参数,执行相应的逻辑。注意这个方法在 API24 版本已经废弃了,须要使用 shouldOverrideUrlLoading (WebView view, WebResourceRequest request)) 替代,使用方法很相似,咱们这里就使用 shouldOverrideUrlLoading (WebView view, String url)) 方法来介绍一下:
public boolean shouldOverrideUrlLoading(WebView view, String url) { //假定传入进来的 url = "js://openActivity?arg1=111&arg2=222",表明须要打开本地页面,而且带入相应的参数 Uri uri = Uri.parse(url); String scheme = uri.getScheme(); //若是 scheme 为 js,表明为预先约定的 js 协议 if (scheme.equals("js")) { //若是 authority 为 openActivity,表明 web 须要打开一个本地的页面 if (uri.getAuthority().equals("openActivity")) { //解析 web 页面带过来的相关参数 HashMap<String, String> params = new HashMap<>(); Set<String> collection = uri.getQueryParameterNames(); for (String name : collection) { params.put(name, uri.getQueryParameter(name)); } Intent intent = new Intent(getContext(), MainActivity.class); intent.putExtra("params", params); getContext().startActivity(intent); } //表明应用内部处理完成 return true; } return super.shouldOverrideUrlLoading(view, url); }
- JS 代码调用 ``` function openActivity(){ document.location = "js://openActivity?arg1=111&arg2=222"; } ``` - 存在问题:这个代码执行以后,就会触发本地的 shouldOverrideUrlLoading 方法,而后进行参数解析,调用指定方法。这个方式不会存在第一种提到的漏洞问题,可是它也有一个很繁琐的地方是,若是 web 端想要获得方法的返回值,只能经过 WebView 的 loadUrl 方法去执行 JS 方法把返回值传递回去,相关的代码以下: ``` //java mWebView.loadUrl("javascript:returnResult(" + result + ")"); //javascript function returnResult(result){ alert("result is" + result); } ```
第三种方式:利用 WebChromeClient 回调接口的三个方法拦截消息
@Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { return super.onJsAlert(view, url, message, result); } @Override public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { return super.onJsConfirm(view, url, message, result); } @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { //假定传入进来的 message = "js://openActivity?arg1=111&arg2=222",表明须要打开本地页面,而且带入相应的参数 Uri uri = Uri.parse(message); String scheme = uri.getScheme(); if (scheme.equals("js")) { if (uri.getAuthority().equals("openActivity")) { HashMap<String, String> params = new HashMap<>(); Set<String> collection = uri.getQueryParameterNames(); for (String name : collection) { params.put(name, uri.getQueryParameter(name)); } Intent intent = new Intent(getContext(), MainActivity.class); intent.putExtra("params", params); getContext().startActivity(intent); //表明应用内部处理完成 result.confirm("success"); } return true; } return super.onJsPrompt(view, url, message, defaultValue, result); }
和 WebViewClient 同样,此次添加的是WebChromeClient接口,能够拦截JS中的几个提示方法,也就是几种样式的对话框,在 JS 中有三个经常使用的对话框方法:
function clickprompt(){ var result=prompt("js://openActivity?arg1=111&arg2=222"); alert("open activity " + result); }
以上三种方案的总结和对比
WebView.loadUrl(url)加载网页作了什么?
加载页面的过程当中回调哪些方法?
加载页面结束回调哪些方法
onPageFinished()或者onPageStarted()方法中注入js代码
WebViewClient.onProgressChanged()方法中注入js代码
WebViewClient.onProgressChanged()这个方法在dom树渲染的过程当中会回调屡次,每次都会告诉咱们当前加载的进度。
那么有人会问,加载到多少才须要处理js注入逻辑呢?
清除缓存数据的方法有哪些?
//清除网页访问留下的缓存 //因为内核缓存是全局的所以这个方法不只仅针对webview而是针对整个应用程序. Webview.clearCache(true); //清除当前webview访问的历史记录//只会webview访问历史记录里的全部记录除了当前访问记录 Webview.clearHistory(); //这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据 Webview.clearFormData();
在Manifest文件中,给想要接收跳转的Activity添加<intent-filter>配置:
<activity android:name=".X5WebViewActivity" android:configChanges="orientation|screenSize" android:hardwareAccelerated="true" android:launchMode="singleTask" android:screenOrientation="portrait" android:theme="@style/Theme.AppCompat.Light.NoActionBar"> <!--须要添加下面的intent-filter配置--> <intent-filter tools:ignore="AppLinkUrlError"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <!--使用http,则只能打开http开头的网页--> <data android:scheme="https" /> </intent-filter> </activity>
而后在 X5WebViewActivity 中获取相关传递数据。具体能够看lib中的X5WebViewActivity类代码。
public class X5WebViewActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_web_view); getIntentData(); initTitle(); initWebView(); webView.loadUrl(mUrl); // 处理 做为三方浏览器打开传过来的值 getDataFromBrowser(getIntent()); } /** * 使用singleTask启动模式的Activity在系统中只会存在一个实例。 * 若是这个实例已经存在,intent就会经过onNewIntent传递到这个Activity。
*/ @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); getDataFromBrowser(intent); } /** * 做为三方浏览器打开传过来的值 * Scheme: https * host: www.jianshu.com * path: /p/yc * url = scheme + "://" + host + path; */ private void getDataFromBrowser(Intent intent) { Uri data = intent.getData(); if (data != null) { try { String scheme = data.getScheme(); String host = data.getHost(); String path = data.getPath(); String text = "Scheme: " + scheme + "\n" + "host: " + host + "\n" + "path: " + path; Log.e("data", text); String url = scheme + "://" + host + path; webView.loadUrl(url); } catch (Exception e) { e.printStackTrace(); } } } } ```
一些重点说明
至于缘由暂时没有找到,解决方案以下所示
/** * 当缩放改变的时候会调用该方法 * @param view view * @param oldScale 以前的缩放比例
*/ @Override public void onScaleChanged(WebView view, float oldScale, float newScale) { super.onScaleChanged(view, oldScale, newScale); //视频全屏播放按返回页面被放大的问题 if (newScale - oldScale > 7) { //异常放大,缩回去。 view.setInitialScale((int) (oldScale / newScale * 100)); } } ```
html代码下载到WebView后,webkit开始解析网页各个节点,发现有外部样式文件或者外部脚本文件时,会异步发起网络请求下载文件,但若是在这以前也有解析到image节点,那势必也会发起网络请求下载相应的图片。在网络状况较差的状况下,过多的网络请求就会形成带宽紧张,影响到css或js文件加载完成的时间,形成页面空白loading太久。解决的方法就是告诉WebView先不要自动加载图片,等页面finish后再发起图片加载。
//初始化的时候设置,具体代码在X5WebView类中 if(Build.VERSION.SDK_INT >= KITKAT) { //设置网页在加载的时候暂时不加载图片 ws.setLoadsImagesAutomatically(true); } else { ws.setLoadsImagesAutomatically(false); } /** * 当页面加载完成会调用该方法 * @param view view
*/ @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); //页面finish后再发起图片加载 if(!webView.getSettings().getLoadsImagesAutomatically()) { webView.getSettings().setLoadsImagesAutomatically(true); } } ```
当WebView加载页面出错时(通常为404 NOT FOUND),安卓WebView会默认显示一个出错界面。当WebView加载出错时,会在WebViewClient实例中的onReceivedError(),还有onReceivedTitle方法接收到错误
/** * 请求网络出现error * @param view view * @param errorCode 错误🐎 * @param description description
*/ @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); if (errorCode == 404) { //用javascript隐藏系统定义的404页面信息 String data = "Page NO FOUND!"; view.loadUrl("javascript:document.body.innerHTML=\"" + data + "\""); } else { if (webListener!=null){ webListener.showErrorView(); } } } // 向主机应用程序报告Web资源加载错误。这些错误一般代表没法链接到服务器。 // 值得注意的是,不一样的是过期的版本的回调,新的版本将被称为任何资源(iframe,图像等) // 不只为主页。所以,建议在回调过程当中执行最低要求的工做。 // 6.0 以后 @Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { super.onReceivedError(view, request, error); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { X5WebUtils.log("服务器异常"+error.getDescription().toString()); } //ToastUtils.showToast("服务器异常6.0以后"); //当加载错误时,就让它加载本地错误网页文件 //mWebView.loadUrl("file:///android_asset/errorpage/error.html"); if (webListener!=null){ webListener.showErrorView(); } } /** * 这个方法主要是监听标题变化操做的 * @param view view * @param title 标题 */ @Override public void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); if (title.contains("404") || title.contains("网页没法打开")){ if (webListener!=null){ webListener.showErrorView(); } } else { // 设置title } } ```
4.0以上的系统咱们开启硬件加速后,WebView渲染页面更加快速,拖动也更加顺滑。但有个反作用就是,当WebView视图被总体遮住一块,而后忽然恢复时(好比使用SlideMenu将WebView从侧边滑出来时),这个过渡期会出现白块同时界面闪烁。解决这个问题的方法是在过渡期前将WebView的硬件加速临时关闭,过渡期后再开启
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null); }
webView加载一些别人的url时候,有时候会发生证书认证错误的状况,这时候咱们但愿可以正常的呈现页面给用户,咱们须要忽略证书错误,须要调用WebViewClient类的onReceivedSslError方法,调用handler.proceed()来忽略该证书错误。
/** * 在加载资源时通知主机应用程序发生SSL错误 * 做用:处理https请求 * @param view view * @param handler handler
*/ @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { super.onReceivedSslError(view, handler, error); if (error!=null){ String url = error.getUrl(); X5WebUtils.log("onReceivedSslError----异常url----"+url); } //https忽略证书问题 if (handler!=null){ //表示等待证书响应 handler.proceed(); // handler.cancel(); //表示挂起链接,为默认方式 // handler.handleMessage(null); //可作其余处理 } } ```
WebView页面中播放了音频,退出Activity后音频仍然在播放,须要在Activity的onDestory()中调用
@Override protected void onDestroy() { try { //有音频播放的web页面的销毁逻辑 //在关闭了Activity时,若是Webview的音乐或视频,还在播放。就必须销毁Webview //可是注意:webview调用destory时,webview仍绑定在Activity上 //这是因为自定义webview构建时传入了该Activity的context对象 //所以须要先从父容器中移除webview,而后再销毁webview: if (webView != null) { ViewGroup parent = (ViewGroup) webView.getParent(); if (parent != null) { parent.removeView(webView); } webView.removeAllViews(); webView.destroy(); webView = null; } } catch (Exception e) { Log.e("X5WebViewActivity", e.getMessage()); } super.onDestroy(); }
创建链接/服务器处理;在页面请求的数据返回以前,主要有如下过程耗费时间。
DNS connection 服务器处理
DNS采用和客户端API相同的域名
客户端内的WebView都是能够经过客户端的某个schema打开的,而要打开页面的URL不少都并不写在客户端内,而是能够由URL中的参数传递过去的。上面4.0.5 使用scheme协议打开连接风险已经说明了scheme使用的危险性,那么如何避免这个问题了,设置运行访问的白名单。或者当用户打开外部连接前给用户强烈而明显的提示。具体操做以下所示:
@Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); String host = Uri.parse(url).getHost(); LoggerUtils.i("host:" + host); if (!BuildConfig.IS_DEBUG) { if (Arrays.binarySearch(domainList, host) < 0) { //不在白名单内,非法网址,这个时候给用户强烈而明显的提示 } else { //合法网址 } } }
致使一直占有cpu 耗电特别快,因此若是遇到这种状况,处理方式以下所示。大概意思就是在后台的时候,会调用onStop方法,即此时关闭js交互,回到前台调用onResume再开启js交互。
//在onStop里面设置setJavaScriptEnabled(false); //在onResume里面设置setJavaScriptEnabled(true)。 @Override protected void onResume() { super.onResume(); if (mWebView != null) { mWebView.getSettings().setJavaScriptEnabled(true); } } @Override protected void onStop() { super.onStop(); if (mWebView != null) { mWebView.getSettings().setJavaScriptEnabled(false); } }
提早显示进度条不是提高性能 , 可是对用户体验来讲也是很重要的一点 , WebView.loadUrl("url") 不会立马就回调 onPageStarted 或者 onProgressChanged 由于在这一时间段,WebView 有可能在初始化内核,也有可能在与服务器创建链接,这个时间段容易出现白屏,白屏用户体验是很糟糕的 ,因此建议
//正确 pb.setVisibility(View.VISIBLE); mWebView.loadUrl("https://github.com/yangchong211/LifeHelper"); //不太好 @Override public void onPageStarted(WebView webView, String s, Bitmap bitmap) { super.onPageStarted(webView, s, bitmap); //设定加载开始的操做 pb.setVisibility(View.VISIBLE); } //下面这个是监听进度条进度变化的逻辑 mWebView.getX5WebChromeClient().setWebListener(interWebListener); mWebView.getX5WebViewClient().setWebListener(interWebListener); private InterWebListener interWebListener = new InterWebListener() { @Override public void hindProgressBar() { pb.setVisibility(View.GONE); } @Override public void showErrorView() { } @Override public void startProgress(int newProgress) { pb.setProgress(newProgress); } @Override public void showTitle(String title) { } };
WebView 默认开启密码保存功能 mWebView.setSavePassword(true),若是该功能未关闭,在用户输入密码时,会弹出提示框,询问用户是否保存密码,若是选择”是”,密码会被明文保到 /data/data/com.package.name/databases/webview.db 中,这样就有被盗取密码的危险,因此须要经过 WebSettings.setSavePassword(false) 关闭密码保存提醒功能。
/设置是否开启密码保存功能,不建议开启,默认已经作了处理,存在盗取密码的危险 mX5WebView.setSavePassword(false);
进化史以下所示
第一次打开Web面 ,使用WebView加载页面的时候特别慢,第二次打开就能明显的感受到速度有提高,为何?
偶发状况,获取不到webView的内容高度
webView.loadData(htmlString, "text/html", "utf-8"); webView.setWebViewClient(new WebViewClient() { public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); Log.d("yc", view.getContentheight() + ""); } });
第一种解决办法:提供onPageFinished()一些延迟
webView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); webView.postDelayed(new Runnable() { @Override public void run() { int contentHeight = webView.getContentHeight(); int viewHeight = webView.getHeight(); } }, 500); } });
常见的用法是在APP获取到来自网页的数据后,从新生成一个intent,而后发送给别的组件使用这些数据。好比使用Webview相关的Activity来加载一个来自网页的url,若是此url来自url scheme中的参数,如:yc://ycbjie:8888/from?load_url=http://www.taobao.com。
使用建议
解决办法
对于WebView加载一个网页过程当中所产生的错误回调,大体有三种
/** * 只有在主页面加载出现错误时,才会回调这个方法。这正是展现加载错误页面最合适的方法。 * 然而,若是无论三七二十一直接展现错误页面的话,那颇有可能会误判,给用户形成常常加载页面失败的错觉。 * 因为不一样的WebView实现可能不同,因此咱们首先须要排除几种误判的例子: * 1.加载失败的url跟WebView里的url不是同一个url,排除; * 2.errorCode=-1,代表是ERROR_UNKNOWN的错误,为了保证不误判,排除 * 3failingUrl=null&errorCode=-12,因为错误的url是空而不是ERROR_BAD_URL,排除 * @param webView webView * @param errorCode errorCode * @param description description
*/ @Override public void onReceivedError(WebView webView, int errorCode, String description, String failingUrl) { super.onReceivedError(webView, errorCode, description, failingUrl); // -12 == EventHandle.ERROR_BAD_URL, a hide return code inside android.net.http package if ((failingUrl != null && !failingUrl.equals(webView.getUrl()) && !failingUrl.equals(webView.getOriginalUrl())) /* not subresource error*/ || (failingUrl == null && errorCode != -12) /*not bad url*/ || errorCode == -1) { //当 errorCode = -1 且错误信息为 net::ERR_CACHE_MISS return; } if (!TextUtils.isEmpty(failingUrl)) { if (failingUrl.equals(webView.getUrl())) { //作本身的错误操做,好比自定义错误页面 } } } /** * 只有在主页面加载出现错误时,才会回调这个方法。这正是展现加载错误页面最合适的方法。 * 然而,若是无论三七二十一直接展现错误页面的话,那颇有可能会误判,给用户形成常常加载页面失败的错觉。 * 因为不一样的WebView实现可能不同,因此咱们首先须要排除几种误判的例子: * 1.加载失败的url跟WebView里的url不是同一个url,排除; * 2.errorCode=-1,代表是ERROR_UNKNOWN的错误,为了保证不误判,排除 * 3failingUrl=null&errorCode=-12,因为错误的url是空而不是ERROR_BAD_URL,排除 * @param webView webView * @param webResourceRequest webResourceRequest * @param webResourceError webResourceError */ @Override public void onReceivedError(WebView webView, WebResourceRequest webResourceRequest, WebResourceError webResourceError) { super.onReceivedError(webView, webResourceRequest, webResourceError); } /** * 任何HTTP请求产生的错误都会回调这个方法,包括主页面的html文档请求,iframe、图片等资源请求。 * 在这个回调中,因为混杂了不少请求,不适合用来展现加载错误的页面,而适合作监控报警。 * 当某个URL,或者某个资源收到大量报警时,说明页面或资源可能存在问题,这时候可让相关运营及时响应修改。 * @param webView webView * @param webResourceRequest webResourceRequest * @param webResourceResponse webResourceResponse */ @Override public void onReceivedHttpError(WebView webView, WebResourceRequest webResourceRequest, WebResourceResponse webResourceResponse) { super.onReceivedHttpError(webView, webResourceRequest, webResourceResponse); } /** * 任何HTTPS请求,遇到SSL错误时都会回调这个方法。 * 比较正确的作法是让用户选择是否信任这个网站,这时候能够弹出信任选择框供用户选择(大部分正规浏览器是这么作的)。 * 有时候,针对本身的网站,可让一些特定的网站,无论其证书是否存在问题,都让用户信任它。 * 坑:有时候部分手机打开页面报错,绝招:让本身网站的全部二级域都是可信任的。 * @param webView webView * @param sslErrorHandler sslErrorHandler * @param sslError sslError */ @Override public void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) { super.onReceivedSslError(webView, sslErrorHandler, sslError); //判断网站是不是可信任的,与本身网站host做比较 if (WebViewUtils.isYCHost(webView.getUrl())) { //若是是本身的网站,则继续使用SSL证书 sslErrorHandler.proceed(); } else { super.onReceivedSslError(webView, sslErrorHandler, sslError); } } ```
另一种让图片不超出屏幕范围的方法,能够用的是css
<script type="text/javascript"> var tables = document.getElementsByTagName("img"); //找到table标签 for(var i = 0; i<tables.length; i++){ // 逐个改变 tables[i].style.width = "100%"; // 宽度改成100% tables[i].style.height = "auto"; } </script>
经过webView的setting属性设置
// 网页内容的宽度是否可大于WebView控件的宽度 ws.setLoadWithOverviewMode(false);
Android和js如何通讯
这类应用程序通常都会有相似以下的代码:
webView.addJavascriptInterface(javaObj, "jsObj");
此段代码将javaObj对象暴露给js脚本,能够经过jsObj对象对其进行引用,调用javaObj的方法。结合Java的反射机制能够经过js脚本执行任意Java代码,相关代码以下:
<script> function execute(cmdArgs) { return jsobj.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs); } execute(someCmd); </script>
addJavascriptInterface任何命令执行漏洞
@JavascriptInterface注解作了什么操做
代码里怎么设置Cookie,以下所示
/**
* * @param url 地址 * @param cookieList 须要添加的Cookie值,以键值对的方式:key=value */ private void syncCookie (Context context , String url, ArrayList<String> cookieList) { //初始化 CookieSyncManager.createInstance(context); //获取对象 CookieManager cookieManager = CookieManager.getInstance(); cookieManager.setAcceptCookie(true); //移除 cookieManager.removeSessionCookie(); //添加 if (cookieList != null && cookieList.size() > 0) { for (String cookie : cookieList) { cookieManager.setCookie(url, cookie); } } String cookies = cookieManager.getCookie(url); X5LogUtils.d("cookies-------"+cookies); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { cookieManager.flush(); } else { CookieSyncManager.getInstance().sync(); } } ```
在android里面在调用webView.loadUrl(url)以前一句调用此方法就能够给WebView设置Cookie
webView.getSettings().setBuiltInZoomControls(true); webView.getSettings().setJavaScriptEnabled(true);
还有跨域问题: 域A: test1.yc.com 域B: test2.yc.com
Cookie的过时机制
能够设置Cookie的生效时间字段名为: expires 或 max-age。
下面列出几个有用的接口:
webView从Lollipop(5.0)开始webView默认不容许混合模式, https当中不能加载http资源, 而开发的时候可能使用的是https的连接, 可是连接中的图片多是http的, 因此须要设置开启。
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); } mWebView.getSettings().setBlockNetworkImage(false);
webviewClient中有onReceivedError方法,当出现证书校验错误时,咱们能够在该方法中使用handler.proceed()来忽略证书校验继续加载网页,或者使用默认的handler.cancel()来终端加载。
@SuppressLint("NewApi") @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { //handler.proceed();// 接受证书 super.onReceivedSslError(view, handler, error); }
若是webView.getSettings().setAllowFileAccess(boolean)设置为true,则会面临该问题;该漏洞是经过WebView对Javascript的延时执行和html文件替换产生的。
问题描述
解决办法
首先载入js
//将js对象与java对象进行映射 webView.addJavascriptInterface(new ImageJavascriptInterface(context), "imagelistener");
html加载完成以后,添加监听图片的点击js函数,这个能够在onPageFinished方法中操做
@Override public void onPageFinished(WebView view, String url) { X5LogUtils.i("-------onPageFinished-------"+url); //html加载完成以后,添加监听图片的点击js函数 //addImageClickListener(); addImageArrayClickListener(webView); }
具体看addImageArrayClickListener的实现方法。
/** * android与js交互: * 首先咱们拿到html中加载图片的标签img. * 而后取出其对应的src属性 * 循环遍历设置图片的点击事件 * 将src做为参数传给java代码 * 这个循环将所图片放入数组,当js调用本地方法时传入。 * 固然若是采用方式一获取图片的话,本地方法能够不须要传入这个数组 * 经过js代码找到标签为img的代码块,设置点击的监听方法与本地的openImage方法进行链接
*/ private void addImageArrayClickListener(WebView webView) { webView.loadUrl("javascript:(function(){" + "var objs = document.getElementsByTagName(\"img\"); " + "var array=new Array(); " + "for(var j=0;j<objs.length;j++){" + " array[j]=objs[j].src; " + "}"+ "for(var i=0;i<objs.length;i++) " + "{" + " objs[i].onclick=function() " + " { " + " window.imagelistener.openImage(this.src,array); " + " } " + "}" + "})()"); } ```
最后看看js的通讯接口作了什么
public class ImageJavascriptInterface { private Context context; private String[] imageUrls; public ImageJavascriptInterface(Context context,String[] imageUrls) { this.context = context; this.imageUrls = imageUrls; } public ImageJavascriptInterface(Context context) { this.context = context; } /**
*/ @android.webkit.JavascriptInterface public void openImage(String img , String[] imageUrls) { Intent intent = new Intent(); intent.putExtra("imageUrls", imageUrls); intent.putExtra("curImageUrl", img); // intent.setClass(context, PhotoBrowserActivity.class); context.startActivity(intent); for (int i = 0; i < imageUrls.length; i++) { Log.e("图片地址"+i,imageUrls[i].toString()); } } } ```
在有些需求中会有一些吸顶的元素,例如导航条,购买按钮等;当页面滚动超出元素高度后,元素吸附在屏幕顶部。在WebView中成了难题:在页面滚动期间,Scroll Event不触发。不只如此,WebView在滚动期间还有各类限定:
这些限制让WebView在滚动期间很难有较好的体验。这些限制大部分是不可突破的,但至少对于吸顶功能仍是能够作一些支持,解决方法:
因为WebView加载的页面代码是从服务器动态获取的,这些代码将会很容易被中间环节所窃取或者修改,其中最主要的问题出自地方运营商和一些WiFi。监测到的问题包括:
针对页面注入的行为,有一些解决方案:
2.HTTPS。
3.App使用Socket代理请求
在资源预加载方面,其实也有不少种方式,下面主要列举了一些:
getContentHeight 返回的是整个html的高度,但并不等同于当前整个页面的高度,由于WebView有缩放功能,因此当前整个页面的高度实际上应该是原始html 的高度再乘上缩放比例. 所以,更正后的结果,准确的判断方法应该是:
if(WebView.getContentHeight*WebView.getScale() == (webview.getHeight()+WebView.getScrollY())){ //已经处于底端 }
能够经过使用 WebView.loadData(String data, String mimeType, String encoding)) 方法来加载一整个 HTML 页面的一小段内容,第一个就是咱们须要 WebView 展现的内容,第二个是咱们告诉 WebView 咱们展现内容的类型,通常,第三个是字节码,可是使用的时候,这里会有一些坑
String html = new String("<h3>我是loadData() 的标题</h3><p>  我是他的内容</p>"); webView.loadData(html, "text/html", "UTF-8");
使用loadData()或 loadDataWithBaseURL()加载一段HTML代码片断
data:是要加载的数据类型,但在数据里面不能出现英文字符:'#', '%', '' , '?' 这四个字符,若是有的话能够用 %23, %25, %27, %3f,这些字符来替换,在平时测试时,你的数据时,你的数据里含有这些字符,但不会出问题,当出问题时,你能够替换下。
解决办法
String html = new String("<h3>我是loadData() 的标题</h3><p>  我是他的内容</p>"); webView.loadData(html, "text/html;charset=UTF-8", "null");
专业叙述
网络解释
举个例子
实现WebView的滑动监听和优雅处理回退栈问题