Maison  >  Article  >  interface Web  >  Comment utiliser le développement mixte Android et HTML

Comment utiliser le développement mixte Android et HTML

php中世界最好的语言
php中世界最好的语言original
2018-06-13 14:28:302767parcourir

Cette fois, je vais vous montrer comment utiliser le développement mixte d'Android et HTML, et quelles sont les précautions à prendre pour utiliser le développement mixte d'Android et HTML. Ce qui suit est un cas pratique, jetons un coup d'œil.

De nombreuses applications contiennent désormais des pages HTML5, telles que celles qui changent fréquemment. Certaines pages nécessitent Java natif pour interagir avec js en HTML5. Voici une introduction à l'utilisation de HTML5 dans Android :

.

1. À propos des cookies HTML5

De nombreux paramètres tels que les informations utilisateur peuvent être utilisés dans la page Web. Vous pouvez mettre ces informations dans les cookies à l'avance. , vous pouvez utiliser les méthodes suivantes :

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;
 }

Ajoutez un cookie avant mWebView.loadUrl(Url), et la page Web peut obtenir la valeur du paramètre correspondant via le cookie.

2. Concernant les problèmes de sécurité de js

js avait des vulnérabilités avant la version 4.2

Grâce à JavaScript, vous pouvez accéder à l'appareil actuel Tout ce qui se trouve sur la carte SD, même les informations de contact, les messages texte, etc. Ok, regardons comment cette erreur s'est produite.

1. WebView a ajouté un objet JavaScript et l'application actuelle a l'autorisation de lire et d'écrire la carte SD, c'est-à-dire : android.permission.WRITE_EXTERNAL_STORAGE

2. window et recherchez l'existence de l'objet méthode " getClass", puis obtenez l'objet Runtime via le mécanisme de réflexion, puis appelez des méthodes statiques pour exécuter certaines commandes, telles que les commandes d'accès aux fichiers

3, et. puis renvoyez l'entrée après avoir exécuté la commande. Si vous obtenez la chaîne dans le flux, vous pouvez obtenir les informations sur le nom du fichier. Après, tu peux faire ce que tu veux, c'est tellement dangereux. Le code JS de base est le suivant :

 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);  
          }  
      }  
 }

Solution :

1, système Android 4.2 ou supérieur

sur Android 4.2 et supérieur, Google a apporté des corrections en déclarant une @JavascriptInterface sur la méthode distante de Java, comme le code suivant :

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, pour les systèmes inférieurs à Android 4.2

Ce problème est difficile à résoudre, mais il n'est pas impossible.

Tout d'abord, nous ne pouvons définitivement plus appeler la méthode addJavascriptInterface. Concernant ce problème, le plus important est de connaître l'action de l'événement JS. Nous savons qu'il existe les types d'interactions suivants entre JS et Java, telles que l'invite, l'alerte, etc. Des actions telles que

le seront. tous correspondent à la classe WebChromeClient. La méthode correspondante, pour prompt, est la méthode onJsPrompt La déclaration de cette méthode est la suivante :

public boolean onJsPrompt(WebView view, String url, String message, 
String defaultValue, JsPromptResult result)

Grâce à cette méthode, JS peut transférer des informations (texte) vers Java. , et Java peut également Les informations (texte) sont transmises à JS. Pouvons-nous trouver une solution pour éclairer cette idée ?

Après quelques essais et analyses, nous avons trouvé une solution plus réalisable. Veuillez examiner les quelques points suivants :

[1] Laissez JS appeler une méthode Javascript. Dans cette méthode, appelez l'invite. La méthode transmet les informations dans JS via une invite. Ces informations doivent être un texte significatif que nous combinons, qui peut inclure : des identifiants spécifiques, des noms de méthodes, des paramètres, etc.

Dans la méthode onJsPrompt, nous analysons le texte transmis, obtenons le nom de la méthode, les paramètres, etc., puis appelons la méthode spécifiée via le mécanisme de réflexion, appelant ainsi la méthode de l'objet Java.

[2] Concernant la valeur de retour, vous pouvez la renvoyer via prompt, afin que les résultats du traitement de la méthode en Java puissent être renvoyés à Js.

【3】Nous devons générer dynamiquement un script JS qui déclare la méthode Javascript, le charger via loadUrl et l'enregistrer dans la page html. Le code spécifique est le suivant :

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]}));  
             },  
         };  
     }  
 }  
 )()
<.>Instructions :

1. Le jsInterface dans le code ci-dessus est le nom de l'objet à enregistrer, onButtonClick(arg0) et onImageClick(arg0, arg1, arg2). une valeur de retour, ajoutez return .

2. L'invite est la chaîne sur laquelle nous nous sommes mis d'accord, qui contient l'identifiant spécifique MyApp :, suivi d'une chaîne de chaînes JSON, qui comprend les noms de méthodes, les paramètres, les noms d'objets, etc.

3. Lorsque JS appelle onButtonClick ou onImageClick, il rappellera la méthode onJsPrompt dans la couche Java. Nous analysons ensuite le nom de la méthode, les paramètres, le nom de l'objet, puis reflétons l'appel de la méthode.

4. window.jsInterface signifie qu'un objet Js est déclaré sur la fenêtre. La forme de la méthode déclarée est : nom de la méthode : fonction (paramètre 1, paramètre 2)

3. Interaction entre java et js en html5

1), première méthode :

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层叠机制使用详解

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn