GVKun编程网logo

WKWebView与js交互之完美解决方案(wkwebview_js与oc交互实例)

23

如果您想了解WKWebView与js交互之完美解决方案的相关知识,那么本文是一篇不可错过的文章,我们将对wkwebview_js与oc交互实例进行全面详尽的解释,并且为您提供关于AndroidWebV

如果您想了解WKWebView与js交互之完美解决方案的相关知识,那么本文是一篇不可错过的文章,我们将对wkwebview_js与oc交互实例进行全面详尽的解释,并且为您提供关于Android WebView与Js交互、Android WebView与JS交互全面详解(小结)、android webview与js交互时遇到的问题解决、Android webview与js交换JSON对象数据示例的有价值的信息。

本文目录一览:

WKWebView与js交互之完美解决方案(wkwebview_js与oc交互实例)

WKWebView与js交互之完美解决方案(wkwebview_js与oc交互实例)

 随着H5功能愈发的强大,没进行过混合开发的小伙们都不好意思说自己能够独立进行iOS的app开发,在iOS7操作系统下,常用的native,js交互框架有easy-js,WebViewJavascriptBridge,以及结合javaScriptCore的框架。easy-js 很早的一个框架了,已经好几年没有人维护了,里面有很多隐藏很深的坑,新人如果没有用过的话,建议不要再用了。主要是js新建一个隐藏的iframe,通过拦截url的形式进行交互。WebViewJavascriptBridge是网上很火的一个交互库,使用的人较多,但是对于js基础较弱的小伙伴来说,底层不是太好理解。底层和easy-js一样都是通过创新一个隐藏的iframe通过截取url来进行交互。缺点这里就暂时不说了,用的不多,体会不够深刻。嘿嘿。javaScriptCore中JSExport进行交互,这种方式比较简单易懂,也是我个人比较推崇 的一种方式。如果app最低版本操作系统是iOS7的小伙伴,建议自己搜一下相关知识点哦。但是WKWebView不能够利用javaScriptCore交互,是不是很坑爹哦,呜呜。 
   由于自己去年的强力推动,今年我们的一系列app最低操作系统都是从iOS8开始,所以今天重点和大家分享一下我是如何实现WKWebView与js交互的。 
js发送消息给native的代理方法是: 
方法1,

- (void)userContentController:(WKUserContentController *)userContentController
      didReceiveScriptMessage:(WKScriptMessage *)message
  •  

主要是js方法消息调用native的方法。

native调用js方法传递参数主要通过如下方法: 
方法2

[_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) {


    }];
  •  

相信这两个方法大家在网上已经看到过很多遍了,貌似可以解决与js交互的问题,实则不然,这两个方法并没有真正的帮我们解决交互的问题。因为在js发送消息给native的时候,有时候需要通过回调来获取相应的信息,仅仅靠上面两个方法是没有办法满足的,也可能会有小伙伴说,先通过上面方法1发送消息个native然后,再使用方法2发送消息给js不就好了么,不行的,这样的话,js调用native方法时,和native发送消息时候并没有时间先后的约定,不能保证,js获取相关返回值的时候,一定能拿到值。 
   我一直在想如何能有一个与js调用native函数相关连的回调呢。功夫不负有心人,偶然看到H5 ,DOM可以绑定事件,后来想能不能绑定自定义事件呢,一搜果然可以,参考博客如下: 
http://www.zhangxinxu.com/wordpress/2012/04/js-dom自定义事件/ 
顺着这个思路,每一次js方法调用native方法的时候,我都为这个js方法绑定一个对应的callBack方法,这样的话,同时在发送的消息中告诉native需要回调,native方法就可以执行完相关的方法后,直接回调相应的 callBack方法,并携带相关的参数,这样就可以完美的进行交互了。这里我主要写了一个JKEventHandler的js类,脚本内容如下:

var JKEventHandler ={

callNativeFunction:function(functionString,params,callBack){

    var methodName = (functionString.replace(/function\s?/mi,"").split("("))[0];
    var callBackName =methodName + ''CallBack'';
    var message;

    if(!callBack){

        message = {''methodName'':methodName,''params'':params};
        window.webkit.messageHandlers.JKEventHandler.postMessage(message);

    }else{
        message = {''methodName'':methodName,''params'':params,''callBackName'':callBackName};
        if(!Event._listeners[callBackName]){
        Event.addEvent(callBackName, function(data){

                       callBack(data);

                       });
        }
        window.webkit.messageHandlers.JKEventHandler.postMessage(message);
    }


},

callBack:function(callBackName,data){

    Event.fireEvent(callBackName,data);

},

removeAllCallBacks:function(data){
    Event._listeners ={};
}

};



var Event = {

_listeners: {},


addEvent: function(type, fn) {
    if (typeof this._listeners[type] === "undefined") {
        this._listeners[type] = [];
    }
    if (typeof fn === "function") {
        this._listeners[type].push(fn);
    }

    return this;
},


fireEvent: function(type,param) {
    var arrayEvent = this._listeners[type];
    if (arrayEvent instanceof Array) {
        for (var i=0, length=arrayEvent.length; i<length; i+=1) {
            if (typeof arrayEvent[i] === "function") {
                arrayEvent[i](param);
            }
        }
    }

    return this;
},

removeEvent: function(type, fn) {
    var arrayEvent = this._listeners[type];
    if (typeof type === "string" && arrayEvent instanceof Array) {
        if (typeof fn === "function") {
            for (var i=0, length=arrayEvent.length; i<length; i+=1){
                if (arrayEvent[i] === fn){
                    this._listeners[type].splice(i, 1);
                    break;
                }
            }
        } else {
            delete this._listeners[type];
        }
    }

    return this;
}
};


callNativeFunction: 这个函数主要是js调用native方法的时候进行调用的。如果有回调的话,需要在传入的参数中写出来哦。 
callBack:主要是用来触发对应js方法回调函数的。

removeAllCallBacks: 主要是在要销毁所有的callback事件时调用的。 
以我的demo为例

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>iOS and Js</title>
    <style type="text/css">
      * {
        font-size: 40px;
      }
    </style>
  </head>

  <body>

    <div>
      <h1>教你如何用H5与OC进行交互,并且把H5输入的内容显示到当前的控制器上</h1><br/>
      <div><input type="button" value="sendInfoToNative" onclick="sendInfoToNative()"></div>
      <br/>
      <div><input type="button"  value="getInfoFromNative" onclick="getInfoFromNative()"></div>
      <br/>
       <div><input type="button" value="cleanAllCallBacks" onclick="cleanAllCallBacks()"></div>
       <br/>
      <div><input type="button" value="点击触发JS方法(callJsConfirm)" onclick="callJsConfirm()"></div><br/>
    </div>
    <br/>
    <div>
      <div><input type="button" value="点击触发JS输入方法(callJsInput) " onclick="callJsInput()"></div><br/>
    </div>

    <br/>
    <div id="SwiftDiv">
      <span id="jsParamFuncSpan"></span>
    </div>

    <script type="text/javascript">
      function sendInfoToNative() {


        var params ={''Phone'':''13566668888''};

       JKEventHandler.callNativeFunction(arguments.callee.toString(),params,null);

      }

    function getInfoFromNative(){

     var params = {''Phone'':''13933333333''};
     JKEventHandler.callNativeFunction(arguments.callee.toString(),params,function(data){
                                      alert(data);
                                      });


    }

    function callJsConfirm() {
      if (confirm(''confirm'', ''Objective-C call js to show confirm'')) {
        document.getElementById(''jsParamFuncSpan'').innerHTML
        = ''true'';
      } else {
        document.getElementById(''jsParamFuncSpan'').innerHTML
        = ''false'';
      }

    }

    function callJsInput() {
      var response = prompt(''Hello'', ''请输入你的名字:'');
      document.getElementById(''jsParamFuncSpan'').innerHTML = response;
      alert (response);

    }

    function cleanAllCallBacks(){

    JKEventHandler.removeAllCallBacks();

    }
      </script>
  </body>
</html>
  •  

在js中调用getInfoFromNative 这个方法既可以发送参数给native,同时也可以从native获取参数 
具体实现:

 function getInfoFromNative(){

     var params = {''Phone'':''13933333333''};
     JKEventHandler.callNativeFunction(arguments.callee.toString(),params,function(data){
                                      alert(data);
                                      });


    }

同时呢,通过JKEventHandler的转换,在JKEventHandler+Demo.m文件中有一个同名的函数,只不过是参数不一样:

- (void)getInfoFromNative:(id)params :(void(^)(id response))callBack{
    NSLog(@"params %@",params);
    NSString *str = @"''Hi Jack!''";
    callBack(str);

}
  •  

就这样,我在native方法里可以获取到js传递来的参数,同时通过callBack我也可以传递参数给js。 
另外呢在JKEventHandler文件里,我写了一个事件分发函数,主要就是为了解决多个js方法交互的问题。感兴趣的小伙伴可以看看我的demo哦。 
另外需要大家注意的是,WKWebView所在的ViewController即将被销毁的时候,也就是WKWebView即将被销毁的时候,一定要记得调用如下方法销毁所有的callback事件哦:

 [_webView evaluateJavaScript:@"JKEventHandler.removeAllCallBacks();" completionHandler:^(id _Nullable data, NSError * _Nullable error) {


    }];//删除所有的回调事件
  •  

俗话说的话,代码就是程序员最好的老师,这里我就不多说了,Demo地址 
如何使用了cocoapod,可以:

pod "JKWKWebViewHandler"

Android WebView与Js交互

Android WebView与Js交互

如果是捕获通过http获取的html网页中的连接,可以使用jsoup进行解析获取。示例代码如下:

//通过url字符串,获取html内容,并解析返回一个Document对象
Document doc = Jsoup.parse(url);


//查找所有的a标签
Elements links=content.getElementsByTag("a");


//遍历links元素,获取所有的链接
for(Elementlink:links){
    //取得a标签中“href”属性的值,即链接
    String linkHref=link.attr("href");


    //取得a标签的内容
    String linkText=link.text();


    //在此对链接地址和内容进行操作和存储
}

 
 
 

 

 

  
  
这样就可以取得html中所有的链接地址和对应的内容了。

Android WebView与JS交互全面详解(小结)

Android WebView与JS交互全面详解(小结)

Android 和 H5 都是移动开发应用的非常广泛。市面上很多App都是使用Android开发的,但使用Android来开发一些比较复杂附属类,提示性的页面是得不偿失的。而H5具有开发速度快,更新不用依赖于App的更新,只需要服务端更新相应的页面即可,所以,App和H5页面相结合就显得尤为重要。而android和H5都不可能每次都是独立存在的,而是相互影响也相互的调用,获取信息等,例如,H5页面要获取App中的用户的基本信息,或者App端要操作H5页面等,下面来看看这两是怎么交互的

目录


1. 交互方式总结

Android与JS通过WebView互相调用方法,实际上是:

  1. Android去调用JS的代码
  2. JS去调用Android的代码

二者沟通的桥梁是WebView

对于Android调用JS代码的方法有2种:

  1. 通过WebView的loadUrl()
  2. 通过WebView的evaluateJavascript()

对于JS调用Android代码的方法有3种:

  1. 通过WebView的addJavascriptInterface()进行对象映射
  2. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
  3. 通过 WebChromeClient的onjsAlert()、onjsConfirm()、onjsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt()消息

2. 具体分析

2.1 Android通过WebView调用 JS 代码

方式1:通过WebView的loadUrl()

实例介绍:点击Android按钮,即调用WebView JS(文本名为javascript)中callJS()

具体使用:

步骤1:将需要调用的JS代码以.html格式放到src/main/assets文件夹里

为了方便展示,本文是采用Andorid调用本地JS代码说明;

实际情况时,Android更多的是调用远程JS代码,即将加载的JS代码路径改成url即可

需要加载JS代码:javascript.html

// 文本名:javascript
<!DOCTYPE html>
<html>

  <head>
   <Meta charset="utf-8">
   <title>Carson_Ho</title>

// JS代码
   <script>
// Android需要调用的方法
  function callJS(){
   alert("Android调用了JS的callJS方法");
  }
</script>

  </head>

</html>

步骤2:在Android里通过WebView设置调用JS代码

public class MainActivity extends AppCompatActivity {

  WebView mWebView;
  Button button;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mWebView =(WebView) findViewById(R.id.webview);

    WebSettings webSettings = mWebView.getSettings();

    // 设置与Js交互的权限
    webSettings.setJavaScriptEnabled(true);
    // 设置允许JS弹窗
    webSettings.setJavaScriptCanopenWindowsAutomatically(true);

    // 先载入JS代码
    // 格式规定为:file:///android_asset/文件名.html
    mWebView.loadUrl("file:///android_asset/javascript.html");

    button = (Button) findViewById(R.id.button);


    button.setonClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        // 必须另开线程进行JS方法调用(否则无法调用)
        mWebView.post(new Runnable() {
          @Override
          public void run() {

            // 注意调用的JS方法名要对应上
            // 调用javascript的callJS()方法
            mWebView.loadUrl("javascript:callJS()");
          }
        });

      }
    });

    // 由于设置了弹窗检验调用结果,所以需要支持js对话框
    // webview只是载体,内容的渲染需要使用webviewChromClient类去实现
    // 通过设置WebChromeClient对象处理JavaScript的对话框
    //设置响应js 的Alert()函数
    mWebView.setWebChromeClient(new WebChromeClient() {
      @Override
      public boolean onjsAlert(WebView view,String url,String message,final JsResult result) {
        AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);
        b.setTitle("Alert");
        b.setMessage(message);
        b.setPositiveButton(android.R.string.ok,new DialogInterface.OnClickListener() {
          @Override
          public void onClick(DialogInterface dialog,int which) {
            result.confirm();
          }
        });
        b.setCancelable(false);
        b.create().show();
        return true;
      }

    });


  }
}

效果图

特别注意:JS代码调用一定要在 onPageFinished() 回调之后才能调用,否则不会调用。

onPageFinished()属于WebViewClient类的方法,主要在页面加载结束时调用

方式2:通过WebView的evaluateJavascript()

优点:

  1. 该方法比第一种方法效率更高、使用更简洁。
  2. 因为该方法的执行不会使页面刷新,而第一种方法(loadUrl )的执行则会。

Android 4.4 后才可使用

具体使用

// 只需要将第一种方法的loadUrl()换成下面该方法即可
  mWebView.evaluateJavascript("javascript:callJS()",new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String value) {
      //此处为 js 返回的结果
    }
  });
}

2.1.2 方法对比

方式对比图

2.1.3 使用建议

两种方法混合使用,即Android 4.4以下使用方法1,Android 4.4以上方法2

// Android版本变量
final int version = Build.VERSION.SDK_INT;
// 因为该方法在 Android 4.4 版本才可使用,所以使用时需进行版本判断
if (version < 18) {
  mWebView.loadUrl("javascript:callJS()");
} else {
  mWebView.evaluateJavascript("javascript:callJS()",new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String value) {
      //此处为 js 返回的结果
    }
  });
}

2.2 JS通过WebView调用 Android 代码

2.2.1 方法分析

方式1:通过 WebView的addJavascriptInterface()进行对象映射

步骤1:定义一个与JS对象映射关系的Android类:AndroidtoJs

AndroidtoJs.java(注释已经非常清楚)

// 继承自Object类
public class AndroidtoJs extends Object {

  // 定义JS需要调用的方法
  // 被JS调用的方法必须加入@JavascriptInterface注解
  @JavascriptInterface
  public void hello(String msg) {
    System.out.println("JS调用了Android的hello方法");
  }
}

步骤2:将需要调用的JS代码以.html格式放到src/main/assets文件夹里

需要加载JS代码:javascript.html

<!DOCTYPE html>
<html>
  <head>
   <Meta charset="utf-8">
   <title>Carson</title> 
   <script>


     function callAndroid(){
    // 由于对象映射,所以调用test对象等于调用Android映射的对象
      test.hello("js调用了android中的hello方法");
     }
   </script>
  </head>
  <body>
   //点击按钮则调用callAndroid函数
   <button type="button" id="button1" onclick="callAndroid()"></button>
  </body>
</html>

步骤3:在Android里通过WebView设置Android类与JS代码的映射

public class MainActivity extends AppCompatActivity {

  WebView mWebView;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mWebView = (WebView) findViewById(R.id.webview);
    WebSettings webSettings = mWebView.getSettings();

    // 设置与Js交互的权限
    webSettings.setJavaScriptEnabled(true);

    // 通过addJavascriptInterface()将Java对象映射到JS对象
    //参数1:Javascript对象名
    //参数2:Java对象名
    mWebView.addJavascriptInterface(new AndroidtoJs(),"test");//AndroidtoJS类对象映射到js的test对象

    // 加载JS代码
    // 格式规定为:file:///android_asset/文件名.html
    mWebView.loadUrl("file:///android_asset/javascript.html");


特点

优点:使用简单,仅将Android对象和JS对象映射即可

缺点:存在严重的漏洞问题

方式2:通过 WebViewClient 的方法shouldOverrideUrlLoading ()回调拦截 url

**具体原理: **

Android通过 WebViewClient 的回调方法shouldOverrideUrlLoading ()拦截 url解析该 url 的协议

如果检测到是预先约定好的协议,就调用相应方法

即JS需要调用Android的方法

具体使用:

步骤1:在JS约定所需要的Url协议

JS代码:javascript.html

以.html格式放到src/main/assets文件夹里

<!DOCTYPE html>
<html>

  <head>
   <Meta charset="utf-8">
   <title>Carson_Ho</title>

   <script>
     function callAndroid(){
      /*约定的url协议为:js://webview?arg1=111&arg2=222*/
      document.location = "js://webview?arg1=111&arg2=222";
     }
   </script>
</head>

<!-- 点击按钮则调用callAndroid()方法 -->
  <body>
   <button type="button" id="button1" onclick="callAndroid()">点击调用Android代码</button>
  </body>
</html>

当该JS通过Android的mWebView.loadUrl("file:///android_asset/javascript.html")加载后,就会回调shouldOverrideUrlLoading (),接下来继续看步骤2:

public class MainActivity extends AppCompatActivity {

  WebView mWebView;
//  Button button;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mWebView = (WebView) findViewById(R.id.webview);

    WebSettings webSettings = mWebView.getSettings();

    // 设置与Js交互的权限
    webSettings.setJavaScriptEnabled(true);
    // 设置允许JS弹窗
    webSettings.setJavaScriptCanopenWindowsAutomatically(true);

    // 步骤1:加载JS代码
    // 格式规定为:file:///android_asset/文件名.html
    mWebView.loadUrl("file:///android_asset/javascript.html");


// 复写WebViewClient类的shouldOverrideUrlLoading方法
mWebView.setWebViewClient(new WebViewClient() {
                   @Override
                   public boolean shouldOverrideUrlLoading(WebView view,String url) {

                     // 步骤2:根据协议的参数,判断是否是所需要的url
                     // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
                     //假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)

                     Uri uri = Uri.parse(url);                 
                     // 如果url的协议 = 预先约定的 js 协议
                     // 就解析往下解析参数
                     if ( uri.getScheme().equals("js")) {

                       // 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议
                       // 所以拦截url,下面JS开始调用Android需要的方法
                       if (uri.getAuthority().equals("webview")) {

                         // 步骤3:
                         // 执行JS所需要调用的逻辑
                         System.out.println("js调用了Android的方法");
                         // 可以在协议上带有参数并传递到Android上
                         HashMap<String,String> params = new HashMap<>();
                         Set<String> collection = uri.getQueryParameterNames();

                       }

                       return true;
                     }
                     return super.shouldOverrideUrlLoading(view,url);
                   }
                 }
    );
  }
    }

特点

优点:不存在方式1的漏洞;

缺点:JS获取Android方法的返回值复杂。

如果JS想要得到Android方法的返回值,只能通过 WebView 的 loadUrl ()去执行 JS 方法把返回值传递回去,相关的代码如下:

// Android:MainActivity.java
mWebView.loadUrl("javascript:returnResult(" + result + ")");

// JS:javascript.html
function returnResult(result){
  alert("result is" + result);
}

方式3:通过 WebChromeClient的onjsAlert()、onjsConfirm()、onjsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息

在JS中,有三个常用的对话框方法:

常用的对话框方法

