Android 6.0 动态权限参考 https://blog.csdn.net/qq_27400335/article/details/79412774
Android 7.0 文件写入问题
在AndroidManifest.xml 配置 FileProvider
为了防止重复 android:authorities 一般配置为 包名.fileProvider
第二步
res添加 xml文件夹,添加file_paths.xml 写入:
//调用册并裁减
//fileName 为全局变量(这里为了直观就没有写)
String fileName = CameraUtils.photoAlbum(activity);
----------------------------------------------------------
//调用拍照并裁剪
String fileName = CameraUtils.photograph(activity);
------------------------------------------------------------------------------------
//调用拍视频
fileName = CameraUtils.shootVideo(activity);
--------------------------------------------------------------------------------------
//调用录音
CameraUtils.startRecord(new CameraUtils.RecordingCallBack() {
@Override
public void name(String name) {
fileName = name;
}
@Override
public void intent(Intent intent) {
startActivityForResult(intent, CameraUtils.RECORD_FLAG);
}
});
--------------------------------------------------------------------------------------------
//回调
//裁剪后的图片uri
private Uri cropUri;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode==-1){
if (requestCode == CameraUtils.CAMERA_FLAG){
//相机
Uri uri= CameraUtils.compressCameraImg(mContext,fileName);
if (uri!=null){
//如不需要裁剪 可不走这一步
cropUri=CameraUtils.crop(uri,this);
}
}else if (requestCode == CameraUtils.PHOTO_FLAG){
//相册
Uri uri = data.getData();
if (uri!=null){
//如不需要裁剪 可不走这一步
cropUri=CameraUtils.crop(uri,this);
}
}else if (requestCode == CameraUtils.CROP_FLAG){
//裁剪回调
if (cropUri!=null){
File file = null;
try {
file = new File(new URI(cropUri.toString()));
.......
} catch (URISyntaxException e) {
e.printStackTrace();
}
}else {
T.showShort(mContext,"裁剪失败");
}
}else if (requestCode == CameraUtils.VIDEO_FLAG){
//视频回调 path 为视频地址
String path = CameraUtils.PRESERVE_PATH+"/" + fileName;
if (!TextUtils.isEmpty(fileName)){
//视频资料
MediaMetadataRetriever media = new MediaMetadataRetriever();
media.setDataSource(path);
//获取时长 单位秒
String duration = media.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
//旋转角度
String rotation = media.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
........
}
}else if (requestCode == CameraUtils.RECORD_FLAG) {
//录音回调 uri 录音资源
Uri uri = data.getData();
String path = CameraUtils.PRESERVE_PATH+"/" + fileName;
if (uri != null) {
String temp = CameraUtils.getAudioFilePathFromUri(uri, getActivity());
boolean b = CameraUtils.saveVoiceToSD(temp);
File file = new File(path);
if (b && file.exists()) {
//path 录音路径
...
}
}
}
}
---------------------------------------------------------------------------------------------------------------------------------
//压缩图片(鲁班 Luban)
添加依赖:implementation 'top.zibin:Luban:1.1.3'
Luban.with(this)
.load(stringList)// 传人要压缩的图片列表 也可单张
.ignoreBy(100) // 忽略不压缩图片的大小
.setTargetDir("") // 设置压缩后文件存储位置
.setCompressListener(new OnCompressListener() { //设置回调
@Override
public void onStart() {
}
@Override
public void onSuccess(File file) {
// TODO 压缩成功后调用,返回压缩后的图片文件
}
@Override
public void onError(Throwable e) {
// TODO 当压缩过程出现问题时调用
}
}).launch(); //启动压缩
-----------------工具类----------------------
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
/**
* Created by Administrator on 2019/3/12 0012.
*/
public class CameraUtils {
//相机回调
public static int CAMERA_FLAG = 1;
//视频回调
public static int VIDEO_FLAG = 2;
//录音回调
public static int RECORD_FLAG = 3;
//裁剪回调
public static int CROP_FLAG = 4;
//相册回调
public static int PHOTO_FLAG = 3;
private static String fileName;
private static String mVoicePath;
//裁剪后图片保存路径
private static final String IMAGE_FILE_LOCATION = "file:///sdcard/temp.jpg";
//文件保存路劲
private static final String PRESERVE_PATH = Environment.getExternalStorageDirectory() + "/宝宝印记";
//provider
private static final String FILE_PROVIDER_NAME = "包名.fileProvider";
/**
* 拍照
* @param activity
* @return
*/
public static String photograph(Activity activity){
fileName=null;
UUID uuid = UUID.randomUUID();
fileName = uuid + ".png";
//将拍摄的照片保存在一个指定好的文件下
File dir= new File(PRESERVE_PATH);
if(!dir.exists()){
dir.mkdirs();
}
File f = new File(dir, fileName);
Uri u = Uri.fromFile(f);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//通过FileProvider创建一个content类型的Uri
u = FileProvider.getUriForFile(activity, FILE_PROVIDER_NAME, f);
}
//调用系统相机
Intent intentCamera = new Intent();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//添加这一句表示对目标应用临时授权该Uri所代表的文件
intentCamera.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
intentCamera.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
//将拍照结果保存至photo_file的Uri中,不保留在相册中
intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, u);
activity.startActivityForResult(intentCamera, CAMERA_FLAG);
return fileName;
}
/**
* 相册
* @param activity
* @return
*/
public static String photoAlbum(Activity activity){
UUID uuid = UUID.randomUUID();
fileName = uuid + ".png";
Intent intent = new Intent(Intent.ACTION_PICK);
//相片类型
intent.setType("image/*");
activity.startActivityForResult(intent, PHOTO_FLAG);
return fileName;
}
/**
* 裁剪
* @param uri
*/
public static Uri crop(Uri uri,Activity activity){
Uri imageUri = Uri.parse(IMAGE_FILE_LOCATION);
Intent intent = new Intent("com.android.camera.action.CROP");
//图片资源uri
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 300);
intent.putExtra("outputY", 300);
intent.putExtra("scale", true);
//截图返回的uri
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
intent.putExtra("return-data", false);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
intent.putExtra("noFaceDetection", true);
activity.startActivityForResult(intent, CROP_FLAG);
return imageUri;
}
/**
* 视频
* @param activity
* @return
*/
public static String shootVideo(Activity activity){
fileName=null;
UUID uuid = UUID.randomUUID();
fileName = uuid + ".mp4";
//将拍摄的照片保存在一个指定好的文件下
File dir= new File(PRESERVE_PATH);
if(!dir.exists()){
dir.mkdirs();
}
File f = new File(dir, fileName);
Uri u = Uri.fromFile(f);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//通过FileProvider创建一个content类型的Uri
u = FileProvider.getUriForFile(activity, FILE_PROVIDER_NAME, f);
}
//调用系统相机
Intent intentVideo = new Intent();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//添加这一句表示对目标应用临时授权该Uri所代表的文件
intentVideo.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
intentVideo.setAction(MediaStore.ACTION_VIDEO_CAPTURE);
intentVideo.addCategory(Intent.CATEGORY_DEFAULT);
//将拍照结果保存至photo_file的Uri中,不保留在相册中
intentVideo.putExtra(MediaStore.EXTRA_OUTPUT, u);
activity.startActivityForResult(intentVideo, VIDEO_FLAG);
return fileName;
}
/**
* 启动录音机,创建文件
*/
public static void startRecord(RecordingCallBack callBack) {
UUID uuid = UUID.randomUUID();
fileName = uuid + ".amr";
//将拍摄的照片保存在一个指定好的文件下
File dir= new File(PRESERVE_PATH);
if(!dir.exists()){
dir.mkdirs();
}
callBack.name(fileName);
File f = new File(dir, fileName);
mVoicePath = f.getAbsolutePath();
f.setWritable(true);
Intent intentRecord = new Intent();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//添加这一句表示对目标应用临时授权该Uri所代表的文件
intentRecord.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
intentRecord.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
callBack.intent(intentRecord);
}
/**
* 通过Uri,获取录音文件的路径(绝对路径)
*
* @param uri 录音文件的uri
* @return 录音文件的路径(String)
*/
public static String getAudioFilePathFromUri(Uri uri,Activity activity) {
Cursor cursor = activity.getContentResolver()
.query(uri, null, null, null, null);
cursor.moveToFirst();
int index = cursor.getColumnIndex(MediaStore.Audio.AudioColumns.DATA);
String temp = cursor.getString(index);
cursor.close();
return temp;
}
/**
* 保存音频到SD卡的指定位置
*
* @param path 录音文件的路径
*/
public static boolean saveVoiceToSD(String path) {
boolean b = false;
//创建输入输出
InputStream isFrom = null;
OutputStream osTo = null;
try {
//设置输入输出流
isFrom = new FileInputStream(path);
osTo = new FileOutputStream(mVoicePath);
byte bt[] = new byte[1024];
int len;
while ((len = isFrom.read(bt)) != -1) {
osTo.write(bt, 0, len);
}
Log.d("TAG_Path", "保存录音完成。");
b=true;
} catch (IOException e) {
e.printStackTrace();
b=false;
Log.d("TAG_Path", "e:"+e.toString());
} finally {
if (osTo != null) {
try {
//不管是否出现异常,都要关闭流
osTo.close();
Log.d("TAG_Path", "关闭输出流");
} catch (IOException e) {
e.printStackTrace();
b=false;
}
}
if (isFrom != null) {
try {
isFrom.close();
Log.d("TAG_Path", "关闭输入流");
} catch (IOException e) {
e.printStackTrace();
b=false;
}
}
}
return b;
}
public interface RecordingCallBack{
void name(String name);
void intent(Intent intent);
}
public static Uri compressCameraImg(Context mContext,String fileName){
Uri imgUrl=null;
if (fileName==null){
return null;
}
//返回原图
File fData = new File(PRESERVE_PATH+"/" + fileName);
try {
imgUrl = Uri.parse(MediaStore.Images.Media.insertImage(mContext.getContentResolver(), fData.getAbsolutePath(), null, null));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return imgUrl;
}
/**
* android 转换 content://media/external/images/media/xxx
* @param context
* @param contentUri
* @return
*/
public static String getRealPathFromUri(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
/**
* 获取图片旋转角度
* 注意:获取图片旋转角度之前不能做任何操作(如:压缩、裁剪)
* 注意:在高版本中 ExifInterface 会抛异常
* 解决方法:添加ExifInterface的依赖 implementation "com.android.support:exifinterface:27.1.1"(对应自己的SDK版本)
* @param path 图片路径
* @return 图片旋转角度
*/
public static int readPictureDegree(String path) {
int degree = 0;
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
default:
break;
}
} catch (IOException e) {
e.printStackTrace();
return degree;
}
return degree;
}
/**
* 旋转图片
* @param degree 旋转角度
* @param bitmap 旋转图片
* @return
*/
public static Bitmap rotaingImageView(int degree, Bitmap bitmap) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), matrix, true);
return resizedBitmap;
}
/**
* 旋转图片并保存到本地
* @param degree 旋转角度
* @param bitmap 旋转图片
* @return 返回图片路径
*/
public static String rotaingImageViewAndSave(Activity activity,int degree, Bitmap bitmap) {
String path = null;
Matrix matrix = new Matrix();
matrix.postRotate(degree);
//设置图片缩放比例 长和宽放大缩小的比例
//matrix.postScale(0.5f,0.5f);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), matrix, true);
if (resizedBitmap!=null){
//保存照片
path = saveBitmap(activity,resizedBitmap,"");
}
return path;
}
/**
* 保存文件到相册,文件名为当前日期
* @param activity
* @param bitmap 图片资源
* @param imageName 图片名称
* @return 返回图片路径
*/
public static String saveBitmap(Activity activity,Bitmap bitmap, String imageName){
String fileName ;
File file =null;
if(Build.BRAND .equals("Xiaomi") ){
fileName = Environment.getExternalStorageDirectory().getPath()+"/DCIM/Camera/"+imageName ;
}else{
fileName = Environment.getExternalStorageDirectory().getPath()+"/DCIM/"+imageName ;
}
file = new File(fileName);
if(file.exists()){
file.delete();
}
FileOutputStream out;
try{
out = new FileOutputStream(file);
// 格式为 JPEG,照相机拍出的图片为JPEG格式的,PNG格式的不能显示在相册中
if(bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)){
out.flush();
out.close();
// 插入图库
MediaStore.Images.Media.insertImage(activity.getContentResolver(), file.getAbsolutePath(), imageName, null);
}
} catch (IOException e) {
e.printStackTrace();
}
// 发送广播,通知刷新图库的显示
activity.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + fileName)));
if (file != null){
return file.getPath();
}else {
return "";
}
}
}