欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解android与HTML混合开发总结

程序员文章站 2022-06-14 17:26:12
现在很多的 APP中会嵌套HTML5的页面,这篇文章主要介绍了详解android与HTML混合开发总结的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧... 18-06-06...

现在很多的 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;  
             }  
 }  

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。