Android WebView及WebView的神坑之旅

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/lijinweii/article/details/79707776

WebView的一些神坑

最近在开发过程中遇到一个问题,主要是WebView页面,需要调用本地相机拍照及图库,遇到一系列的神坑,这里结合本人所查阅的资料给大家一一说明。

进入正题,首先来了解webview,这里我分享两篇大佬的博客

1.WebView开车指南

2.WebView详解

3.WebView深坑之旅

本人也是首次使用H5页面调用相机及图库,本以为只要将页面展示就可以,其他的都是前端的事情,我还能偷偷懒,可是在测试的时候就遇到了

第一个神坑:权限的添加

Android 6.0以后对于一些危险权限都需要动态的添加权限,这些对于大家来说都已经很容易实现了,大家可参考:

https://blog.csdn.net/m0_37959831/article/details/77854548

但是,如果你已经添加了权限,调用相机之后,文件回调不了,其实根本就是没有回调.这个时候你要去检查你的webview的Settings了关键代码,是否给足了权限;

WebSettings settings = webView.getSettings();
        settings.setUseWideViewPort(true);
        settings.setLoadWithOverviewMode(true);
        settings.setDomStorageEnabled(true);
        settings.setDefaultTextEncodingName("UTF-8");
        settings.setAllowContentAccess(true); // 是否可访问Content Provider的资源,默认值 true
        settings.setAllowFileAccess(true);    // 是否可访问本地文件,默认值 true
        // 是否允许通过file url加载的Javascript读取本地文件,默认值 false
        settings.setAllowFileAccessFromFileURLs(false);
        // 是否允许通过file url加载的Javascript读取全部资源(包括文件,http,https),默认值 false
        settings.setAllowUniversalAccessFromFileURLs(false);
        //开启JavaScript支持
        settings.setJavaScriptEnabled(true);
        // 支持缩放
        settings.setSupportZoom(true);
其中 settings.setDomStorageEnabled(true);这个方法当时我没加,血崩了一次;

第二个神坑:Android端 webview根本不能让h5自己调用,ios是可以的。

这里是为什么呢?查了资料发现Android端H5页面对于相机及图库的调用有一套专门的代码:这里给大家推荐两篇文章:

https://blog.csdn.net/m0_37959831/article/details/77854548

https://www.cnblogs.com/nmdzwps/p/5841509.html

大家啊先参考文档,最后我会贴上本人的代码供大家参考

第三个神坑:WebchromClient的openFileChooser()只调用了一次

首先了解为什么这个方法只调用了一次,看这篇博客就可

Android开发深入理解WebChromeClient之onShowFileChooser或openFileChooser使用说明
看了他基本你就了解怎么回事了

第四个神坑 :android 7.0的FileProvider的坑

看洪阳大佬的这篇博客基本就了解了

Android 7.0 行为变更 通过FileProvider在应用间共享文件吧

第五个神坑:WebView软键盘冲突

对于H5页面中的输入框与软件盘冲突的问题,或者输入框被软键盘遮盖问题,相信大部分人都遇到过,这里就和大家说下解决方案:

软键盘挡住输入框问题的终极解决方案

解决安卓全屏状态下WebView的输入框被软键盘挡住的问题

第六个神坑:H5页面加载地图

https://blog.csdn.net/jyz_2015/article/details/52776195

https://blog.csdn.net/csdndouniwan/article/details/51159901

贴上自己的代码:

public class WebViewInstallationActivity extends BaseActivity {

    // 定位
    private static final int REQ_SET_LOCATION = 300;
    private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 1;//打电话
    private WebView webView;
    private String dataMap;
    private String order_type;
    private String out_trade_no;
    private int code;
    private String userid;
    private String installer_phone;

    //H5调用Android 相册 相机的
    private ValueCallback<Uri> mUploadMessage;// 表单的数据信息
    private ValueCallback<Uri[]> mUploadCallbackAboveL;
    private final static int FILECHOOSER_RESULTCODE = 1;// 表单的结果回调</span>
    private Uri imageUri;
    private WaitDialog waitDialog;
    private String h5_notice_url;
    private String url;
    private String gobackurl;
    private Uri bitmap2uri;

    @Override
    public int getLayoutResId() {
        waitDialog = new WaitDialog(activity, "", false, null);
        String user_id = SpUtils.getUserId(activity);
        h5_notice_url = getIntent().getStringExtra("h5_notice_url");
        if (StringUtils.isEmpty(h5_notice_url)) {
            if (StringUtils.isEmpty(user_id)) {
                user_id = "";
            }
            url = ServiceApi.getWebView(user_id);
        } else if (!StringUtils.isEmpty(h5_notice_url)) {
            url = h5_notice_url;
        }
        return R.layout.activity_webview;
    }

    @Override
    protected void initView() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            Window window = getWindow();
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }
        webView = (WebView) findViewById(R.id.webview);
        WebSettings webSettings = webView.getSettings();

        webSettings.setJavaScriptEnabled(true);//支持js
        webSettings.setAppCacheEnabled(true);
        webSettings.setDomStorageEnabled(true);//自适应屏幕
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setUseWideViewPort(false);  //将图片调整到适合webview的大小
        webSettings.setSupportZoom(false);  // 设置可以支持缩放
        webSettings.setBuiltInZoomControls(false); //设置出现缩放工具
        webSettings.setTextZoom(100); //禁止缩放,按照百分百显示
        //缓存模式
        boolean networkAvailable = MySystemUtils.isNetworkAvailable(activity);
        if (networkAvailable) {
            webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);  //缓存模式
        } else {
            webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);  //缓存模式
        }

        webSettings.setAllowContentAccess(true); // 是否可访问Content Provider的资源,默认值 true
        webSettings.setAllowFileAccess(true);  //设置可以访问本地文件
        webSettings.setNeedInitialFocus(true); //当webview调用requestFocus时为webview设置节点
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
        //启用数据库
        webSettings.setDatabaseEnabled(true);
        String dir = this.getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
        //webview定位相关设置
        webSettings.setGeolocationEnabled(true);
        //设置定位的数据库路径
        webSettings.setGeolocationDatabasePath(dir);
        webView.setWebChromeClient(new MyWebChromeClient());
        webView.setWebViewClient(new MyWebViewClient());//对webview页面加载管理、如url重定向
    }

    @Override
    protected void initListener() {
    }

    @Override
    protected void initData() {
        //添加定位权限 相机图库权限
        initPermission();
    }

    private void initPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//SDK>=23
            if (!(checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED)) {
                if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_COARSE_LOCATION)) {
                    Toast.makeText(this, "请确认是否开启定位的相关权限", Toast.LENGTH_LONG).show();
                    MySystemUtils.goToSetPermission(activity, "在设置-应用-权限中开启定位的权限,以保证功能的正常使用", REQ_SET_LOCATION);
                } else {
                    requestPermissions(new String[]{Manifest.permission.CHANGE_WIFI_STATE, Manifest.permission.ACCESS_COARSE_LOCATION}, REQ_SET_LOCATION);
                }
            } else {
                Log.i("--", "onClick granted");
                onLoadData();
            }
        } else {
            onLoadData();
        }
    }

    private void onLoadData() {
        webView.loadUrl(url);
        if (!isFinishing()) {
            waitDialog.show();
        }
        doSpecialiSomethingAsVirtualBar();
    }

    /**
     * 虚拟按键-tangZd
     */
    private void doSpecialiSomethingAsVirtualBar() {
        //webview-软键盘-冲突
        //KeyBoardListenerManager.newInstance(this).init();
        //华为虚拟按键冲突问题:
        //是否存在导航栏(虚拟功能键)
        if (PhoneSystemManager.AndroidWorkaround.checkDeviceHasNavigationBar(this)) {
            PhoneSystemManager.AndroidWorkaround.assistActivity(findViewById(android.R.id.content));
            ViewStub stub = (ViewStub) findViewById(R.id.view_stub);
            stub.inflate();
            View enuiStubView = this.findViewById(R.id.enuiNatView);
            LinearLayout.LayoutParams zLayoutParams = (LinearLayout.LayoutParams) enuiStubView.getLayoutParams();
            //获取虚拟功能键高度
            int virtualBarHeigh = PhoneSystemManager.AndroidWorkaround.getVirtualBarHeigh(this);
            zLayoutParams.height = virtualBarHeigh;
            enuiStubView.setLayoutParams(zLayoutParams);

        } else {
            //webview-软键盘-冲突
            KeyBoardListenerManager.newInstance(this).init();
        }
    }

    private class MyWebChromeClient extends WebChromeClient {

        //定位
        @Override
        public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
            callback.invoke(origin, true, true);
            super.onGeolocationPermissionsShowPrompt(origin, callback);
        }

        //android 5.0以后google做了支持
        @Override
        public boolean onShowFileChooser(WebView webView,
                                         ValueCallback<Uri[]> filePathCallback,
                                         FileChooserParams fileChooserParams) {
            mUploadCallbackAboveL = filePathCallback;
            //take();
            getPermissions();
            return true;
        }

        //下面的这些方法会根据android的版本自动选择
        //android3.0以下
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            mUploadMessage = uploadMsg;
            getPermissions();
        }

        //android3.0-4.0
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
            mUploadMessage = uploadMsg;
            getPermissions();
        }

        //4.0-4.3  4.4.4(android 4.4无方法)
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
            mUploadMessage = uploadMsg;
            getPermissions();
        }
    }

    private void getPermissions() {//拍照权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //checkSelfPermission用来检测应用是否已经具有权限
            if (!(checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)) {
                if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
                    //去设置权限(申请权限) dialog
                    MySystemUtils.goToSetPermission(activity, getResources().getString(R.string.permission_camera), JHConstants.REQ_PERMISSION_CAMERA);
                } else {
                    //进行请求单个或多个权限
                    requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, JHConstants.REQ_PERMISSION_CAMERA);
                }
            } else {
                //具有权限
                take();
            }
        } else {// < 23
            take();
        }
    }

    private class MyWebViewClient extends MyWebViewClientUtils {

        @Override
        protected boolean initShouldOverrideUrlLoading(WebView view, String url) {

            if (url.contains("installPhoneMyOrderPF/installerOrderCallPhone.do")) {//截取 电话
                Map urlParamMap = UIutils.getUrlParamMap(url);
                installer_phone = urlParamMap.get("INSTALLER_PHONE").toString();
                //web 打电话
                webViewCall();

            } else if (url.contains("iosIndex/gotoIndexPage.do")) {//返回
                waitDialog.dismiss();
                WebViewInstallationActivity.this.finish();

            } else if (url.contains("installPhoneIndexPF/phoneLoginPage.do")) {//去登录页面
                startActivity(new Intent(activity, LoginActivity.class));

            } else if (url.contains("installPhoneIndexPF/phoneRegisterPage.do")) {//去认证页面
                startActivity(new Intent(activity, IdentifyActivity.class));

            } else if (url.contains("kuaiQianJAZH5Pay/toPayPage.do")) {//去快钱支付页面
                Map urlParamMap = UIutils.getUrlParamMap(url);
                String order_id = urlParamMap.get("ORDER_ID").toString();
                //快钱支付
                Intent webviewkuaiqian = new Intent(activity, WebViewKuaiqianPayActivity.class);
                webviewkuaiqian.putExtra("pay_type", "web");
                webviewkuaiqian.putExtra("out_trade_no", order_id);
                startActivity(webviewkuaiqian);

            } else if (url.contains("submitToPayOrder")) {//待支付 去支付
                Map urlParamMap = UIutils.getUrlParamMap(url);
                userid = urlParamMap.get("USER_ID").toString();

                ServiceApi.getUrlParammap(NetUtils.H5_URL_WEBTOPAYPAGE, urlParamMap, new MyString2Callback() {
                    @Override
                    public void onError(Call call, Exception e) {
                        ToastUtils.showInternetErrorToast();
                    }

                    @Override
                    public void onResponse(Call call, String s) {

                        String PAY_user_id = "PAY_" + userid;
                        try {
                            JSONObject jsonObject = new JSONObject(s);
                            code = jsonObject.getInt("code");
                            dataMap = jsonObject.getString("dataMap");
                            JSONObject pay_user_id = jsonObject.getJSONObject(PAY_user_id);
                            out_trade_no = pay_user_id.getString("out_trade_no");
                            order_type = jsonObject.getString("order_type");

                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        if (0 == code) {

                            ZFBUtils zfbUtils = new ZFBUtils(WebViewInstallationActivity.this, dataMap);
                            zfbUtils.payV2(new ZFBUtils.Pay_ZFB_Pay_Listener() {
                                @Override
                                public void onPaySuccess(PayResult payResult) {
                                    ToastUtils.showToast("支付成功");
                                    webView.loadUrl(ServiceApi.getPaySuccessToDetail(userid, out_trade_no));
                                }

                                @Override
                                public void onPayError(PayResult payResult) {
                                    String s1 = payResult.toString();
                                    ToastUtils.showToast("支付失败");
                                }
                            });
                        } else if (-1 == code) {
                            ToastUtils.showToast("操作失败");
                        }
                    }
                });
            } else {
                return false;
            }
            return true;
        }

        @Override
        protected void initOnPageStarted(WebView view, String url, Bitmap favicon) {
            gobackurl = url;
            if (!isFinishing()) {
                waitDialog.show();
            }
        }

        @Override
        protected void initOnPageFinished(WebView view, String url) {
            waitDialog.dismiss();
        }

        @Override
        protected void initOnReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
            waitDialog.dismiss();
        }
    }

    //web 打电话
    private void webViewCall() {
        // 检查是否获得了权限(Android6.0运行时权限)
        if (ContextCompat.checkSelfPermission(WebViewInstallationActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
            // 没有获得授权,申请授权
            if (ActivityCompat.shouldShowRequestPermissionRationale(WebViewInstallationActivity.this, Manifest.permission.CALL_PHONE)) {
                // 返回值:
                //如果app之前请求过该权限,被用户拒绝, 这个方法就会返回true.
                //如果用户之前拒绝权限的时候勾选了对话框中”Don’t ask again”的选项,那么这个方法会返回false.
                // 如果设备策略禁止应用拥有这条权限, 这个方法也返回false.
                // 弹窗需要解释为何需要该权限,再次请求授权
                Toast.makeText(WebViewInstallationActivity.this, "请授权!", Toast.LENGTH_LONG).show();

                // 帮跳转到该应用的设置界面,让用户手动授权
                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                Uri uri = Uri.fromParts("package", getPackageName(), null);
                intent.setData(uri);
                startActivity(intent);
            } else {
                // 不需要解释为何需要该权限,直接请求授权
                ActivityCompat.requestPermissions(WebViewInstallationActivity.this, new String[]{Manifest.permission.CALL_PHONE}, MY_PERMISSIONS_REQUEST_CALL_PHONE);
            }
        } else {
            // 已经获得授权,可以打电话
            CallPhone();
        }
    }

    private void CallPhone() {
        if (TextUtils.isEmpty(installer_phone)) {
            // 提醒用户
            // 注意:在这个匿名内部类中如果用this则表示是View.OnClickListener类的对象,
            // 所以必须用MainActivity.this来指定上下文环境。
            Toast.makeText(WebViewInstallationActivity.this, "号码不能为空!", Toast.LENGTH_SHORT).show();
        } else {
            // 拨号:激活系统的拨号组件
            Intent intent = new Intent(); // 意图对象:动作 + 数据
            intent.setAction(Intent.ACTION_CALL); // 设置动作
            Uri data = Uri.parse("tel:" + installer_phone); // 设置数据
            intent.setData(data);
            startActivity(intent); // 激活Activity组件
        }
    }

    // 处理权限申请的回调
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_CALL_PHONE: {//电话
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // 授权成功,继续打电话
                    CallPhone();
                } else {
                    // 授权失败!
                    Toast.makeText(this, "授权失败!", Toast.LENGTH_LONG).show();
                }
                break;
            }
            case REQ_SET_LOCATION: {//定位
                Boolean grantResultBoolean = false;
                for (int grantResult : grantResults) {
                    grantResultBoolean = (grantResult == PackageManager.PERMISSION_GRANTED);
                    if (!grantResultBoolean) {
                        break;
                    }
                }
                if (grantResultBoolean) {
                    //通过
                    onLoadData();
                } else {
                    MySystemUtils.goToSetPermission(activity, "在设置-应用-权限中开启定位的权限,以保证功能的正常使用", REQ_SET_LOCATION);
                }
                break;
            }
            case JHConstants.REQ_PERMISSION_CAMERA: {//相机相册
                boolean isAllow = false;
                for (int result : grantResults) {
                    if (PackageManager.PERMISSION_GRANTED == result) {
                        isAllow = true;
                    } else {
                        isAllow = false;
                    }
                }
                if (isAllow) {
                    take();
                } else {
                    MySystemUtils.goToSetPermission(activity, getResources().getString(R.string.permission_notice_storage_and_camera), JHConstants.REQ_PERMISSION_CAMERA);
                }
                break;
            }
        }
    }

    /**
     * 以下是webview的照片上传时候,用于在网页打开android图库文件
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data); //图库的图片 data != null, 拍照的图片时 data == null
        if (requestCode == FILECHOOSER_RESULTCODE) {
            if (null == mUploadMessage && null == mUploadCallbackAboveL)
                return;

            Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
            if (mUploadCallbackAboveL != null) {//android 5.0以后
                try {
                    onActivityResultAboveL(requestCode, resultCode, data);
                } catch (IOException e) {
                    e.printStackTrace();
                }

            } else if (mUploadMessage != null) {//android 5.0以前
                if (result != null) {//图库的图片
                    try {
                        String path = getPath(getApplicationContext(), result);
                        Uri uri = Uri.fromFile(new File(path));
                        Bitmap bitmapformuri = PhotoUtils.getBitmapFormUri(activity, uri);
                        bitmap2uri = PhotoUtils.bitmap2uri(activity, bitmapformuri);
                        mUploadMessage.onReceiveValue(bitmap2uri);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else {//拍照的图片
                    //此处要设为null,否则在未选择图片的情况下,依然会出现上传空白文件,后台做了Uri 路径流是否可用判断
//                    imageUri = null;
                    mUploadMessage.onReceiveValue(imageUri);
                }
                mUploadMessage = null;
            }
        }
    }

    //针对5.0的结果回调
    @SuppressWarnings("null")
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) throws IOException {
        if (requestCode != FILECHOOSER_RESULTCODE || mUploadCallbackAboveL == null) {
            return;
        }
        Uri[] results = null;
        if (resultCode == Activity.RESULT_OK) {
            if (data == null) {
                results = new Uri[]{imageUri};
            } else {
                String dataString = data.getDataString();
                ClipData clipData = data.getClipData();
                if (clipData != null) {
                    results = new Uri[clipData.getItemCount()];
                    for (int i = 0; i < clipData.getItemCount(); i++) {
                        ClipData.Item item = clipData.getItemAt(i);
                        results[i] = item.getUri();
                    }
                }
                if (dataString != null)
                    results = new Uri[]{Uri.parse(dataString)};
            }
        }
        if (results != null) {
            Uri[] compressResults = new Uri[results.length];
            for (int i = 0; i < results.length; i++) {
                Uri result = results[i];
                Bitmap bitmapFormUri = PhotoUtils.getBitmapFormUri(activity, result);
                bitmap2uri = PhotoUtils.bitmap2uri(activity, bitmapFormUri);
                compressResults[i] = bitmap2uri;
            }
            mUploadCallbackAboveL.onReceiveValue(compressResults);
            mUploadCallbackAboveL = null;
        } else {
            //此处要设为null,否则在未选择图片的情况下,依然会出现上传空白文件,
            results = null;
            mUploadCallbackAboveL.onReceiveValue(results);
            mUploadCallbackAboveL = null;
        }
        return;
    }

    //take方法
    private void take() {
        File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");
        // Create the storage directory if it does not exist
        if (!imageStorageDir.exists()) {
            imageStorageDir.mkdirs();
        }
        File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
        //设定图片的uri路径
        imageUri = Uri.fromFile(file);

        final List<Intent> cameraIntents = new ArrayList<Intent>();
        //调用相机的intent
        final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        //获取包管理器(就是包含了整个清单文件,其中包括application,activity)
        final PackageManager packageManager = getPackageManager();
        //查询相机intent的activity,ResolveInfo其实就是activity节点
        final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
        //进行遍历
        for (ResolveInfo res : listCam) {
            //获取list中的元素,就activity,就是根据activity拿到相机的包名
            final String packageName = res.activityInfo.packageName;
            //将相机的intent 赋给新的intent
            final Intent i = new Intent(captureIntent);
            //重新设置当前intent的Component  (写全包名)
            i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
            i.setPackage(packageName);
            i.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            cameraIntents.add(i);
        }
        //这个是文档内容,包含image,音视频
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        //添加分类
        i.addCategory(Intent.CATEGORY_OPENABLE);
        //类型为图片
        i.setType("image/*");

        //开始创建跳转应用的对话框,可以自己设置dialog样式,也可以像下面这样,同时创建包含多个
        //intent的对话框,但样式不好控制,只能由系统默认,比如在4.4.4的模拟器上样式,图片见末尾
        Intent chooserIntent = Intent.createChooser(i, "选择图片");//Image Chooser
        //添加额外初始相机intent,但要序列化
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
        WebViewInstallationActivity.this.startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
    }

    //由于4.4以后content后面不再表示路径,以下方法专为4.4以后路径问题的解决
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static String getPath(final Context context, final Uri uri) {
        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                }
                // TODO handle non-primary volumes
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {
                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{split[1]};

                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }

        return null;
    }

    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context       The context.
     * @param uri           The Uri to query.
     * @param selection     (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = {column};

        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int column_index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(column_index);
            }
        } finally {
            if (cursor != null) cursor.close();
        }
        return null;
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }


    @Override
    public Resources getResources() {
        Resources res = super.getResources();
        Configuration config = new Configuration();
        config.setToDefaults();
        res.updateConfiguration(config, res.getDisplayMetrics());
        return res;
    }


    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        // TODO Auto-generated method stub
        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            if (gobackurl.contains("installPhoneIndexPF/phoneIndexPage.do")) {
                waitDialog.dismiss();
                WebViewInstallationActivity.this.finish();
            } else if (gobackurl.contains("installPhoneMyOrderPF/phoneMyOrderPage.do")) {
                waitDialog.dismiss();
                WebViewInstallationActivity.this.finish();
            } else if (gobackurl.contains("installPhonePersonCenterPF/phonePersonIndexPage.do")) {
                waitDialog.dismiss();
                WebViewInstallationActivity.this.finish();
            } else {
                webView.goBack();
            }
            return true;
        } else {
            waitDialog.dismiss();
            finish();

        }
        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (webView != null) {
            webView.setWebViewClient(null);
            webView.setWebChromeClient(null);
            webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
            webView.clearHistory();
            webView.destroy();
            webView = null;
        }
    }
}
/**
 * Created by LiJinWei on 2018/1/22.
 * 调用方式为:KeyBoardListenerManager.newInstance(this).init();
 * 出现华为虚拟按键冲突问题:
 * 解决方案使用下面此类,此类主要作为封装处理特殊手机的工具类。
 */
public class PhoneSystemManager {
    public static final String SYS_EMUI = "sys_emui";// 华为
    public static final String SYS_MIUI = "sys_miui";// 小米
    public static final String SYS_FLYME = "sys_flyme";// 魅族
    public static final String SYS_NORMAL = "sys_normal";// 一般市面手机


    private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
    private static final String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
    private static final String KEY_MIUI_INTERNAL_STORAGE = "ro.miui.internal.storage";
    private static final String KEY_EMUI_API_LEVEL = "ro.build.hw_emui_api_level";
    private static final String KEY_EMUI_VERSION = "ro.build.version.emui";
    private static final String KEY_EMUI_CONFIG_HW_SYS_VERSION = "ro.confg.hw_systemversion";

    public static String getTelPhoneSystem() {
        String SYS = SYS_NORMAL;
        try {
            Properties prop = new Properties();
            prop.load(new FileInputStream(new File(Environment.getRootDirectory(), "build.prop")));
            if (prop.getProperty(KEY_MIUI_VERSION_CODE, null) != null
                    || prop.getProperty(KEY_MIUI_VERSION_NAME, null) != null
                    || prop.getProperty(KEY_MIUI_INTERNAL_STORAGE, null) != null) {
                SYS = SYS_MIUI;//小米
            } else if (prop.getProperty(KEY_EMUI_API_LEVEL, null) != null
                    || prop.getProperty(KEY_EMUI_VERSION, null) != null
                    || prop.getProperty(KEY_EMUI_CONFIG_HW_SYS_VERSION, null) != null) {
                SYS = SYS_EMUI;//华为
            } else if (getMeizuFlymeOSFlag().toLowerCase().contains("flyme")) {
                SYS = SYS_FLYME;//魅族
            }
        } catch (IOException e) {
            e.printStackTrace();
            return SYS;
        }
        return SYS;
    }

    public static String getMeizuFlymeOSFlag() {
        return getSystemProperty("ro.build.display.id", "");
    }

    private static String getSystemProperty(String key, String defaultValue) {
        try {
            Class<?> clz = Class.forName("android.os.SystemProperties");
            Method get = clz.getMethod("get", String.class, String.class);
            return (String) get.invoke(clz, key, defaultValue);
        } catch (Exception e) {
        }
        return defaultValue;
    }


    /**
     * 设置透明状态栏目
     * setMiuiStatusBarDarkMode(this, true);
     * setMeizuStatusBarDarkIcon(this, true);
     **/
    public static boolean setMiuiStatusBarDarkMode(Activity activity, boolean darkmode) {
        Class<? extends Window> clazz = activity.getWindow().getClass();
        try {
            int darkModeFlag = 0;
            Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
            Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
            darkModeFlag = field.getInt(layoutParams);
            Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
            extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static boolean setMeizuStatusBarDarkIcon(Activity activity, boolean dark) {
        boolean result = false;
        if (activity != null) {
            try {
                WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
                Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
                Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
                darkFlag.setAccessible(true);
                meizuFlags.setAccessible(true);
                int bit = darkFlag.getInt(null);
                int value = meizuFlags.getInt(lp);
                if (dark) {
                    value |= bit;
                } else {
                    value &= ~bit;
                }
                meizuFlags.setInt(lp, value);
                activity.getWindow().setAttributes(lp);
                result = true;
            } catch (Exception e) {
            }
        }
        return result;
    }


    /**
     * 处理华为手机虚拟按键和底部导航遮挡问题
     * 出现原因-
     * getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
     * getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
     * 加:
     * -android::fitsSystemWindows="true"
     * 去除-FLAG_TRANSLUCENT_NAVIGATION
     * -仍旧不行使用本类-在setContentView(……
     * if (AndroidWorkaround.checkDeviceHasNavigationBar(this))
     * {
     * AndroidWorkaround.assistActivity(findViewById(android.R.id.content));
     * }
     */
    public static class AndroidWorkaround {

        public static void assistActivity(View content) {
            new AndroidWorkaround(content);
        }

        private View mChildOfContent;
        private int usableHeightPrevious;
        private ViewGroup.LayoutParams frameLayoutParams;

        private AndroidWorkaround(View content) {
            mChildOfContent = content;
            mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                public void onGlobalLayout() {
                    possiblyResizeChildOfContent();
                }
            });
            frameLayoutParams = mChildOfContent.getLayoutParams();
        }

        private void possiblyResizeChildOfContent() {
            int usableHeightNow = computeUsableHeight();
            if (usableHeightNow != usableHeightPrevious) {

                frameLayoutParams.height = usableHeightNow;
                mChildOfContent.requestLayout();
                usableHeightPrevious = usableHeightNow;
            }
        }

        private int computeUsableHeight() {
            Rect r = new Rect();
            mChildOfContent.getWindowVisibleDisplayFrame(r);
            return (r.bottom);
        }

        /**
         * 获取虚拟功能键高度
         */
        public static int getVirtualBarHeigh(Context context) {

            int vh = 0;
            WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            Display display = windowManager.getDefaultDisplay();
            DisplayMetrics dm = new DisplayMetrics();

            try {
                @SuppressWarnings("rawtypes")
                Class c = Class.forName("android.view.Display");
                @SuppressWarnings("unchecked")
                Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
                method.invoke(display, dm);
                vh = dm.heightPixels - windowManager.getDefaultDisplay().getHeight();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return vh;
        }

        //是否存在导航栏(虚拟功能键)
        public static boolean checkDeviceHasNavigationBar(Context context) {
            boolean hasNavigationBar = false;
            Resources rs = context.getResources();
            int id = rs.getIdentifier("config_showNavigationBar", "bool", "android");
            if (id > 0) {
                hasNavigationBar = rs.getBoolean(id);
            }
            try {
                Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
                Method m = systemPropertiesClass.getMethod("get", String.class);
                String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
                if ("1".equals(navBarOverride)) {
                    hasNavigationBar = false;
                } else if ("0".equals(navBarOverride)) {
                    hasNavigationBar = true;
                }
            } catch (Exception e) {

            }
            return hasNavigationBar;
        }

        //NavigationBar状态是否是显示
        public static boolean isNavigationBarShow(Context context) {
            Activity mContext = (Activity) context;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                Display display = mContext.getWindowManager().getDefaultDisplay();
                Point size = new Point();
                Point realSize = new Point();
                display.getSize(size);
                display.getRealSize(realSize);
                return realSize.y != size.y;
            } else {
                boolean menu = ViewConfiguration.get(context).hasPermanentMenuKey();
                boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
                if (menu || back) {
                    return false;
                } else {
                    return true;
                }
            }

        }
    }
}
/**
 * Created by LiJinWei on 2018/1/22.
 * webview-软键盘-冲突
 * 由于项目中WebView输入数据,软键盘不会顶上布局,遮盖住页面,
 * 使用下边此类解决冲突后出现底部导航栏被遮挡的问题。
 */
public class KeyBoardListenerManager {

    private Activity activity;
    private View mChildOfContent;
    private int usableHeightPrevious;
    private FrameLayout.LayoutParams frameLayoutParams;
    private static KeyBoardListenerManager keyBoardListener;


    public static KeyBoardListenerManager newInstance(Activity activity) {
        keyBoardListener = new KeyBoardListenerManager(activity);
        return keyBoardListener;
    }

    public KeyBoardListenerManager(Activity activity) {
        super();
        // TODO Auto-generated constructor stub
        this.activity = activity;
    }

    public void init() {
        FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
        mChildOfContent = content.getChildAt(0);
        mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                possiblyResizeChildOfContent();
            }
        });
        frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
    }


    private void possiblyResizeChildOfContent() {
        int usableHeightNow = computeUsableHeight();
        if (usableHeightNow != usableHeightPrevious) {
            int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
            int heightDifference = usableHeightSansKeyboard - usableHeightNow;
            if (heightDifference > (usableHeightSansKeyboard / 4)) {
                // keyboard probably just became visible
                frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
            } else {
                // keyboard probably just became hidden
                frameLayoutParams.height = usableHeightSansKeyboard;
            }
            mChildOfContent.requestLayout();
            usableHeightPrevious = usableHeightNow;
        }
    }

    private int computeUsableHeight() {
        Rect r = new Rect();
        mChildOfContent.getWindowVisibleDisplayFrame(r);
        return (r.bottom - r.top);
    }

}

