Webview打开本地文件、图片选择的解决方案。版本兼容问题

本文期待解决的问题:1、html中 <input id="input"type="file"/>  标签可以在android真机各个版本上调取本地文件,并获取文件信息。

     第一次做的时候想到利用WebView的JS交互来完成。

     思路:给WebView添加JS接口。

  WebView.addJavascriptInterface(new JavascriptInterface(),"");
      在接口    JavascriptInterface中定义方法暴露给html调用传参。返回后在方法中实现想要的操作。如果有需要通知html界面的操作时,可以调用下面的方法传递参数。
  WebView.loadUrl("javascript:hello_android('" + picIds + "','" + imageurl + "')");

      上面的思路可以实现简单的JS交互,但有安全隐患。  so...不到实在没有办法了,不建议使用。

     Webview的属性设置中提供了,打开本地文件的回调方法。

  WebView.setWebChromeClient(new ReWebChomeClient(this));

      这里的  ReWebChomeClient   继承了  extends WebChromeClient 

      在重写的方法中有针对android 各个版本打开本地文件的对应的方法。 废话少说,实践一下。

1、开发环境要求5.0以上(一些方法只有5.0下才能重写生效)。

2、这里的html放在本地assets资源文件下。

 WebView = (WebView) findViewById(R.id.webview);
 WebView.setWebChromeClient(new ReWebChomeClient(this));
 WebView.setWebViewClient(new ReWebViewClient());
//这里加载自己Url(也可加载本地资源)
 WebView.loadUrl("file:///android_asset/input.html");

设置WebView的基本属性。 接下来看看  new ReWebChomeClient(this) 中实现了什么。

  public class ReWebChomeClient extends WebChromeClient
     继承了WebChromeClient  重写了4个方法。
// For Android < 3.0
    public void openFileChooser(ValueCallback<Uri> uploadMsg)
//For Android 3.0+
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType)
 // For Android  > 4.1.1
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
// For Android > 5.0
    public boolean onShowFileChooser (WebView webView, ValueCallback<Uri[]> uploadMsg, WebChromeClient.FileChooserParams fileChooserParams)
      从小于3.0到大于5.0的各个版本需要的方法。

      由于5.0的重写方法中传递的参数 ValueCallBack<Uri[]> uploadMsg 与其他的几个方法传递参数不同,我们在自定义的接口中实现两个方法。在上面重写的方法中接收参数。

/**
 * 自定义接口  方便MainActivity调用
 */
public interface OpenFileChooserCallBack {
    void openFileChooserCallBack(ValueCallback<Uri> uploadMsg, String acceptType);

    void openFileChooserCallBack(ValueCallback<Uri[]> uploadMsg,WebChromeClient.FileChooserParams fileChooserParams);
}

    ReWebChomeClient类完整代码:

public class ReWebChomeClient extends WebChromeClient  {

    private OpenFileChooserCallBack mOpenFileChooserCallBack;

    public ReWebChomeClient(OpenFileChooserCallBack openFileChooserCallBack) {
        mOpenFileChooserCallBack = openFileChooserCallBack;
    }

    // For Android < 3.0
    public void openFileChooser(ValueCallback<Uri> uploadMsg) {
        openFileChooser(uploadMsg, "");
    }

    //For Android 3.0+
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
        mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg, acceptType);
    }

    // For Android  > 4.1.1
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        openFileChooser(uploadMsg, acceptType);
    }

    // For Android > 5.0
    public boolean onShowFileChooser (WebView webView, ValueCallback<Uri[]> uploadMsg, WebChromeClient.FileChooserParams fileChooserParams) {
        mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg,fileChooserParams);
        return true;
    }


    /**
     * 自定义接口  方便MainActivity调用
     */
    public interface OpenFileChooserCallBack {
        void openFileChooserCallBack(ValueCallback<Uri> uploadMsg, String acceptType);

        void openFileChooserCallBack(ValueCallback<Uri[]> uploadMsg,WebChromeClient.FileChooserParams fileChooserParams);
    }

}

   接下来  new ReWebViewClient() 中没什么技术点。说句题外话。当WebView中有链接可以点击时,默认是跳到浏览器中浏览。而我们想在WebView中继续浏览时。重写  

   shouldOverrideUrlLoading方法。 就可以在webview中继续浏览。如果有电话号码可以点击 也可以在这个方法中去做判断,具体实现看下面代码。

     public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if (url.contains("tel:")) {
                    Intent intent = new Intent(Intent.ACTION_CALL);
                    intent.setData(Uri.parse(url));
                    startActivity(intent);
                } else {
                    view.loadUrl(url);
                }
                return true;
            }

   举一反三,既然要打开系统拨号键盘,那邮箱,地图也可以支持

 if (url.startsWith("mailto:") || url.startsWith("geo:") || url.startsWith("tel:")) {
          Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
          startActivity(intent);
          return true;
        }

   

    接下来看 MainActivity中具体做哪些工作。

   首先,实现自定义的接口  OpenFileChooserCallBack ,实现两个方法。当点击file标签时,回调成功。具体实现代码写在两个方法中。  

    implements ReWebChomeClient.OpenFileChooserCallBack
