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

android手机拍照6.0,7.0问题

程序员文章站 2022-05-09 15:09:56
...

因前期项目运行没有再7.0以上手机运行,最近一个同事用的华为8.0手机运行项目进行拍照,结果闪退,问题就来了,整的是焦头烂额啊,先是用的FilePrivider,网上好多博客都进行了讲解,我在使用过程中FileProvider.getUriForFile发现返回为空,结果,又忙乎了,最后忘了啥原因了改好了,但是我在下面代码中因为要得到图片具体路径,上传到阿里云服务器上,就是拿不到路径,空指针,办法试尽了,也是自己能力不够,就是不行;没办法,项目着急更新一版,就在网上找了找,看到了TakePhoto,感觉能实现我的问题,就用了这个第三方。

导入这个库的时候提示找不到,最后找了一个老版本就能导进去了,我用的这个版本

compile 'com.jph.takephoto:takephoto_library:3.0.0'

还有导入冲突问题,在文章末尾有解决办法
TakePhoto有两种方式:1是继承它的activity或者fragment;2是实现接口,重写方法,我是用的第二张

1.首先实现接口,重写三个方法

public class RealNameActivityStep1 extends Activity implements View.OnClickListener, TakePhoto.TakeResultListener, InvokeListener {
    @Override
    public void takeSuccess(TResult result) {
    }
    @Override
    public void takeFail(TResult result, String msg) {
    }
      @Override
    public void takeCancel() {
    }
}

同时记得加上6.0,7.0权限处理


    private InvokeParam invokeParam;
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //以下代码为处理Android6.0、7.0动态权限所需
        PermissionManager.TPermissionType type = PermissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
        PermissionManager.handlePermissionsResult(this, type, invokeParam, this);
    }

    @Override
    public PermissionManager.TPermissionType invoke(InvokeParam invokeParam) {
        PermissionManager.TPermissionType type = PermissionManager.checkPermission(TContextWrap.of(this), invokeParam.getMethod());
        if (PermissionManager.TPermissionType.WAIT.equals(type)) {
            this.invokeParam = invokeParam;
        }
        return type;
    }

还有重要一点,在 onCreate,onActivityResult,onSaveInstanceState方法中调用TakePhoto对用的方法。


    /**
     * 获取TakePhoto实例
     *
     * @return
     */
    public TakePhoto getTakePhoto() {
        if (takePhoto == null) {
            takePhoto = (TakePhoto) TakePhotoInvocationHandler.of(this).bind(new TakePhotoImpl(this, this));
        }
        return takePhoto;
    }
    //这三个方法里调用takeohoto的方法
        @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        getTakePhoto().onCreate(savedInstanceState);
   }       
        @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        getTakePhoto().onSaveInstanceState(outState);
        super.onSaveInstanceState(outState, outPersistentState);
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        getTakePhoto().onActivityResult(requestCode, resultCode, data);
        super.onActivityResult(requestCode, resultCode, data);
    }

看一下作者是怎么说的这个takephotot
支持通过相机拍照获取图片
支持从相册选择图片
支持从文件选择图片
支持批量图片选取
支持图片压缩以及批量图片压缩
支持图片裁切以及批量图片裁切
支持照片旋转角度自动纠正
支持自动权限管理(无需关心SD卡及摄像头权限等问题)
支持对裁剪及压缩参数个性化配置
提供自带裁剪工具(可选)
支持智能选取及裁剪异常处理
支持因拍照Activity被回收后的自动恢复
支持Android8.1
+支持多种压缩工具
+支持多种图片选择工具

TakePhoto提供拍照,从相册选择,从文件中选择三种方式获取图片。

API:
/**
 * 从文件中获取图片(不裁剪)
 */
void onPickFromDocuments();
/**
 * 从相册中获取图片(不裁剪)
 */
void onPickFromGallery();
/**
 * 从相机获取图片(不裁剪)
 * @param outPutUri 图片保存的路径
 */
void onPickFromCapture(Uri outPutUri);
/**
 * 图片多选
 * @param limit 最多选择图片张数的限制
 **/
void onPickMultiple(int limit);