这里面有个photoUtils,已经封装好了各种调用,简单好用

/**
 * Created by LiJinWei on 2018/1/31.
 */
public class PhotoUtils {

    private static final String TAG = "PhotoUtils";

    /**
     * @param activity    当前activity
     * @param imageUri    拍照后照片存储路径
     * @param requestCode 调用系统相机请求码
     */
    public static void takePicture(Activity activity, Uri imageUri, int requestCode) {
        //调用系统相机
        Intent intentCamera = new Intent();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            intentCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
        }
        intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        //将拍照结果保存至photo_file的Uri中,不保留在相册中
        intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        if (activity != null) {
            activity.startActivityForResult(intentCamera, requestCode);
        }
    }

    /**
     * @param activity    当前activity
     * @param requestCode 打开相册的请求码
     */
    public static void openPic(Activity activity, int requestCode) {
        Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
        photoPickerIntent.setType("image/*");
        activity.startActivityForResult(photoPickerIntent, requestCode);
    }

    /**
     * @param activity    当前activity
     * @param orgUri      剪裁原图的Uri
     * @param desUri      剪裁后的图片的Uri
     * @param aspectX     X方向的比例
     * @param aspectY     Y方向的比例
     * @param width       剪裁图片的宽度
     * @param height      剪裁图片高度
     * @param requestCode 剪裁图片的请求码
     */
    public static void cropImageUri(Activity activity, Uri orgUri, Uri desUri, int aspectX, int aspectY, int width, int height, int requestCode) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
        intent.setDataAndType(orgUri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", aspectX);
        intent.putExtra("aspectY", aspectY);
        intent.putExtra("outputX", width);
        intent.putExtra("outputY", height);
        intent.putExtra("scale", true);
        //将剪切的图片保存到目标Uri中
        intent.putExtra(MediaStore.EXTRA_OUTPUT, desUri);
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", true);
        activity.startActivityForResult(intent, requestCode);
    }

    /**
     * 读取uri所在的图片
     *
     * @param uri      图片对应的Uri
     * @param mContext 上下文对象
     * @return 获取图像的Bitmap
     */
    public static Bitmap getBitmapFromUri(Uri uri, Context mContext) {
        try {
//            Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), uri);
            Bitmap bitmapFormUri = getBitmapFormUri(mContext, uri);
            return bitmapFormUri;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 通过uri获取图片并进行压缩
     *
     * @param uri
     */
    public static Bitmap getBitmapFormUri(Context ac, Uri uri) throws FileNotFoundException, IOException {
        InputStream input = ac.getContentResolver().openInputStream(uri);
        BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
        onlyBoundsOptions.inJustDecodeBounds = true;
        onlyBoundsOptions.inDither = true;//optional
        onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
        BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
        input.close();
        int originalWidth = onlyBoundsOptions.outWidth;
        int originalHeight = onlyBoundsOptions.outHeight;
        if ((originalWidth == -1) || (originalHeight == -1)) {
            return null;
        }
        //图片分辨率以480x800为标准
        float hh = 1280f;//这里设置高度为800f
        float ww = 720f;//这里设置宽度为480f
        //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        int be = 1;//be=1表示不缩放
        if (originalWidth > originalHeight && originalWidth > ww) {//如果宽度大的话根据宽度固定大小缩放
            be = (int) (originalWidth / ww);
        } else if (originalWidth < originalHeight && originalHeight > hh) {//如果高度高的话根据宽度固定大小缩放
            be = (int) (originalHeight / hh);
        }
        if (be <= 0) {
            be = 1;
        }
        //比例压缩
        BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
        bitmapOptions.inSampleSize = be;//设置缩放比例
        bitmapOptions.inDither = true;//optional
        bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
        input = ac.getContentResolver().openInputStream(uri);
        Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
        input.close();
        return compressImage(bitmap);//再进行质量压缩
    }

    /**
     * 质量压缩方法
     *
     * @param image
     * @return
     */
    public static Bitmap compressImage(Bitmap image) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        int options = 100;
        while (baos.toByteArray().length / 1024 > 512) {  //循环判断如果压缩后图片是否大于100kb,大于继续压缩
            baos.reset();//重置baos即清空baos
            //第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差  ,第三个参数:保存压缩后的数据的流
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
            options -= 10;//每次都减少10
        }
        byte[] bytes = baos.toByteArray();
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
        return bitmap;
    }

    /**
     * bitmap 转 uri
     * @param c
     * @param b
     * @return
     */
    public static Uri bitmap2uri(Context c, Bitmap b) {
        File path = new File(c.getCacheDir() + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
        try {
            OutputStream os = new FileOutputStream(path);
            b.compress(Bitmap.CompressFormat.JPEG, 100, os);
            os.close();
            return Uri.fromFile(path);
        } catch (Exception ignored) {
        }
        return null;
    }

    /**
     * @param context 上下文对象
     * @param uri     当前相册照片的Uri
     * @return 解析后的Uri对应的String
     * 专为Android4.4设计的从Uri获取文件绝对路径,以前的方法已不好使
     */
    @SuppressLint("NewApi")
    public static String getPath(final Context context, final Uri uri) {

        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
        String pathHead = "file:///";
        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];
                if ("primary".equalsIgnoreCase(type)) {
                    return pathHead + Environment.getExternalStorageDirectory() + "/" + split[1];
                }
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);

                final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

                return pathHead + getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{split[1]};

                return pathHead + getDataColumn(context, contentUri, selection, selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            return pathHead + getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return pathHead + uri.getPath();
        }
        return null;
    }

    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context       The context.
     * @param uri           The Uri to query.
     * @param selection     (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = {column};
        try {
            cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int column_index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(column_index);
            }
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        return null;
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is ExternalStorageProvider.
     */
    private static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is DownloadsProvider.
     */
    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri The Uri to check.
     * @return Whether the Uri authority is MediaProvider.
     */
    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }


}
OK ! ! !  到这里 相信大家对WebView及所遇到的一些坑都有一定的了解,希望对你有帮助。给我点赞 再见 再见

猜你喜欢

转载自blog.csdn.net/lijinweii/article/details/79707776
今日推荐