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的滑動監聽和優雅處理回退棧問題