How to use mixed development of android and HTML

php中世界最好的语言
Release: 2018-06-13 14:28:30
Original
2839 people have browsed it

This time I will show you how to use mixed development of android and HTML, and what are the precautions for using mixed development of android and HTML. The following is a practical case, let's take a look.

Many APPs now have HTML5 pages embedded in them, such as those that change frequently. Some pages require native Java to interact with js in HTML5. Here is an introduction to the use of HTML5 in android:

1. About HTML5 cookies

Many parameters such as user information may be used in web pages. You can put this information in cookies in advance. , you can use the following methods:

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()); 
         } 
       } 
     } 
   }
Copy after login
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;
 }
Copy after login

Add a cookie before mWebView.loadUrl(Url), and the web page can get the corresponding parameter value through the cookie.

2. Regarding the security issues of js

js had vulnerabilities before 4.2

The current device can be accessed through JavaScript Anything on the SD card, even contact information, text messages, etc. Okay, let's take a look at how this error occurred.

1, WebView has added a JavaScript object, and the current application has the permission to read and write SDCard, that is: android.permission.WRITE_EXTERNAL_STORAGE

2, You can traverse the window object in JS to find the existence of " getClass" method object, and then obtain the Runtime object through the reflection mechanism, and then call static methods to execute some commands, such as commands to access files.

3, and then return the input after executing the command If you get the string in the stream, you can get the file name information. Then you can do whatever you want, it's so dangerous. The core JS code is as follows:

 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);  
          }  
      }  
 }
Copy after login

Solution:

1, Android 4.2 or above system

On Android 4.2 or above Yes, Google has made a correction by declaring a @JavascriptInterface on Java's remote method, such as the following code:

class JsObject {  
    @JavascriptInterface  
    public String toString() { return "injectedObject"; }  
 }  
 webView.addJavascriptInterface(new JsObject(), "injectedObject");  
 webView.loadData("", "text/html", null);  
 webView.loadUrl("javascript:alert(injectedObject.toString())");
Copy after login

2, for systems below Android 4.2

this The problem is more difficult to solve, but it is not impossible.

First of all, we definitely can no longer call the addJavascriptInterface method. Regarding this issue, the most important thing is to know the action of JS event. We know that there are the following types of interactions between JS and Java, such as prompt, alert, etc.

Such actions will all correspond to the WebChromeClient class The corresponding method, for prompt, is the onJsPrompt method. The declaration of this method is as follows:

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

Through this method, JS can transfer information (text) to Java, and Java can also transfer information ( Text) is passed to JS. Can we find a solution to inform this idea?

After some trial and analysis, we found a more feasible solution. Please look at the following few points:

[1] Let JS call a Javascript method. In this method, call The prompt method passes the information in JS through prompt. This information should be a meaningful text that we combine, which may include: specific identifiers, method names, parameters, etc.

In the onJsPrompt method, we parse the passed text to get the method name, parameters, etc., and then call the specified method through the reflection mechanism to call the method of the Java object.

[2] Regarding the return value, you can return it through prompt, so that the processing results of the method in Java can be returned to Js.

[3] We need to dynamically generate a JS script that declares the Javascript method, load it through loadUrl, and register it in the html page. The specific code is as follows:

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]}));  
             },  
         };  
     }  
 }  
 )()
Copy after login

Instructions:

1. The jsInterface in the above code is the name of the object to be registered. It registers two methods, onButtonClick(arg0) and onImageClick(arg0, arg1, arg2). If there is a return value, add return.

2. The prompt is the string we agreed on, which contains the specific identifier MyApp:, followed by a string of JSON strings, which includes method names, parameters, object names, etc.

3. When JS calls onButtonClick or onImageClick, it will call back to the onJsPrompt method in the Java layer. We then parse out the method name, parameters, object name, and then call the method reflectively.

4, window.jsInterface means that a Js object is declared on the window. The form of the method declaration is: method name: function (parameter 1, parameter 2)

3. Interaction between java and js in html5

1), method one:

mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(this, "xxx");
Copy after login

然后在当前类中实现以下方法:

@JavascriptInterface
  public void callbackFromH5(final String j) {
    //TODO
  }
Copy after login

callbackFromH5的名字必须和网页中的js方法名一样

Java调用js方法:

mWebView.loadUrl(String.format("javascript:java2js(0)"));//这里是java端调用webview的JS
Copy after login

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'
  }
Copy after login

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>
Copy after login

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");
Copy after login
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);  
                 }  
   
             });
Copy after login

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);  
            });  
        })
Copy after login

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);
Copy after login

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);  
             }  
         }
Copy after login

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;  
             }  
 }
Copy after login

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

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

CSS层叠机制使用详解

The above is the detailed content of How to use mixed development of android and HTML. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!