Dieses Mal zeige ich Ihnen, wie Sie die gemischte Entwicklung von Android und HTML verwenden und welche Vorsichtsmaßnahmen für die Verwendung der gemischten Entwicklung von Android und HTML gelten. Das Folgende ist ein praktischer Fall, schauen wir uns das an.
Viele APPs verfügen mittlerweile über eingebettete HTML5-Seiten, beispielsweise solche, die sich häufig ändern. Einige Seiten erfordern natives Java, um mit js in HTML5 zu interagieren:
1. Über HTML5-Cookies
Viele Parameter wie Benutzerinformationen können im Voraus in Cookies gespeichert werden. Sie können die folgenden Methoden verwenden:
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); CookieManager cookieManager = CookieManager.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; }
Fügen Sie vor mWebView.loadUrl(Url) ein Cookie hinzu, und die Webseite kann den entsprechenden Parameterwert über das Cookie abrufen.
2. In Bezug auf js-Sicherheitsprobleme
js hatte vor 4.2 Schwachstellen
Über JavaScript können Sie auf das aktuelle Gerät zugreifen Alles auf der SD-Karte, sogar Kontaktinformationen, Textnachrichten usw. Okay, schauen wir uns an, wie dieser Fehler aufgetreten ist.
1. WebView hat ein JavaScript-Objekt hinzugefügt und die aktuelle Anwendung hat die Berechtigung zum Lesen und Schreiben von SDCard, das heißt: android.permission.WRITE_EXTERNAL_STORAGE
2 In JS können Sie das durchqueren Fensterobjekt und finden Sie die Existenz des Methodenobjekts „getClass“, rufen Sie dann das Laufzeitobjekt über den Reflexionsmechanismus ab und rufen Sie dann statische Methoden auf, um einige Befehle auszuführen, z. B. Befehle für den Zugriff auf Dateien
3, und Geben Sie dann die Eingabe zurück, nachdem Sie den Befehl ausgeführt haben. Wenn Sie die Zeichenfolge im Stream erhalten, können Sie die Dateinameninformationen abrufen. Dann kannst du machen, was du willst, es ist so gefährlich. Der Kern-JS-Code lautet wie folgt:
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); } } }
Lösung:
1, Android 4.2 oder höher
Auf Android 4.2 oder höher Ja, Google hat eine Korrektur vorgenommen, indem es ein @JavascriptInterface auf der Remote-Methode von Java deklariert hat, wie im folgenden Code gezeigt:
class JsObject { @JavascriptInterface public String toString() { return "injectedObject"; } } webView.addJavascriptInterface(new JsObject(), "injectedObject"); webView.loadData("", "text/html", null); webView.loadUrl("javascript:alert(injectedObject.toString())");
2, für Systeme unter Android 4.2
dieses Problem ist schwieriger zu lösen, aber nicht unmöglich.
Erstens können wir die Methode addJavascriptInterface definitiv nicht mehr aufrufen. In Bezug auf dieses Problem ist es am wichtigsten, die Aktion von JS-Ereignissen zu kennen. Wir wissen, dass es die folgenden Arten von Interaktionen zwischen JS und Java gibt, z. B. Eingabeaufforderung, Warnung usw. Aktionen wie
werden Alle entsprechen der WebChromeClient-Klasse. Die Deklaration dieser Methode lautet wie folgt:
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result)
Über diese Methode kann JS Informationen (Text) an Java übertragen Java kann auch Informationen (Text) an JS übergeben. Können wir eine Lösung finden, um diese Idee umzusetzen?
Nach einigen Versuchen und Analysen haben wir eine praktikablere Lösung gefunden:
[1] Lassen Sie JS eine Javascript-Methode aufrufen Die Methode übergibt die Informationen in JS per Eingabeaufforderung. Diese Informationen sollten ein aussagekräftiger Text sein, den wir kombinieren können und der Folgendes umfassen kann: spezifische Bezeichner, Methodennamen, Parameter usw.
In der onJsPrompt-Methode analysieren wir den übergebenen Text, rufen den Methodennamen, die Parameter usw. ab und rufen dann die angegebene Methode über den Reflexionsmechanismus auf, wodurch die Methode des Java-Objekts aufgerufen wird.
[2] Was den Rückgabewert betrifft, können Sie ihn über die Eingabeaufforderung zurückgeben, sodass die Verarbeitungsergebnisse der Methode in Java an Js zurückgegeben werden können.
[3] Wir müssen dynamisch ein JS-Skript generieren, das die Javascript-Methode deklariert, es über loadUrl laden und auf der HTML-Seite registrieren. Der spezifische Code lautet wie folgt:
javascript:(function JsAddJavascriptInterface_(){ if (typeof(window.jsInterface)!='undefined') { console.log('window.jsInterface_js_interface_name is exist!!');} else { window.jsInterface = { onButtonClick:function(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]})); }, }; } } )()
Anleitung:
1. Das jsInterface im obigen Code ist der Name des zu registrierenden Objekts. Es registriert zwei Methoden: onButtonClick(arg0) und onImageClick(arg0, arg1, arg2). Wert, Rückgabe hinzufügen.
2. Die Eingabeaufforderung ist die von uns vereinbarte Zeichenfolge, die den spezifischen Bezeichner MyApp: enthält, gefolgt von einer Zeichenfolge aus JSON-Zeichenfolgen, die Methodennamen, Parameter, Objektnamen usw. enthält.
3. Wenn JS onButtonClick oder onImageClick aufruft, ruft es die onJsPrompt-Methode in der Java-Ebene auf. Anschließend analysieren wir den Methodennamen, die Parameter und den Objektnamen und spiegeln dann den Methodenaufruf wider.
4. window.jsInterface bedeutet, dass ein Js-Objekt im Fenster deklariert wird. Die Form der deklarierten Methode ist: Methodenname: Funktion (Parameter 1, Parameter 2)
3. Interaktion zwischen Java und JS in HTML5
1), Methode eins:
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" > <!-- 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': str} , function(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', 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.LOAD_DEFAULT); //设置 缓存模式 // 开启 DOM storage API 功能 mWebView.getSettings().setDomStorageEnabled(true); //开启 database storage API 功能 mWebView.getSettings().setDatabaseEnabled(true); String cacheDirPath = getFilesDir().getAbsolutePath()+APP_CACAHE_DIRNAME; // String cacheDirPath = getCacheDir().getAbsolutePath()+Constant.APP_DB_DIRNAME; Log.i(TAG, "cacheDirPath="+cacheDirPath); //设置数据库缓存路径 mWebView.getSettings().setDatabasePath(cacheDirPath); //设置 Application Caches 缓存目录 mWebView.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().getAbsolutePath()+"/webviewCache"); Log.e(TAG, "webviewCacheDir path="+webviewCacheDir.getAbsolutePath()); //删除webview 缓存目录 if(webviewCacheDir.exists()){ deleteFile(webviewCacheDir); } //删除webview 缓存 缓存目录 if(appCacheDir.exists()){ deleteFile(appCacheDir); } }
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_INT >= Build.VERSION_CODES.HONEYCOMB){ response = 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; response = super.shouldInterceptRequest(view, request); if (url.contains("xxxxx.png")){ try { response = new WebResourceResponse("image/png","UTF-",getAssets().open("xxxxx.png")); } catch (IOException e) { e.printStackTrace(); } } return response; } }
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
Das obige ist der detaillierte Inhalt vonSo nutzen Sie die gemischte Entwicklung von Android und HTML. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!