@Override
public void openFileChooserCallBack(ValueCallback<Uri> uploadMsg, String acceptType) {
    mUploadMsg = uploadMsg;
    showOptions();
}

@Override
public void openFileChooserCallBack(ValueCallback<Uri[]> uploadMsg, WebChromeClient.FileChooserParams fileChooserParams) {
    mUploadMessageForAndroid5 = uploadMsg;
    showOptions();
}
public void showOptions() {

    CharSequence[] sequences = {"相册", "拍照"};
    AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
    alertDialog.setOnCancelListener(new ReOnCancelListener());
    alertDialog.setTitle("选择图片");
    alertDialog.setItems(sequences, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (which == 0) {

                        Intent showImgIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                        startActivityForResult(showImgIntent, REQUEST_CODE_PICK_IMAGE);
                    } else {

                        File dir = new File(Environment.getExternalStorageDirectory() + "/econ/");
                        if (!dir.exists()) {
                            dir.mkdirs();
                        }
                        File mCameraPicture = new File(dir, System.currentTimeMillis() + ".jpg");

                        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mCameraPicture));
                        cameraIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
                        startActivityForResult(cameraIntent, REQUEST_CODE_IMAGE_CAPTURE);
                    }
                }
            }
    );
    alertDialog.show();
}
 @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (resultCode != Activity.RESULT_OK) {
            if (mUploadMsg != null) {
                mUploadMsg.onReceiveValue(null);
                mUploadMsg = null;
            }

            if (mUploadMessageForAndroid5 != null) {
                mUploadMessageForAndroid5.onReceiveValue(null);
                mUploadMessageForAndroid5 = null;
            }
            return;
        }
        if (null == mUploadMessageForAndroid5)
            return;
        Uri result = (data == null || resultCode != RESULT_OK) ? null : data.getData();
        if (result != null) {
            mUploadMessageForAndroid5.onReceiveValue(new Uri[]{result});
        } else {
            mUploadMessageForAndroid5.onReceiveValue(new Uri[]{});
        }
        mUploadMessageForAndroid5 = null;
        。。。。。。。。。。   
 }

  实现思路基本完成,说说在实现过程中遇到的问题。

   1、支持release版

    debug版是好的,为什么release就不行了呢?准确的说,开启了混淆的release包是不可以的,究其原因在于, openFileChooser 方法并不是WebChromeClient 的对外开放的方法,因此这个方法会被混淆,解决办法也比较简单,只需要在混淆文件里控制一下即可:

-keepclassmembers class * extends android.webkit.WebChromeClient{
   		public void openFileChooser(...);
}

  2、在操作过程中选完图片后返回或直接返回。发现选择文件按钮点击无反应!

        ValueCallback<Uri>  uploadMsg    参数的 onReceiveValue() 方法。重新置为null。选择文件按钮就可以重新被调用了。

        ①、 如果你的弹出选择框是自定义的,那就设置一个监听来重置。②、在onActivityResult方法中。

  if (resultCode != Activity.RESULT_OK) {
     if (mUploadMsg != null) {
        mUploadMsg.onReceiveValue(null);
        mUploadMsg = null;
     }
     return;
   } 。。。。。有操作(选择了文件) 处理完数据别忘记将onReceiveValue(null)


完整代码链接  

http://download.csdn.net/detail/yanchun413/9677301    

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值