首頁  >  文章  >  web前端  >  如何使用android與HTML混合開發

如何使用android與HTML混合開發

php中世界最好的语言
php中世界最好的语言原創
2018-06-13 14:28:302855瀏覽

這次帶給大家如何使用android與HTML混合開發,使用android與HTML混合開發的注意事項有哪些,以下就是實戰案例,一起來看一下。

現在很多的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);
                 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)之前加入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("javascript:alert(injectedObject.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 = {          
              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,上面程式碼中的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" >  
    
      <!-- 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中文网其它相关文章!

推荐阅读:

CSS实战项目中书写规范与顺序

CSS层叠机制使用详解

以上是如何使用android與HTML混合開發的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn