Android webview和js交互 之踩坑

1.前言:Android 通过webview和网页东西进行交互 由于网页无法调用原生的一些方法:比如调用相册或者照片之类的无法调用,则需要原生和js进行交互。
  本项目使用的是七牛的三方工具进行的交互 内置 <input> <file>标签 需要重写WebChromClient 根据版本调用openFile或者showFile方法,但适配出现了严重的问题,相当一部分机型不能响应该方法,有一部分能响应的上传4M以上的大图的时候无法响应,总之问题颇多。所以想到了两者互调,使用原生方法进行调用相册拍照以及后续上传工作,上传完毕后将获取到的网址传给js,以便实现响应的功能。
  ps: a.webview.getSettings().setJavaScriptEnabled(true)//使支持js
        b.webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);//使允许js弹框
        c.经验式理解:http://localhost:8080/  myweb/hello.html
       以上web地址,前边=URL;资源定位符  后边=URI资源标识符
  
2.Android原生 调用js
  (1)通过webview的loadUrl();方法
  (2)通过webview的evaluateJavaScript();方法
  
   (1)webView.loadUrl("javascript:showInfoFromJava('" + msg + "')");//其中showInfoFromJava()为 js方法需h5在<script>标签下声明 msg为传过去的参数下同
   (2)webView.evaluateJavascript("javascript:showInfoFromJava('" + msg + "')", new ValueCallback<String>() {//此处   ValueCallback可以传null 
        @Override
        public void onReceiveValue(String value) {
            //此处为 js 返回的结果
        }
     });
 

方法对比:1.第一种会刷新页面第二种不会
                  2.第一种效率低获取返回值麻烦第二种效率相对较高可直接获取返回值
                  3.第二种智能在android 4.4以上直接使用
  
解决方法:两种方法混合使用,即Android 4.4以下使用方法1,Android 4.4以上方法2
          final int version = Build.VERSION.SDK_INT;
  if(version < 18){
      webView.loadUrl("javascript:showInfoFromJava('" + msg + "')");
  }else{
     webView.evaluateJavascript("javascript:showInfoFromJava('" + msg + "')",null);
  }
3.Androidjs 调用原生
 
  (1)通过webview的addJavascriptInterface()进行映射
  (2)通过WebviewClient的shouldOverrideUrlLoading()方法回调拦截url
  (3)通过WebChromClient的onJsAlert()、OnJsConfirm()、OnJsPromt() 方法回调拦截js对话框 alert、confirm、prmpt等信息
  
   (1)webview.addJavascriptInterface(new JsInterface(MyTestActivity.this), "AndroidWebView");//JsInterface为内部类 AndroidWebView为js识别原生方法的约定
   
   private class JsInterface {
            private Context mContext;


public JsInterface(Context context) {
   his.mContext = context;
}


//在js中调用window.AndroidWebView.showInfoFromJs(name),便会触发此方法。不加window也行的
@JavascriptInterface
public void showInfoFromJs(String name) {
Toast.makeText(mContext, name, Toast.LENGTH_SHORT).show();
}
}

优点:使用简单仅将Android对象和JS对象映射即可  但有漏洞
    (2)public class MyWebViewClient extends WebViewClient {
//拦截webview 点击事件 需返回true 可拦截进行操作
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);//可判断url是否包含某些约定字符串进行操作 比如跳转或者关闭当前页面
                return true;
        }
   }
   
   优点:不存在方式(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)public class MyWebChromeClient extends WebChromeClient {
  
@Override
public boolean onJsAlert(WebView view, String url, final String message, JsResult result) {
runOnUiThread(new Runnable() {
@Override
public void run() {


}
});
            result.confirm();//这里必须调用,否则页面会阻塞造成假死
            return true;
        }
  }
  
  主要为拦截作用 使用自身的弹框之类 保证 UI一致性。
4.Android Webiew 响应<input> <file>标签调用系统文件框  注意版本适配问题


private class OpenFileChromeClient extends WebChromeClient {


      
        //  Android 2.2 (API level 8)到Android 2.3 (API level 10)版本选择文件时会触发该隐藏方法
        @SuppressWarnings("unused")
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            openFileChooser(uploadMsg, null);
        }


        // Android 3.0 (API level 11)到 Android 4.0 (API level 15))版本选择文件时会触发,该方法为隐藏方法
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
            openFileChooser(uploadMsg, acceptType, null);
        }


        // Android 4.1 (API level 16) -- Android 4.3 (API level 18)版本选择文件时会触发,该方法为隐藏方法
        @SuppressWarnings("unused")
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
            openFileInput(uploadMsg, null, false);
        }


        // Android 5.0 (API level 21)以上版本会触发该方法,该方法为公开方法
        @SuppressWarnings("all")
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
            if (Build.VERSION.SDK_INT >= 21) {
                final boolean allowMultiple = fileChooserParams.getMode() == FileChooserParams.MODE_OPEN_MULTIPLE;//是否支持多选




                openFileInput(null, filePathCallback, allowMultiple);


                return true;
            } else {
                return false;
            }
        }




    }


    @SuppressLint("NewApi")
    protected void openFileInput(final ValueCallback<Uri> fileUploadCallbackFirst, final ValueCallback<Uri[]> fileUploadCallbackSecond, final boolean allowMultiple) {
        //Android 5.0以下版本
        if (mFileUploadCallbackFirst != null) {
            mFileUploadCallbackFirst.onReceiveValue(null);
        }
        mFileUploadCallbackFirst = fileUploadCallbackFirst;


        //Android 5.0及以上版本
        if (mFileUploadCallbackSecond != null) {
            mFileUploadCallbackSecond.onReceiveValue(null);
        }
        mFileUploadCallbackSecond = fileUploadCallbackSecond;


        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);


        if (allowMultiple) {
            if (Build.VERSION.SDK_INT >= 18) {
                i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
            }
        }


        i.setType(mUploadableFileTypes);


        startActivityForResult(Intent.createChooser(i, "选择文件"), REQUEST_CODE_FILE_PICKER);


    }


    public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
        if (requestCode == REQUEST_CODE_FILE_PICKER) {
            if (resultCode == RESULT_OK) {
                if (intent != null) {
                    //Android 5.0以下版本
                    if (mFileUploadCallbackFirst != null) {
                        mFileUploadCallbackFirst.onReceiveValue(intent.getData());
                        mFileUploadCallbackFirst = null;
                    } else if (mFileUploadCallbackSecond != null) {//Android 5.0及以上版本
                        Uri[] dataUris = null;


                        try {
                            if (intent.getDataString() != null) {
                                dataUris = new Uri[]{Uri.parse(intent.getDataString())};
                            } else {
                                if (Build.VERSION.SDK_INT >= 16) {
                                    if (intent.getClipData() != null) {
                                        final int numSelectedFiles = intent.getClipData().getItemCount();


                                        dataUris = new Uri[numSelectedFiles];


                                        for (int i = 0; i < numSelectedFiles; i++) {
                                            dataUris[i] = intent.getClipData().getItemAt(i).getUri();
                                        }
                                    }
                                }
                            }
                        } catch (Exception ignored) {
                        }
                        mFileUploadCallbackSecond.onReceiveValue(dataUris);
                        mFileUploadCallbackSecond = null;
                    }
                }
            } else {
                //这里mFileUploadCallbackFirst跟mFileUploadCallbackSecond在不同系统版本下分别持有了
                //WebView对象,在用户取消文件选择器的情况下,需给onReceiveValue传null返回值
                //否则WebView在未收到返回值的情况下,无法进行任何操作,文件选择器会失效
                if (mFileUploadCallbackFirst != null) {
                    mFileUploadCallbackFirst.onReceiveValue(null);
                    mFileUploadCallbackFirst = null;
                } else if (mFileUploadCallbackSecond != null) {
                    mFileUploadCallbackSecond.onReceiveValue(null);
                    mFileUploadCallbackSecond = null;
                }
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值