現在很多的APP中會嵌套HTML5的頁面,例如經常變化的等等,有一部分頁面需要原生Java與HTML5中的js進行交互操作,下面介紹一下android中HTML5的使用:
1.關於HTML5種cookie網頁中可能會用到使用者資訊等很多參數,可以提前把這些資訊放到cookie中,可以採用以下方法:
public static void addCookies(Context context, WebView webView, String url) { String url=https://www.xxxx.com/xx/xx/ String protocol = ; String authority = ; try { URL urlObj = new URL(url) ; protocol = urlObj.getProtocol(); authority = urlObj.getAuthority(); } catch (Exception e) { e.printStackTrace(); } String ua = webView.getSettings().getUserAgentString(); webView.getSettings().setUserAgentString(Constant.PROJECT_NAME + / + ParamHandler.getVersion(context) + ( + ua + ; HFWSH)); if (!TextUtils.isEmpty(url) && !TextUtils.isEmpty(protocol) && !TextUtils.isEmpty(authority)) { if (protocol.equals(https) && authority.indexOf(liepin.com) > -1) { CookieSyncManager.createInstance(context); .getInstance(); cookieManager.setAcceptCookie(true); try { List<String> data = getCookiesString(); if (!ListUtils.isEmpty(data)) { for (String value : data) { cookieManager.setCookie(url, value); } } cookieManager.setCookie(url, client_id= + Constant.CLIENT_ID + ;path=/;domain=.XXXX.com); cookieManager.setCookie(url, appVersion= + Constant .VERSION + ;path=/;domain=.XXXX.com); CookieSyncManager.getInstance().sync(); } catch (Exception e) { LogUtils.e(Exception: + e.getMessage())) ; } } } } public List<String> getCookiesString() { ArrayList data = new ArrayList(); this.clearExpired(); Collection values = this.mCookies.values(); Iterator var3 = values.iterator(); while(var3.hasNext() ) { SwiftCookie c = (SwiftCookie)var3.next(); data.add(c.toCookieString()); } return data; }在mWebView.loadUrl(Url)之前加入cookie,網頁就可以透過cookie取到對應的參數值了。
2、關於js的安全問題js在4.2以前有漏洞
透過JavaScript,可以存取目前裝置的SD卡上面的任何東西,甚至是聯絡人訊息,簡訊等。好,我們一起來看看是怎麼出現這樣的錯誤的。
1,WebView新增了JavaScript對象,目前應用具有讀寫SDCard的權限,也就是:android.permission.WRITE_EXTERNAL_STORAGE
2,JS中可以遍歷window對象,找到存在getClass方法的對象的對象,然後再通過反射的機制,得到Runtime對象,然後調用靜態方法來執行一些命令,比如訪問文件的命令.
3,再從執行指令後傳回的輸入流中得到字串,就可以得到檔名的資訊了。然後想幹什麼就做什麼,好危險。核心JS程式碼如下:
function execute(cmdArgs) { for (var obj in window) { if (getClass in window[obj]) { alert(obj); return window[obj].getClass().forName(java.lang.Runtime) .getMethod( getRuntime,null).invoke(null,null).exec(cmdArgs); } } }解決方案: 1,Android 4.2以上的系統在Android 4.2以上的,google作了修正,透過在Java的遠端方法上面聲明一個@JavascriptInterface,如下面程式碼:
class JsObject { @JavascriptInterface public String toString() { return injectedObject; } } webView.addJavascriptInterface(new JsObject(), injectedObject); webView.loadData(, text/html, null); webView.loadUrl(script:alert(injected. toString())); 2,Android 4.2以下的系統這個問題比較難解決,但不是不能解決。
首先,我們肯定不能再呼叫addJavascriptInterface方法了。關於這個問題,最核心的就是要知道JS事件這一動作,JS與Java互動我們知道,有以下幾種,比prompt, alert等,
這樣的動作都會對應到WebChromeClient類別中對應的方法,對於prompt,它對應的方法是onJsPrompt方法,這個方法的宣告如下:
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result)
透過這個方法,JS能把訊息(文字)傳遞到Java,而Java也能把訊息(文字)傳遞到JS中,通知這個思路我們能不能找到解決方案呢?
經過一番嘗試與分析,找到比較可行的方案,請看下面幾個小點:
【1】讓JS呼叫一個Javascript方法,這個方法中是呼叫prompt方法,透過prompt把JS中的信息傳遞過來,這些資訊應該是我們組合成的一段有意義的文本,可能包含:特定標識,方法名稱,參數等。
在onJsPrompt方法中,我們去解析傳遞過來的文本,得到方法名,參數等,再透過反射機制,呼叫指定的方法,從而呼叫到Java物件的方法。
【2】關於回傳值,可以透過prompt回傳回去,這樣就可以把Java中方法的處理結果回傳到Js中。
【3】我們需要動態產生一段宣告Javascript方法的JS腳本,透過loadUrl來載入它,從而註冊到html頁面中,具體的程式碼如下:
javascript:(function JsAddJavascriptInterface_(){ if (typeof(window.jsInterface)!='undefined') { console.log('window.jsInterface_js_interface_name is exist!!');} else { window.jsInterface_interface_name is exist!!');} else { window.jsInterface = {functionC.ClickC. arg0) { return prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onButtonClick',args:[arg0]})); }, onImageClick:function(arg0,arg1,arg2) { prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onImageClick',args:[arg0,arg1,arg2]})); }, }; } } )()說明:
1,上面程式碼中的jsInterface就是要註冊的物件名,它註冊了兩個方法,onButtonClick(arg0)和onImageClick(arg0, arg1, arg2),如果有回傳值,就加上上return。
2,prompt中是我們約定的字串,它包含特定的標識符MyApp:,後麵包含了一串JSON字串,它包含了方法名,參數,物件名等。
3,當JS呼叫onButtonClick或onImageClick時,就會回調到Java層中的onJsPrompt方法,我們再解析出方法名,參數,物件名,再反射呼叫方法。
4,window.jsInterface這表示在window上宣告了一個Js對象,宣告方法的形式是:方法名稱:function(參數1,參數2)
3.在html5中進行java和js的交互1)、方法一:
mWebView.getSettings().setJavaScriptEnabled(true);mWebView.addJavascriptInterface(this, xxx);
然後在當前類別中實作以下方法:
@JavascriptInterface public void callbackFromH5(final String j) { //TODO }callbackFromH5的名字必須和網頁中的js方法名稱一樣
Java呼叫js方法:
mWebView.loadUrl(String.format(javascript:java2js(0)));//這裡是java端呼叫webview的JS
js方法名稱需要和網頁端一直
2)方法二:
jsbridge方法(https://github.com/lzyzsd/JsBridge)
Android JsBridge 是用來在Android app的原生java 程式碼與javascript 程式碼中架設通訊(呼叫)橋樑的輔助工具
1 將jsBridge.jar引進到我們的工程
Android Studio:
repositories { // ... maven { url https://jitpack.io } } dependencies { compile 'com.github.lzyzsd:jsbridge:1.0.4' }2、佈局文件
<?xml version=1.0 encoding=utf-8?> <LinearLayout xmlns:android=http://schemas.android.com/apk/res/android android:layout_width=match_parent android:layout_height=match_parent android:orientation=vertical >:orientation=vertical > <!-- button 示範Java呼叫web --> <Button android:id=@+id/button android:layout_width=match_parent android:text=@string/button_name android:layout_height=dp /> <!-- webview 示範web呼叫Java --> <com.github.lzyzsd.jsbridge. BridgeWebView android:id=@+id/webView android:layout_width=match_parent android:layout_height=match_parent > </com.github.lzyzsd.jsbridge.BridgeWebView> </LinearLayout>
3、java程式碼
//載入伺服器網頁webView.loadUrl(https://www.baidu.com); //必須和js同名函數。 webView.registerHandler(submitFromWeb, new BridgeHandler() { @Override public void handler(String data, CallBackFunction function) { String str =html傳回給java的資料: + data; makeText(MainActivity.this, str, LENGTH_SHORT).show( ); Log.i(TAG, handler = submitFromWeb, data from web = + data); function.onCallBack( str + ,Java經過處理後:+ str.substring(,)); } }); //模擬使用者取得本機位置 User user = new User(); Location location = new Location (); location.address = xxx; user.location = location; user.name = Bruce; webView.callHandler(functionInJs, new Gson().toJson(user), new CallBackFunction() { @Override public void onCallBack(String data) { makeText(MainActivity.this, 網頁在取得你的資訊, LENGTH_SHORT).show(); } }); webView. send(hello); webView.callHandler(functionInJs, data from Java, new CallBackFunction() { @Override public void onCallBack(String data) { // TODO Auto-generated method stub Log.i(TAG, reponse data from js + data); }) ;js調用
var str1 = document.getElementById(text1).value; var str2 = document.getElementById(text2).value; //呼叫本機java方法window.WebViewJavascriptBridge.callHandler( 'submitFromWeb' , {'param': strtion} , ftionunc( responseData) { document.getElementById(show).innerHTML = send get responseData from java, data = + responseData } ); //註冊事件監聽document.addEventListener( 'WebViewJavascriptBridgeReady' , function() { callback(WebViewJavascriptBridge) }, false ); //註冊回調函數,第一次連線回調函數,第一次連線回調函數呼叫初始化函數connectWebViewJavascriptBridge(function(bridge) { bridge.init(function(message, responseCallback) { console.log('JS got a message', message); var data = { 'Javascript Responds': 'Wee!' }; console.log('JS responding with',ponds': 'Wee!' }; console.log('JS responding with', data); responseCallback(data); }); bridge.registerHandler(functionInJs, function(data, responseCallback) { document.getElementById(show).innerHTML = (data from Java: = + data); var responseData = Javascript Says Right back aka!; responseCallback(responseData); }); })4.關於webView的最佳化
1.設定WebView 快取模式
private void initWebView() { mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setRenderPriority(RenderPriority.HIGH); mWebView.getSettings().setCacheMode(WebSettings.HIGH); mWebView.getSettings().setCacheMode(WebSettings..開啟DOM storage API功能mWebView.getSettings().setDomStorageEnabled(true); //開啟database storage API 功能mWebView.getSettings().setDatabaseEnabled(true); String cacheDirPath = getFilesDir().getAbsolutePath)+APP_CACAHE_DIacheME_CACAHE_DIacheME; getCacheDir().getAbsolutePath()+Constant.APP_DB_DIRNAME; Log.i(TAG, cacheDirPath=+cacheDirPath); //設定資料庫快取路徑mWebView.getSettings().setDatabasePath(cacheDircationPath); //設定資料庫快取路徑mWebView.getSettings().setDatabasePath(cacheDircationPath); //設定AppliView Caches mWeb. getSettings().setAppCachePath(cacheDirPath); //開啟Application Caches 功能mWebView.getSettings().setAppCacheEnabled(true);2、清除快取
/** * 清除WebView快取*/ public void clearWebViewCache(){ //清理Webview快取資料庫try { deleteDatabase(webview.db); deleteDatabase(webviewCache.db); } catch (Exception e) { e.printStackTrace(); } //WebView 快取檔案File appCacheDir = new File(getFilesDir().getAbsolutePath()+APP_CACAHE_DIRNAME); Log.e(TAG, appCacheDir path=+appCacheDir.getAbsolutePath()); File webviewCacheDir = new File(getCacheDir()。 e(TAG, webviewCacheDir path=+webviewCacheDir.getAbsolutePath()); //刪除webview 快取目錄if(webviewCacheDir.exists()){ deleteFile(webviewCacheDir); } //刪除webview 快取快取目錄if(appCacheDir.exists()){ delete //(appCacheDirete ); } }3.在使用WebView載入網頁的時候,有一些固定的資源檔案如js/css/圖片等資源會比較大,如果直接從網路載入會導致頁面載入的比較慢,而且會消耗比較多的流量。所以這些文件應該要放在assets裡面同app打包。
解決這個問題用到API 11(HONEYCOMB)提供的shouldInterceptRequest(WebView view, String url) 函數來載入本機資源。
API 21又將這個方法棄用了,是重載一個新的shouldInterceptRequest,所需的參數中將url替換成了成了request。
例如有一個圖片xxxxx.png,這張圖片已經放在了assets中,現在載入了一個外部html,就需要直接把assets裡面的圖片拿出來載入而不需要重新從網路取得。當然可以在html裡面將圖片連結換成file:///android_asset/xxxxx.png,
但是這樣這個html就不能在Android ,ios,WAP中公用了。
webView.setWebViewClient(new WebViewClient() { @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { WebResourceResponse response = null; if (Build.VERSION.SDK_VERINT >= Build. super.shouldInterceptRequest(view,url); if (url.contains(xxxxx.png)){ try { response = new WebResourceResponse(image/png,UTF-8,getAssets().open(xxxxx.png)); } catch (IOException e) { e.printStackTrace(); } } } // return super.shouldInterceptRequest(view, url); return response; } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { WebResourceResponse response = null; responsequest. (url.contains(xxxxx.png)){ try { response = new WebResourceResponse(image/png,UTF-,getAssets().open(xxxxx.png)); } catch (IOException e) { e.printStackTrace(); } } return response; } }以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。