方式3的原理:Android通过 WebChromeClient 的onjsAlert()、onjsConfirm()、onjsPrompt()

方法回调分别拦截JS对话框 (即上述三个方法),得到他们的消息内容,然后解析即可。

下面的例子将用拦截 JS的输入框(即prompt()方法)

说明 :

常用的拦截是:拦截 JS的输入框(即prompt()方法)

因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定 / 取消)两个值

步骤1:加载JS代码,如下: javascript.html

以.html格式放到src/main/assets文件夹里

<!DOCTYPE html>
<html>
  <head>
   <Meta charset="utf-8">
   <title>Carson_Ho</title>

   <script>

  function clickprompt(){
  // 调用prompt()
  var result=prompt("js://demo?arg1=111&arg2=222");
  alert("demo " + result);
}

   </script>
</head>

<!-- 点击按钮则调用clickprompt() -->
  <body>
   <button type="button" id="button1" onclick="clickprompt()">点击调用Android代码</button>
  </body>
</html>

当使用mWebView.loadUrl("file:///android_asset/javascript.html")加载了上述JS代码后,就会触发回调onjsPrompt(),具体如下:

  1. 如果是拦截警告框(即alert()),则触发回调onjsAlert();
  2. 如果是拦截确认框(即confirm()),则触发回调onjsConfirm();

步骤2:在Android通过WebChromeClient复写onjsPrompt()

public class MainActivity extends AppCompatActivity {

  WebView mWebView;
//  Button button;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mWebView = (WebView) findViewById(R.id.webview);

    WebSettings webSettings = mWebView.getSettings();

    // 设置与Js交互的权限
    webSettings.setJavaScriptEnabled(true);
    // 设置允许JS弹窗
    webSettings.setJavaScriptCanopenWindowsAutomatically(true);

// 先加载JS代码
    // 格式规定为:file:///android_asset/文件名.html
    mWebView.loadUrl("file:///android_asset/javascript.html");


    mWebView.setWebChromeClient(new WebChromeClient() {
    // 拦截输入框(原理同方式2)
      // 参数message:代表promt()的内容(不是url)
        // 参数result:代表输入框的返回值
      @Override
      public boolean onjsPrompt(WebView view,String defaultValue,JsPromptResult result) {
        // 根据协议的参数,判断是否是所需要的url(原理同方式2)
        // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
        //假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)

        Uri uri = Uri.parse(message);
        // 如果url的协议 = 预先约定的 js 协议
        // 就解析往下解析参数
        if ( uri.getScheme().equals("js")) {

          // 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议
          // 所以拦截url,下面JS开始调用Android需要的方法
          if (uri.getAuthority().equals("webview")) {

            //
            // 执行JS所需要调用的逻辑
            System.out.println("js调用了Android的方法");
            // 可以在协议上带有参数并传递到Android上
            HashMap<String,String> params = new HashMap<>();
            Set<String> collection = uri.getQueryParameterNames();

            //参数result:代表消息框的返回值(输入值)
            result.confirm("js调用了Android的方法成功啦");
          }
          return true;
        }
        return super.onjsPrompt(view,url,message,defaultValue,result);
      }

// 通过alert()和confirm()拦截的原理相同,此处不作过多讲述

      // 拦截JS的警告框
      @Override
      public boolean onjsAlert(WebView view,JsResult result) {
        return super.onjsAlert(view,result);
      }

      // 拦截JS的确认框
      @Override
      public boolean onjsConfirm(WebView view,JsResult result) {
        return super.onjsConfirm(view,result);
      }
    });
    }
    }


2.2.2 三种方式的对比 & 使用场景

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

android webview与js交互时遇到的问题解决

android webview与js交互时遇到的问题解决

问题如下

 

1、android调用js方法无效的问题 

    我的原因是少了

    webView.setWebChromeClient(new WebChromeClient());这一句

2、js调用android方法无效的问题

    我的原因:在api>17之后为了解决webviewjs调用任意代码的漏洞,要给回调的方法加上

    @JavascriptInterface 使用方式可以看下面的源码

    

 

解决后的代码:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    WebView webView;
    String text;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webView= (WebView) findViewById(R.id.main_webview);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.setWebChromeClient(new WebChromeClient());
