이번에는 안드로이드와 HTML의 혼합 개발을 사용하는 방법에 대해 설명하고, 안드로이드와 HTML의 혼합 개발을 사용할 때 주의 사항은 무엇인지 알아보겠습니다.
자주 변경되는 페이지를 포함하여 이제 많은 앱에 HTML5 페이지가 포함되어 있습니다. 다음은 Android에서 HTML5 사용에 대한 소개입니다.
1 HTML5 쿠키
사용자 정보와 같은 많은 매개변수가 웹페이지에 사용될 수 있습니다. 이 정보를 쿠키에 미리 넣을 수 있습니다.
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; }
mWebView.loadUrl(Url) 앞에 쿠키를 추가하세요. 웹페이지는 쿠키를 통해 해당 매개변수 값을 얻을 수 있습니다.
2. js 보안 문제 관련
js는 4.2 이전에도 취약점이 있었습니다.
JavaScript를 통해 현재 기기의 SD 카드에 있는 모든 항목, 연락처 정보, 문자 메시지 등에도 액세스할 수 있습니다. 자, 이 오류가 어떻게 발생했는지 살펴보겠습니다.
1. WebView에는 JavaScript 개체가 추가되었으며 현재 애플리케이션에는 SDCard를 읽고 쓸 수 있는 권한이 있습니다. 즉, android.permission.WRITE_EXTERNAL_STORAGE
2. JS에서는 창 개체를 탐색하여 개체를 찾을 수 있습니다. 그런 다음 리플렉션 메커니즘을 사용하여 런타임 개체를 가져온 다음 정적 메서드를 호출하여 파일에 액세스하는 명령과 같은 일부 명령을 실행합니다. 명령을 실행하면 파일 이름 정보를 얻을 수 있습니다. 그렇다면 당신이 원하는 것은 무엇이든 할 수 있습니다. 그것은 매우 위험합니다. 핵심 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("javascript:alert(injectedObject.toString())");
이하 시스템의 경우 이 문제는 해결하기가 더 어렵지만 해결이 불가능하지는 않습니다.
우선, 더 이상 addJavascriptInterface 메소드를 호출할 수 없습니다. 이 문제와 관련하여 가장 중요한 것은 JS 이벤트의 동작을 아는 것입니다. JS와 Java 사이에는 프롬프트, 경고 등과 같은 다음과 같은 유형의 상호 작용이 있다는 것을 알고 있습니다.
이러한 동작은 해당 메서드에 해당합니다. WebChromeClient 클래스에서 해당 메소드는 onJsPrompt 메소드입니다.
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result)
이 메소드를 통해 JS는 정보(텍스트)를 Java로 전송할 수 있습니다. )를 JS에 알리고 이 아이디어에 대한 해결책을 찾을 수 있을까요?
몇 가지 시행착오와 분석 끝에 우리는 다음 몇 가지 사항을 살펴보시기 바랍니다.
[1] JS가 Javascript 메소드를 호출하도록 합니다. 이 메소드에서는 프롬프트 메소드가 호출되고 JS가 로드됩니다. 정보는 프롬프트를 통해 전달됩니다. 이 정보는 특정 식별자, 메서드 이름, 매개 변수 등을 포함할 수 있는 의미 있는 텍스트여야 합니다.
onJsPrompt 메소드에서는 전달된 텍스트를 구문 분석하고 메소드 이름, 매개변수 등을 가져온 다음 리플렉션 메커니즘을 통해 지정된 메소드를 호출하여 Java 객체의 메소드를 호출합니다.
【2】반환 값은 프롬프트를 통해 반환할 수 있으므로 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 = { 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]})); }, }; } } )()
지침:
1. 위 코드에서 등록할 객체의 이름은 onButtonClick(arg0), onImageClick(arg0, arg1, arg2) 두 가지 메소드를 등록합니다. 반환값이 있는 경우 return을 추가합니다.
2 프롬프트는 우리가 동의한 문자열로, 특정 식별자 MyApp:과 그 뒤에 메서드 이름, 매개변수, 객체 이름 등이 포함된 JSON 문자열 문자열이 포함됩니다.
3. JS가 onButtonClick 또는 onImageClick을 호출하면 Java 계층의 onJsPrompt 메서드를 다시 호출합니다. 그런 다음 메서드 이름, 매개 변수, 개체 이름을 구문 분석한 다음 반사적으로 메서드를 호출합니다.
4. window.jsInterface는 Js 객체가 창에 선언되었음을 의미합니다. 메서드 이름: 함수(매개변수 1, 매개변수 2)
3 html5에서 java와 js 간의 상호 작용.1), 방법 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" > <!-- 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中文网其它相关文章!
推荐阅读:
위 내용은 안드로이드와 HTML의 혼합 개발을 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!