多くの APP には、頻繁に変更される HTML5 ページが埋め込まれています。一部のページでは、HTML5 での js との対話にネイティブ Java が必要です。ここでは、Android での HTML5 の使用について説明します。
1. HTML5 CookieについてWeb ページでは、ユーザー情報などの多くのパラメータが使用される場合があります。この情報を事前に Cookie に含めることができます。
public static void addCookies(Context context, WebView webView, String url) { String url=https://www.xxxx.com/xx/xx/ String プロトコル = ; URL urlObj = 新しい URL(url) ; プロトコル = urlObj.getProtocol(); 権限 = urlObj.getAuthority(); } 文字列 ua = webView.getSettings().getUserAgentString(); webView.getSettings().setUserAgentString(Constant.PROJECT_NAME + / + ParamHandler.getVersion(context) + ( + ua + ; HFWSH)); if (!TextUtils.isEmpty(url) !TextUtils.isEmpty(プロトコル) && !TextUtils.isEmpty(authority)) { if (protocol.equals(https) && authoritative.indexOf(liepin.com) > -1) { CookieSyncManager.createInstance(context); CookieManager cookieManager = CookieManager.getInstance(); (true); {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());
public List<String> getCookiesString() { ArrayList データ = new ArrayList(); this.clearExpired(); コレクション値 = this.mCookies.values(); () ) { SwiftCookie c = (SwiftCookie)var3.next() data.add(c.toCookieString()); } }
mWebView.loadUrl(Url) の前に Cookie を追加すると、Web ページは Cookie を通じて対応するパラメータ値を取得できます。
2. jsのセキュリティ問題についてjs には 4.2 より前に脆弱性がありました
JavaScript を使用すると、連絡先情報やテキスト メッセージなど、現在のデバイスの SD カード上のあらゆるものにアクセスできます。さて、このエラーがどのように発生したかを見てみましょう。
1. WebView は JavaScript オブジェクトを追加し、現在のアプリケーションには SDCard の読み取りと書き込みの権限、つまり android.permission.WRITE_EXTERNAL_STORAGE が与えられます。
2. JS では、ウィンドウ オブジェクトをトラバースして getClass メソッドでオブジェクトを見つけ、リフレクション メカニズムを通じて Runtime オブジェクトを取得して、静的メソッドを呼び出してファイルにアクセスするコマンドなどのいくつかのコマンドを実行できます。
3. コマンド実行後に返される入力ストリームから文字列を取得すると、ファイル名情報を取得できます。そうなるとやりたい放題になってしまい、とても危険です。コアの JS コードは次のとおりです。
functionexecute(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)(javascript:alert(injectedObject. toString()));2. Android 4.2未満のシステム
この問題を解決するのはさらに困難ですが、不可能ではありません。
まず第一に、addJavascriptInterface メソッドを呼び出すことはできなくなりました。この問題に関して最も重要なことは、JS イベントのアクションを知ることです。JS と Java の間には、プロンプト、アラートなどの次の種類の対話があることがわかっています。
このようなアクションは、WebChromeClient クラスの対応するメソッドに対応します。プロンプトの場合、対応するメソッドは onJsPrompt メソッドです。このメソッドの宣言は次のとおりです。
public boolean onJsPrompt(WebView ビュー、文字列 URL、文字列メッセージ、文字列defaultValue、JsPromptResult 結果)
この方法により、JS は Java に情報 (テキスト) を渡すことができ、Java も情報 (テキスト) を JS に渡すことができます。このアイデアに対する解決策は見つかるでしょうか。
いくつかの試行と分析の結果、より実現可能な解決策が見つかりました。次の点を参照してください。
[1] JS に Javascript メソッドを呼び出します。このメソッドでは、プロンプト メソッドが呼び出され、JS 内の情報はプロンプトを介して渡されます。この情報には、特定の識別子とメソッド名が含まれる場合があります。 、パラメータなど。
onJsPrompt メソッドでは、渡されたテキストを解析してメソッド名、パラメータなどを取得し、リフレクション メカニズムを通じて指定されたメソッドを呼び出して Java オブジェクトのメソッドを呼び出します。
[2] 戻り値については、プロンプトで返すことができるので、Javaでのメソッドの処理結果をJsに返すことができます。
[3] Javascript メソッドを宣言する JS スクリプトを動的に生成し、loadUrl を通じてロードして、HTML ページに登録する必要があります。具体的なコードは次のとおりです。
javascript:(function JsAddJavascriptInterface_(){ if (typeof(window.jsInterface)!='未定義') { console.log('window.jsInterface_js_interface_name は存在します!!');} else { window.jsInterface = { onButtonClick:function( arg0) { 戻り値プロンプト('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onButtonClick',args:[arg0]})) }, onImageClick:function(arg0,arg1,arg2) {プロンプト('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onImageClick',args:[arg0,arg1,arg2]}); }, } } );
例証します:
1. 上記コードの jsInterface は登録するオブジェクトの名前で、onButtonClick(arg0) と onImageClick(arg0, arg1, arg2) の 2 つのメソッドを登録します。戻り値がある場合は 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 の名前は、Web ページの js メソッド名と同じである必要があります。
Java は js メソッドを呼び出します。
mWebView.loadUrl(String.format(javascript:java2js(0)));//Java 側で WebView を呼び出すための JS は次のとおりです
js メソッド名は Web ページと一致している必要があります
2) 方法 2:
jsbridge メソッド (https://github.com/lzyzsd/JsBridge)
Android JsBridge は、Android アプリのネイティブ Java コードと JavaScript コード間の通信 (呼び出し) ブリッジを構築するために使用される補助ツールです。
1 jsBridge.jar をプロジェクトに導入します
Androidスタジオ:
リポジトリ { // ... maven { url https://jitpack.io } } 依存関係 { コンパイル 'com.github.lzyzsd:jsbridge:1.0.4' }
2. レイアウトファイル
<?xml version=1.0coding=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 による 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コード
//サーバー Web ページをロードします。 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、ハンドラー = submitFromWeb、Web からのデータ = + データ); 、 Java 処理後: + str.substring(,)); } }); ユーザーをシミュレートしてローカルの場所を取得します user = new User() location = new 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, Web ページはあなたの情報を取得しています, LENGTH_SHORT).show() } });
webView.callHandler(functionInJs, Java からのデータ, new CallBackFunction() { @Override public void onCallBack(String data) { // TODO 自動生成されたメソッド スタブ Log.i(TAG, 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 = 送信 Java からの応答データを取得、データ = + responseData } ); //イベントリスニングを登録します document.addEventListener( 'WebViewJavascriptBridgeReady' , function() { callback(WebViewJavascriptBridge) }, false ); // 接続時にコールバック関数を登録し、初期化関数を呼び出します connectWebViewJavascriptBridge(function(bridge) {初めて Bridge.init(function(message, responseCallback) { console.log('JS がメッセージを取得しました', message); var data = { 'Javascript応答': 'Wee!' }; console.log('JS 応答', data); Bridge.registerHandler(functionInJs, function(data, responseCallback) { document.getElementById(show); innerHTML = (Java からのデータ: = + data); var responseData = Javascript は、responseCallback(responseData) と返します。 })
4. webViewの最適化について
1. WebViewキャッシュモードを設定する
private void initWebView() { mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); DOM ストレージ API を有効にするFunction mWebView.getSettings().setDomStorageEnabled(true); //データベースストレージ API 関数 mWebView.getSettings().setDatabaseEnabled(true); // String cacheDirPath = getCacheDir().getAbsolutePath()+Constant.APP_DB_DIRNAME; Log.i(TAG,cacheDirPath=+cacheDirPath); //データベース キャッシュ パスを設定します。 mWebView.getSettings().setDatabasePath(cacheDirPath); //アプリケーション キャッシュ ディレクトリを設定します。 mWebView.getSettings().setAppCachePath(cacheDirPath); //アプリケーション キャッシュを有効にする function 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()); ファイル webviewCacheDir = new File(getCacheDir().getAbsolutePath()+/webviewCache); ); //Webビューを削除しますキャッシュ ディレクトリ if(webviewCacheDir.exists()){ deleteFile(webviewCacheDir); } //WebView キャッシュ ディレクトリを削除します if(appCacheDir.exists()){ deleteFile(appCacheDir) } }
3. WebView を使用して Web ページを読み込む場合、js/css/image やその他のリソースなどの一部の固定リソース ファイルがネットワークから直接読み込まれると、ページの読み込みが遅くなり、より多くのトラフィックが消費されます。したがって、これらのファイルはアセットに配置し、アプリにパッケージ化する必要があります。
この問題を解決するには、API 11 (HONEYCOMB) で提供される shouldInterceptRequest(WebView view, String url) 関数を使用してローカル リソースを読み込みます。
API 21 ではこのメソッドが再び非推奨になり、新しい shouldInterceptRequest がオーバーロードされ、URL が request に置き換えられました。
たとえば、xxxxx.png という画像があります。この画像は外部 HTML がロードされているため、ネットワークから再取得せずに、アセット内の画像を直接取り出してロードする必要があります。もちろん、HTML 内の画像リンクを file:///android_asset/xxxxx.png に変更することもできます。
ただし、この HTML は Android、iOS、WAP では共有できません。
webView.setWebViewClient(new WebViewClient() { @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { WebResourceResponse 応答 = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){ 応答 = super. shouldInterceptRequest(view ,url); if (url.contains(xxxxx.png)){ 試してください{ response = new WebResourceResponse(image/png,UTF-8,getAssets().open(xxxxx.png)) } catch (IOException e) { e.printStackTrace() } } // return super.ShouldInterceptRequest(view) 、url); 応答を返します。 WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { WebResourceResponse 応答 = null; 応答 = super.ShouldInterceptRequest(view, request); if (url.contains(xxxxx.png)){ try { 応答 = new WebResourceResponse(image/png,UTF) -,getAssets().open(xxxxx.png)); } catch (IOException e) { e.printStackTrace() } } 応答を返します。
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。また、VeVb Wulin Network をご支援いただければ幸いです。