//这一句是为了不让外部链接跳转到其他app去执行,而是在我们自己的webview上显示
//        webView.setWebViewClient(new WebViewClient(){
//            @Override
//            public boolean shouldOverrideUrlLoading(WebView view, String url) {
//                view.loadUrl(url);
//                return false;
//            }
//        });


     //我在raw目录下存放了一个test.html文件,代码在后面
        InputStream inputStream = getResources().openRawResource(R.raw.test);
        try {
            text=readStreamText(inputStream);
//加载本地的html文件
            webView.loadData(text,"text/html","utf-8");

//设置js回调的方法,回调方法要加上@JavascriptInterface注释,第二个参数对应js中window.demo中的demo
            webView.addJavascriptInterface(new Object(){
                @JavascriptInterface
                public void clickon(){
                    Toast.makeText(MainActivity.this, "js call android", Toast.LENGTH_SHORT).show();
                }
            },"demo");
            Log.i(TAG,"text="+text);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String readStreamText(InputStream inputStream) throws IOException {
        BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream));
        StringBuffer b=new StringBuffer();
        String temp=null;
        while ((temp=reader.readLine())!=null)
              b.append(temp);
        reader.close();
        return b.toString();
    }
//android调用js的testa函数,加入webView.setWebChromeClient(new WebChromeClient())后成功alert
    public void c(View v){
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                webView.loadUrl("javascript:testa()");
            }
        });
    }

   
}

html(raw目录下):

<html>

<body>
<script language="JavaScript">
   function testa()
   {
      alert("hello js");
   }
</script>
   <font size=31 color=red onclick="window.demo.clickon()">hello js</font>

</body>

</html>

 

 

 

Android webview与js交换JSON对象数据示例

Android webview与js交换JSON对象数据示例

最近几个项目的测试结果,Android无法主动通过调用
webview.loadUrl("javascript:"+callbackFunction+"('"+data+"')"); 这种方式将jsonobject类型的data传给js,因为js那边得到就是一个string的对象。

与此同时,js主动调用android的对象方式,android也无法返回给js一个jsonobject,需要js做一下转换,例如:

Android 代码:
复制代码 代码如下:

WebView mWebView = (WebView) this.findViewById(R.id.webview);
WebSettings settings = mWebView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setPluginsEnabled(true);
settings.setAllowFileAccess(true);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);//不加上,会显示白边
String url="file:///android_asset/t.html"; //js代码卸载t.html里
NavigationInstance navigation =new NavigationInstance(this);
mWebView.addJavascriptInterface(navigation,"Navigation");

NavigationInstance里的代码:
复制代码 代码如下:

@Override
public JSONObject GetManeuverInfo() {
try{
JSONObject test=new JSONObject();
test.put("maomao","value");
return test;
//return new JSONObject(bean.ManeuverInfo);
}catch(Exception e){
Log.e(TAG,"",e);
}
return null;
}

t.html里的代码:
复制代码 代码如下:

function testAPI(el){
console.log("---------testAPI---------");
eval("var obj = "+Navigation.GetManeuverInfo());
alert('typeof:'+typeof(obj));
alert('maomao:'+obj.maomao);
alert('obj:'+obj);
}

如果直接写成 Navigation.GetManeuverInfo.maomao是会提示undefined,因为js那边只得到了一个string对象而已,它不知道maomao是个key。

通过eval将其转化成表达式就可以调用obj.maomao得到value。
在此ps一下ios,貌似人家支持webview很好,js可以直接获取到json对象.
默认t.html加载会自动执行testAPI函数,结果如下:

今天关于WKWebView与js交互之完美解决方案wkwebview_js与oc交互实例的介绍到此结束,谢谢您的阅读,有关Android WebView与Js交互、Android WebView与JS交互全面详解(小结)、android webview与js交互时遇到的问题解决、Android webview与js交换JSON对象数据示例等更多相关知识的信息可以在本站进行查询。

本文标签:

上一篇JS将日期转为距现在的时间长度(js怎么样把日期转化为时间戳)

下一篇sqlalchemy.exc.CircularDependencyError:检测到循环依赖(检测到循环依赖关系)