TakePhoto支持对图片进行裁剪,无论是拍照的照片,还是从相册、文件中选择的图片。你只需要调用TakePhoto的相应方法即可:

API:
/**
 * 从相机获取图片并裁剪
 * @param outPutUri 图片裁剪之后保存的路径
 * @param options 裁剪配置             
 */
void onPickFromCaptureWithCrop(Uri outPutUri, CropOptions options);
/**
 * 从相册中获取图片并裁剪
 * @param outPutUri 图片裁剪之后保存的路径
 * @param options 裁剪配置
 */
void onPickFromGalleryWithCrop(Uri outPutUri, CropOptions options);
/**
 * 从文件中获取图片并裁剪
 * @param outPutUri 图片裁剪之后保存的路径
 * @param options 裁剪配置
 */
void onPickFromDocumentsWithCrop(Uri outPutUri, CropOptions options);
/**
 * 图片多选,并裁切
 * @param limit 最多选择图片张数的限制
 * @param options  裁剪配置
 * */
void onPickMultipleWithCrop(int limit, CropOptions options);

另外,TakePhoto也支持你对指定图片进行裁剪:

/**
 * 裁剪图片
 * @param imageUri 要裁剪的图片
 * @param outPutUri 图片裁剪之后保存的路径
 * @param options 裁剪配置
 */
void onCrop(Uri imageUri, Uri outPutUri, CropOptions options)throws TException;
/**
 * 裁剪多张图片
 * @param multipleCrop 要裁切的图片的路径以及输出路径
 * @param options 裁剪配置
 */
void onCrop(MultipleCrop multipleCrop, CropOptions options)throws TException;

压缩图片
你可以选择是否对图片进行压缩处理,你只需要告诉它你是否要启用压缩功能以及CompressConfig即可。

API
 /**
  * 启用图片压缩
  * @param config 压缩图片配置
  * @param showCompressDialog 压缩时是否显示进度对话框
  * @return
  */
 void onEnableCompress(CompressConfig config,boolean showCompressDialog);

TakePhoto takePhoto=getTakePhoto();
takePhoto.onEnableCompress(compressConfig,true);
takePhoto.onPickFromGallery();

对指定图片进行压缩
另外,你也可以对指定图片进行压缩:

Usage:

new CompressImageImpl(compressConfig,result.getImages(), new CompressImage.CompressListener() {
    @Override
    public void onCompressSuccess(ArrayList<TImage> images) {
        //图片压缩成功
    }
    @Override
    public void onCompressFailed(ArrayList<TImage> images, String msg) {
        //图片压缩失败
    }
}).compress();

CompressConfig compressConfig=new CompressConfig.Builder().setMaxSize(50*1024).setMaxPixel(800).create();

还有好多,就不贴了,自己用不到,具体github搜索takephoto就有全部

我基本就用了两个,一个拍照图片显示并上传到阿里云服务器,另一个就是相册选取上传阿里云

自己用这个的好处,也正是吸引我的地方,能解决我问题的地方:

强调内容

兼容性
Android6.0
由于Android6.0新增了”运行时权限控制(Runtime Permissions)”,为了应对这一改变,TakePhoto加入和自动权限管理,当TakePhoto检测到需要权限时,TakePhoto会自动申请权限,所以小伙伴们不用担心权限的使用问题。

Android7.0
在Android N中,Android 框架执行了 StrictMode,应用间共享文件和以前也有所区别。为了适配Android7.0的改变,同时也为了方便大家使用TakePhoto,TakePhoto会自动根据手机的Android版本自行适配,小伙伴们依旧可以向TakePhoto传递Uri imageUri = Uri.fromFile(file);类型的Uri而不用担心兼容性问题。

