ขณะนี้แอปจำนวนมากมีหน้า HTML5 ฝังอยู่ เช่น หน้าเพจที่มีการเปลี่ยนแปลงบ่อยครั้ง ต้องใช้ Java ดั้งเดิมเพื่อโต้ตอบกับ js ใน HTML5 ต่อไปนี้เป็นคำแนะนำเกี่ยวกับการใช้ HTML5 ใน Android:
1. เกี่ยวกับคุกกี้ HTML5อาจมีการใช้พารามิเตอร์หลายอย่างเช่นข้อมูลผู้ใช้ในหน้าเว็บ คุณสามารถใส่ข้อมูลนี้ไว้ในคุกกี้ล่วงหน้าได้ คุณสามารถใช้วิธีการต่อไปนี้:
addCookies โมฆะสาธารณะ (บริบทบริบท, WebView webView, URL สตริง) { String url=https://www.xxxx.com/xx/xx/ String protocol = ; String Authority = ; ลอง { URL urlObj = URL ใหม่ (url) ; protocol = urlObj.getProtocol(); อำนาจ = urlObj.getAuthority(); } catch (ข้อยกเว้น e) { e.printStackTrace(); webView.getSettings().getUserAgentString(); webView.getSettings().setUserAgentString(Constant.PROJECT_NAME + / + ParamHandler.getVersion(บริบท) + ( + ua + ; HFWSH) ถ้า (!TextUtils.isEmpty(url) && !TextUtils.isEmpty(โปรโตคอล) && !TextUtils.isEmpty(authority)) { if (protocol.equals(https) && allowance.indexOf(liepin.com) > -1) { CookieSyncManager.createInstance(บริบท); CookieManager cookieManager = CookieManager.getInstance(); (จริง); ลอง { List<String> data = getCookiesString(); (!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= + ค่าคงที่ .VERSION + ;path=/;domain=.XXXX.com); CookieSyncManager.getInstance().sync(); } catch (ข้อยกเว้น e) { LogUtils.e(ข้อยกเว้น: + e.getMessage());
รายการสาธารณะ<String> getCookiesString() { ArrayList data = new ArrayList(); this.clearExpired(); ค่าของคอลเลกชัน = this.mCookies.values(); () ) { SwiftCookie c = (SwiftCookie)var3.next(); data.add(c.toCookieString() } ส่งคืนข้อมูล; -
เพิ่มคุกกี้ก่อน mWebView.loadUrl(Url) และหน้าเว็บสามารถรับค่าพารามิเตอร์ที่เกี่ยวข้องผ่านคุกกี้
2. เกี่ยวกับประเด็นด้านความปลอดภัยของ jsjs มีช่องโหว่ก่อน 4.2.2
ด้วย JavaScript คุณสามารถเข้าถึงทุกสิ่งบนการ์ด SD ของอุปกรณ์ปัจจุบัน แม้แต่ข้อมูลการติดต่อ ข้อความ และอื่น ๆ เอาล่ะ เรามาดูกันว่าข้อผิดพลาดนี้เกิดขึ้นได้อย่างไร
1. WebView เพิ่มวัตถุ JavaScript และแอปพลิเคชันปัจจุบันได้รับอนุญาตให้อ่านและเขียน SDCard นั่นคือ: android.permission.WRITE_EXTERNAL_STORAGE
2. ใน JS คุณสามารถสำรวจวัตถุหน้าต่างเพื่อค้นหาอ็อบเจ็กต์ด้วยเมธอด getClass จากนั้นรับอ็อบเจ็กต์ Runtime ผ่านกลไกการสะท้อน จากนั้นเรียกเมธอดแบบสแตติกเพื่อรันคำสั่งบางคำสั่ง เช่น คำสั่งเพื่อเข้าถึงไฟล์
3. จากนั้นรับสตริงจากอินพุตสตรีมที่ส่งคืนหลังจากดำเนินการคำสั่ง และคุณจะได้รับข้อมูลชื่อไฟล์ ถ้าอย่างนั้นคุณจะทำอะไรก็ได้ตามที่คุณต้องการ มันอันตรายมาก รหัส JS หลักมีดังนี้:
ฟังก์ชั่นดำเนินการ (cmdArgs) { สำหรับ (var obj ในหน้าต่าง) { if (getClass ในหน้าต่าง [obj]) { การแจ้งเตือน (obj); กลับหน้าต่าง [obj] .getClass (). forName (java.lang.Runtime) .getMethod ( getRuntime,null).เรียก(null,null).exec(cmdArgs);สารละลาย: 1. ระบบ Android 4.2 ขึ้นไป
ใน Android 4.2 ขึ้นไป Google ได้ทำการแก้ไขโดยการประกาศ @JavascriptInterface บนวิธีการระยะไกลของ Java ดังที่แสดงในโค้ดต่อไปนี้:
คลาส JsObject { @JavascriptInterface สตริงสาธารณะ toString() { return injectedObject; } } webView.addJavascriptInterface(new JsObject(), injectedObject(, text/html, null); webView.loadUrl(javascript:alert(injectedObject. toString()));2. ระบบที่ต่ำกว่า Android 4.2
ปัญหานี้แก้ไขได้ยากกว่า แต่ก็ไม่ใช่ว่าจะเป็นไปไม่ได้
ก่อนอื่น เราไม่สามารถเรียกใช้เมธอด addJavascriptInterface ได้อีกต่อไป เกี่ยวกับปัญหานี้ สิ่งที่สำคัญที่สุดคือการทราบการทำงานของเหตุการณ์ JS เรารู้ว่ามีการโต้ตอบประเภทต่อไปนี้ระหว่าง JS และ Java เช่น prompt การแจ้งเตือน ฯลฯ
การดำเนินการดังกล่าวจะสอดคล้องกับวิธีการที่เกี่ยวข้องในคลาส WebChromeClient สำหรับ prompt วิธีการที่สอดคล้องกันคือวิธี onJsPrompt การประกาศของวิธีนี้มีดังนี้:
บูลีนสาธารณะ onJsPrompt (มุมมอง WebView, URL สตริง, ข้อความสตริง, ค่าเริ่มต้นของสตริง, ผลลัพธ์ JsPromptResult)
ด้วยวิธีการนี้ JS สามารถส่งข้อมูล (ข้อความ) ไปยัง Java และ Java ยังสามารถส่งข้อมูล (ข้อความ) ไปยัง JS ได้หรือไม่
หลังจากการทดลองและวิเคราะห์แล้ว เราพบวิธีแก้ปัญหาที่เป็นไปได้มากกว่า โปรดดูประเด็นต่อไปนี้:
[1] ให้ JS เรียกใช้เมธอด Javascript ในเมธอดนี้ เมธอด prompt จะถูกเรียก และข้อมูลใน JS จะถูกส่งผ่าน prompt ข้อมูลนี้ควรเป็นข้อความที่มีความหมายที่เรารวมเข้าด้วยกัน ซึ่งอาจรวมถึง: ตัวระบุเฉพาะและชื่อเมธอด . , พารามิเตอร์ ฯลฯ
ในเมธอด onJsPrompt เราจะแยกวิเคราะห์ข้อความที่ส่งเพื่อรับชื่อเมธอด พารามิเตอร์ ฯลฯ จากนั้นเรียกเมธอดที่ระบุผ่านกลไกการสะท้อนกลับเพื่อเรียกเมธอดของอ็อบเจ็กต์ Java
[2] เกี่ยวกับค่าที่ส่งคืน คุณสามารถส่งคืนผ่านพร้อมต์ เพื่อให้สามารถส่งคืนผลลัพธ์การประมวลผลของวิธีการใน Java ไปยัง Js
[3] เราจำเป็นต้องสร้างสคริปต์ JS แบบไดนามิกที่ประกาศวิธีการ Javascript โหลดผ่าน loadUrl และลงทะเบียนในหน้า html รหัสเฉพาะมีดังนี้:
javascript:(function JsAddJavascriptInterface_(){ if (typeof(window.jsInterface)!='unknown') { console.log('window.jsInterface_js_interface_name is existing!!');} else { window.jsInterface = { onButtonClick:function( arg0) { กลับ prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onButtonClick',args:[arg0]})); }, onImageClick:ฟังก์ชั่น(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. ข้อความแจ้งคือสตริงที่เราตกลงกัน ซึ่งมีตัวระบุเฉพาะ MyApp: ตามด้วยสตริงของสตริง JSON ซึ่งประกอบด้วยชื่อเมธอด พารามิเตอร์ ชื่ออ็อบเจ็กต์ ฯลฯ
3. เมื่อ JS เรียก onButtonClick หรือ onImageClick มันจะเรียกกลับไปยังเมธอด onJsPrompt ในเลเยอร์ Java จากนั้นเราจะแยกวิเคราะห์ชื่อเมธอด พารามิเตอร์ ชื่ออ็อบเจ็กต์ จากนั้นจึงเรียกเมธอดนั้นอย่างสะท้อนกลับ
4. window.jsInterface หมายความว่าวัตถุ Js ถูกประกาศบนหน้าต่าง รูปแบบของวิธีการประกาศคือ: ชื่อวิธีการ: ฟังก์ชั่น (พารามิเตอร์ 1, พารามิเตอร์ 2)
3. ปฏิสัมพันธ์ระหว่าง java และ js ใน html51) วิธีที่ 1:
mWebView.getSettings().setJavaScriptEnabled(true);mWebView.addJavascriptInterface(นี่, xxx);
จากนั้นใช้วิธีการต่อไปนี้ในคลาสปัจจุบัน:
@JavascriptInterface โทรกลับโมฆะสาธารณะจาก H5 (สตริงสุดท้าย j) { // TODO }
ชื่อของ callbackFromH5 จะต้องเหมือนกับชื่อเมธอด js ในหน้าเว็บ
Java เรียกวิธี js:
mWebView.loadUrl(String.format(javascript:java2js(0)));//นี่คือ JS สำหรับการเรียก webview บนฝั่ง java
ชื่อเมธอด js จะต้องสอดคล้องกับหน้าเว็บ
2) วิธีที่สอง:
วิธี jsbridge (https://github.com/lzyzsd/JsBridge)
Android JsBridge เป็นเครื่องมือเสริมที่ใช้สร้างสะพานการสื่อสาร (การโทร) ระหว่างโค้ด Java แบบเนทีฟและโค้ด Javascript ของแอป Android
1 แนะนำ jsBridge.jar ในโครงการของเรา
แอนดรอยด์สตูดิโอ:
ที่เก็บ { // ... maven { url https://jitpack.io } } การอ้างอิง { คอมไพล์ '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 > <!-- ปุ่มสาธิตการเรียกใช้ Java เว็บ --> <Button android:id=@+id/button android:layout_width=match_parent android:text=@string/button_name android:layout_height=dp /> <!-- webview สาธิตการเรียกเว็บ 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. โค้ดจาวา
//โหลดหน้าเว็บเซิร์ฟเวอร์ webView.loadUrl(https://www.baidu.com); //ต้องมีชื่อเดียวกันกับฟังก์ชัน js webView.registerHandler(submitFromWeb, new BridgeHandler() { @Override public void handler(String data, CallBackFunction function) { String str =html data return to java: + data; makeText(MainActivity.this, str, LENGTH_SHORT).show( ) ; Log.i(TAG, ตัวจัดการ = sendFromWeb, ข้อมูลจากเว็บ = + data); function.onCallBack( str + หลังจากการประมวลผล Java: + str.substring(,)); // จำลองผู้ใช้เพื่อรับตำแหน่งท้องถิ่น User = new User(); Location location = new Location(); user.location = location; user.name = Bruce; webView.callHandler(functionInJs, new Gson().toJson(user), new CallBackFunction() { @แทนที่สาธารณะเป็นโมฆะ onCallBack (ข้อมูลสตริง) makeText(MainActivity.this หน้าเว็บกำลังรับข้อมูลของคุณ LENGTH_SHORT).show(); webView.send(hello);
webView.callHandler(functionInJs, ข้อมูลจาก Java, CallBackFunction ใหม่ () { @Override public void onCallBack (ข้อมูลสตริง) { // TODO วิธีการสร้างอัตโนมัติ stub Log.i (TAG, ข้อมูลตอบกลับจาก js + data); } }) ;
เจเอสโทรมา
var str1 = document.getElementById(text1).value; var str2 = document.getElementById(text2).value; //เรียกเมธอด java ในเครื่อง window.WebViewJavascriptBridge.callHandler( 'submitFromWeb' , {'param': str} , ฟังก์ชัน ( responseData) { document.getElementById(show).innerHTML = ส่งรับ responseData จาก java, data = + responseData } ); //ลงทะเบียนการฟังเหตุการณ์ document.addEventListener( 'WebViewJavascriptBridgeReady' , function() { callback(WebViewJavascriptBridge) }, false ); //ลงทะเบียนฟังก์ชันการเรียกกลับและเรียกใช้ฟังก์ชันการเริ่มต้น ครั้งแรก bridge.init (ฟังก์ชั่น (ข้อความ, responseCallback) { console.log ('JS ได้รับข้อความ', ข้อความ); var data = { 'Javascript ตอบกลับ: 'Wee!' }; console.log('JS ตอบกลับด้วย', data); responseCallback(data); }); bridge.registerHandler(functionInJs, function(data, responseCallback) { document.getElementById(show) innerHTML = (ข้อมูลจาก Java: = + data); var responseData = Javascript บอกว่ากลับมา aka!; -
4. เกี่ยวกับการเพิ่มประสิทธิภาพของ webView
1. ตั้งค่าโหมดแคช WebView
โมฆะส่วนตัว initWebView() { mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setRenderPriority(RenderPriority.HIGH); mWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); เปิดใช้งาน API การจัดเก็บ DOM ฟังก์ชัน mWebView.getSettings().setDomStorageEnabled().getAbsolutePath()+APP_CACAHE_DIRNAME; // String cacheDirPath = getCacheDir().getAbsolutePath()+Constant.APP_DB_DIRNAME; Log.i(TAG, cacheDirPath=+cacheDirPath); // ตั้งค่าไดเรกทอรีแคชของแอปพลิเคชัน mWebView.getSettings().setAppCachePath(cacheDirPath); //เปิดใช้งานฟังก์ชันแคชแอปพลิเคชัน mWebView.getSettings().setAppCacheEnabled(true);
2. ล้างแคช
/** * ล้างแคช WebView*/ โมฆะสาธารณะ clearWebViewCache(){ //ล้างฐานข้อมูลแคช Webview ลอง { DeleteDatabase(webview.db); DeleteDatabase(webviewCache.db); } catch (ข้อยกเว้น e) { e.printStackTrace(); } //ไฟล์แคช WebView ไฟล์ appCacheDir = ไฟล์ใหม่ (getFilesDir().getAbsolutePath()+APP_CACAHE_DIRNAME); Log.e(TAG, appCacheDir path=+appCacheDir.getAbsolutePath()); ไฟล์ webviewCacheDir = ไฟล์ใหม่ (getCacheDir().getAbsolutePath()+/webviewCache() ); // ลบมุมมองเว็บ ไดเรกทอรีแคช if(webviewCacheDir.exists()){ DeleteFile(webviewCacheDir); } // ลบไดเรกทอรีแคช webview if(appCacheDir.exists()){ DeleteFile(appCacheDir);
3. เมื่อใช้ WebView เพื่อโหลดหน้าเว็บ ไฟล์ทรัพยากรคงที่บางไฟล์ เช่น js/css/images และทรัพยากรอื่นๆ จะมีขนาดค่อนข้างใหญ่ หากโหลดโดยตรงจากเครือข่าย หน้าเว็บจะโหลดช้าลงและใช้การรับส่งข้อมูลมากขึ้น ดังนั้นไฟล์เหล่านี้ควรอยู่ในเนื้อหาและบรรจุมาพร้อมกับแอป
ในการแก้ปัญหานี้ ให้ใช้ฟังก์ชัน shouldInterceptRequest (มุมมอง WebView, URL สตริง) ที่ได้รับจาก API 11 (HONEYCOMB) เพื่อโหลดทรัพยากรในเครื่อง
API 21 เลิกใช้วิธีนี้อีกครั้งและโหลด shouldInterceptRequest ใหม่มากเกินไป พารามิเตอร์ที่จำเป็นจะแทนที่ url ด้วยคำขอ
ตัวอย่างเช่น มีรูปภาพ xxxxx.png รูปภาพนี้ถูกวางไว้ในเนื้อหาแล้ว เมื่อโหลด HTML ภายนอกแล้ว รูปภาพในเนื้อหาจะต้องถูกนำออกและโหลดโดยตรงโดยไม่ต้องรับใหม่จากเครือข่าย แน่นอน คุณสามารถเปลี่ยนลิงค์รูปภาพใน html เป็น file:///android_asset/xxxxx.png ได้
แต่ html นี้ไม่สามารถแชร์ใน Android, ios และ WAP
webView.setWebViewClient (WebViewClient ใหม่ () { @แทนที่สาธารณะ WebResourceResponse shouldInterceptRequest (มุมมอง WebView, String url) { การตอบสนอง WebResourceResponse = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){ response = super.shouldInterceptRequest (ดู ,url); if (url.contains(xxxxx.png)){ ลอง { การตอบสนอง = ใหม่ WebResourceResponse(image/png,UTF-8,getAssets().open(xxxxx.png)); } catch (IOException e) { e.printStackTrace(); } } // return super.shouldInterceptRequest(view , url); ตอบกลับ; } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @แทนที่สาธารณะ WebResourceResponse shouldInterceptRequest (มุมมอง WebView, คำขอ WebResourceRequest) { การตอบสนอง WebResourceResponse = null; response = super.shouldInterceptRequest (ดู, คำขอ); -,getAssets().open(xxxxx.png)); } จับ (IOException e) { e.printStackTrace(); } } ตอบกลับ;
ข้างต้นคือเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการศึกษาของทุกคน ฉันหวังว่าทุกคนจะสนับสนุน VeVb Wulin Network