主要代码:

    /**
     * @param request 区分是相册还是拍照 1是拍照,2是相册
     */
    private void openPhoto(int request) {
        File file = new File(Environment.getExternalStorageDirectory(), "/temp/" + System.currentTimeMillis() + ".jpg");
        if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
        Uri imageUri = Uri.fromFile(file);
        if (request == 1) {
            //file:///storage/emulated/0/temp/1527231988466.jpg
            takePhoto.onPickFromCapture(imageUri);
        }
        takePhoto.onPickFromGallery();
    }
    //上面原来这么写的,但是不对,在快下班时候才发现,应该加改成如下:
        /**
     * @param request 区分是相册还是拍照
     */
    private void openPhoto(int request) {
        File file = new File(Environment.getExternalStorageDirectory(), "/temp/" + System.currentTimeMillis() + ".jpg");
        if (!file.getParentFile().exists()) file.getParentFile().mkdirs();
        Uri imageUri = Uri.fromFile(file);
        if (request == 1) {
            //file:///storage/emulated/0/temp/1527231988466.jpg
            takePhoto.onPickFromCapture(imageUri);
        } else {
            takePhoto.onPickMultiple(1);
        }
    }

然后拍照成功后会回调

    @Override
    public void takeSuccess(TResult result) {
//具体实现图片上传的功能了,我的是上传身份证,1是正面,2是反面;这里主要是拿到图片路径result.getImage().getPath(),以下涉及业务,不能写了
        if (isImage1) {
            getImgKey("身份证", result.getImage().getPath(), "01", SPUtil.getString(SysParam.TOKEN));
        }
        if (isImage2) {
            getImgKey("身份证", result.getImage().getPath(), "02", SPUtil.getString(SysParam.TOKEN));
        }

    }

然后写完了,运行在6.0以上手机上,拍照直接进不去,过一会崩了,一看日志,才知道又是那个7.0文件的问题,虽然作者说了:
重点内容
Android7.0
在Android N中,Android 框架执行了 StrictMode,应用间共享文件和以前也有所区别。为了适配Android7.0的改变,同时也为了方便大家使用TakePhoto,TakePhoto会自动根据手机的Android版本自行适配,小伙伴们依旧可以向TakePhoto传递Uri imageUri = Uri.fromFile(file);类型的Uri而不用担心兼容性问题。
但是还是报 java.lang.IllegalArgumentException:Failed to find configured root that contains /storage/emulated/0/temp/1527233829268.jpg
解决办法就是加个xml文件,manifests里面就不用配置provider了
android手机拍照6.0,7.0问题

provider_path.xml内容,这个网上好多解释,自己不是很懂

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <cache-path name="cache_dir" path="."/>
    <external-cache-path name="external_dir" path="." />
</paths>

对了有一点,因为之前我在导入这个takephoto之前它提示有冲突,我之前用的FileProvider7.0以上拍照,在清单文件里配置了这个:

        <provider
            android:authorities="你的包名.fileprovider"
            android:name="android.support.v4.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_path" />
            ></provider>

因为配置了provider,提示冲突,后来我给注释掉就成功了;个人怀疑,作者的这个TakePhoto里面已经加了这个provider了,不然这个第三方在7.0以上拍照也肯定会失败,所以清单文件里就不用写了,但是xml文件必须得建,不然进不去相机
这样就ok了!成功了,之前因为拍照要显示到页面,还得上传,因为现在手机太乱了,返回的date有的是空,有的拿不到uri路径,就报空指针,很是操蛋,所以就另想了个办法,我是先上传图片,上传成功一霎那再网络进行获取图片,显示到imageview上,就跳过了那个返回路径问题。
还有另外一个简单的办法:
Glide不是能直接传图片路径吗,你可以和后台商量一下定死一个域名,例如:http://www.baidu.com/,这就可以写死,后面拼接上你的拍照或者相册选取的图片名,是不是就不用费事的网络请求,然后解析json串,拿到图片路径,最后glide加载出来,想法是不是很好,但是你后台的得给力啊,愿意帮你整,我这里没用这个办法,后台不在,只是提供一个思路。
例如:

//图片名可以考虑在takeSuccess的result里获取,感觉不一定能获取到
    @Override
    public void takeSuccess(TResult result) {
    }
//也可以考虑在onActivityResult获取,只要能或获取到就行,这两个方法可以试试
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    }
 //最后直接一步:
 Glide.with(this).load("http://www.baidu.com/"+图片名).into(mImageView);

OK了,完活!

相关标签: p