由于Android7.0对权限的一些改动,我们不分手机无法访问到文件地址,那是因为在,官方7.0的以上的系统中,尝试传递 file://URI
可能会触发FileUriExposedException
。
拍照汇报
java.lang.SecurityException: Permission 等等异常
(1)声明provider --AndoidManifest中
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="(你的包名).fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
注意一点,他需要设置一个meta-data,里面指向一个xml文件。
(2)编写resource xml file
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path path="Android/data/你的包名/" name="files_root" />
<!--<external-path path="Android/data/com.yun.yunball/" name="files_root" />-->
<external-path path="/" name="myyunball" />
</paths>
以下是我fragment的全部代码 具体细节自己看
package com.yun.yunball.ui.home.mine.infosetting;
import android.Manifest;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.example.xiongchen.uibase.uiFrame.BaseBackFragment;
import com.yun.yunball.R;
import com.yun.yunball.ui.activity.MainActivity;
import com.yun.yunball.ui.home.mine.infosetting.presenter.InfoSettingPresenter;
import com.yun.yunball.ui.home.mine.infosetting.presenter.InfoSettingView;
import com.yun.yunball.utils.PermissionsChecker;
import com.yun.yunball.utils.popupwindow.PhotoPopupWindow;
import com.yun.yunball.widgets.CircleImageView;
import java.io.File;
import java.io.FileOutputStream;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
/**
* 个人信息设置界面
*/
public class InfoSettingFragment extends BaseBackFragment implements InfoSettingView {
@BindView(R.id.tv_top_left)
TextView tvTopLeft;
@BindView(R.id.tv_mid_title)
TextView tvMidTitle;
@BindView(R.id.info_setting_pic)
CircleImageView infoSettingPic;
@BindView(R.id.info_setting_pic_linear)
LinearLayout infoSettingPicLinear;
@BindView(R.id.info_setting_name)
TextView infoSettingName;
@BindView(R.id.info_setting_name_linear)
LinearLayout infoSettingNameLinear;
@BindView(R.id.info_setting_tips)
TextView infoSettingTips;
@BindView(R.id.info_setting_tips_linear)
LinearLayout infoSettingTipsLinear;
@BindView(R.id.info_setting_sex)
TextView infoSettingSex;
@BindView(R.id.info_setting_sex_linear)
LinearLayout infoSettingSexLinear;
@BindView(R.id.info_setting_signature)
TextView infoSettingSignature;
@BindView(R.id.info_setting_signature_linear)
LinearLayout infoSettingSignatureLinear;
@BindView(R.id.info_setting_address)
TextView infoSettingAddress;
@BindView(R.id.info_setting_address_linear)
LinearLayout infoSettingAddressLinear;
@BindView(R.id.info_setting_influence)
TextView infoSettingInfluence;
@BindView(R.id.info_setting_influence_linear)
LinearLayout infoSettingInfluenceLinear;
private Unbinder mBind;
private InfoSettingPresenter mPresenter;
private PermissionsChecker mPermissionsChecker; // 权限检测器
static final String[] PERMISSIONS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA};
private Uri imageUri;//原图保存地址
private boolean isClickCamera;
private String imagePath;
private PhotoPopupWindow mPhotoPopupWindow;
private Uri mImageUri;
public static InfoSettingFragment newInstance() {
Bundle args = new Bundle();
InfoSettingFragment fragment = new InfoSettingFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_mine_info_setting, container, false);
mBind = ButterKnife.bind(this, view);
mPermissionsChecker = new PermissionsChecker(getActivity());
mPresenter = new InfoSettingPresenter(getActivity(), this);
tvMidTitle.setText("个人资料");
tvTopLeft.setText("后退");
responseListener();
return view;
}
private void responseListener() {
}
@OnClick({R.id.info_setting_pic_linear, R.id.info_setting_name_linear, R.id.info_setting_tips_linear,
R.id.info_setting_sex_linear, R.id.info_setting_signature_linear, R.id.info_setting_address_linear,
R.id.info_setting_influence_linear})
public void multipleOnclick(View view) {
switch (view.getId()) {
case R.id.info_setting_pic_linear:
selectPhoto();
Toast.makeText(getActivity(), "共同处理方法-----1", Toast.LENGTH_SHORT).show();
break;
case R.id.info_setting_name_linear:
Toast.makeText(getActivity(), "共同处理方法-----2", Toast.LENGTH_SHORT).show();
break;
case R.id.info_setting_tips_linear:
Toast.makeText(getActivity(), "共同处理方法-----3", Toast.LENGTH_SHORT).show();
break;
case R.id.info_setting_sex_linear:
break;
case R.id.info_setting_signature_linear:
break;
case R.id.info_setting_address_linear:
break;
case R.id.info_setting_influence_linear:
break;
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
mBind.unbind();
}
@Override
public boolean onBackPressedSupport() {
return super.onBackPressedSupport();
}
@Override
public void showLoadingDialog() {
}
@Override
public void hideLoadingDialog() {
}
@Override
public void showMyToast(String string) {
}
private static final int REQUEST_IMAGE_GET = 0;
private static final int REQUEST_IMAGE_CAPTURE = 1;
private static final int REQUEST_SMALL_IMAGE_CUTTING = 2;
private static final int REQUEST_BIG_IMAGE_CUTTING = 3;
private static final String IMAGE_FILE_NAME = "icon.jpg";
//选择照片还是拍照
public void selectPhoto() {
//打开相册
//检查权限(6.0以上做权限判断)
mPhotoPopupWindow = new PhotoPopupWindow(getActivity(), new View.OnClickListener() {
@Override
public void onClick(View v) {
// 权限申请
if (ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//权限还没有授予,需要在这里写申请权限的代码
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 200);
} else {
// 如果权限已经申请过,直接进行图片选择
mPhotoPopupWindow.dismiss();
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
// 判断系统中是否有处理该 Intent 的 Activity
if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_IMAGE_GET);
} else {
Toast.makeText(getActivity(), "未找到图片查看器", Toast.LENGTH_SHORT).show();
}
}
}
}, new View.OnClickListener() {
@Override
public void onClick(View v) {
// 权限申请
if (ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// 权限还没有授予,需要在这里写申请权限的代码
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 300);
} else {
// 权限已经申请,直接拍照
mPhotoPopupWindow.dismiss();
imageCapture();
}
}
});
View rootView = LayoutInflater.from(getActivity())
.inflate(R.layout.fragment_mine_info_setting, null);
mPhotoPopupWindow.showAtLocation(rootView,
Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// 回调成功
if (resultCode == RESULT_OK) {
switch (requestCode) {
// 小图切割
case REQUEST_SMALL_IMAGE_CUTTING:
if (data != null) {
setPicToView(data);
}
break;
// 大图切割
case REQUEST_BIG_IMAGE_CUTTING:
Bitmap bitmap = BitmapFactory.decodeFile(mImageUri.getEncodedPath());
Log.e("mImageUri", "=========mImageUri=========" + mImageUri);
File file = new File(mImageUri.getPath());
Log.e("mImageUri", "=========file===getPath======" + file.getPath());
Log.e("mImageUri", "=========file===getAbsolutePath======" + file.getAbsolutePath());
infoSettingPic.setImageBitmap(bitmap);
break;
// 相册选取
case REQUEST_IMAGE_GET:
try {
// startSmallPhotoZoom(data.getData());
startBigPhotoZoom(data.getData());
} catch (NullPointerException e) {
e.printStackTrace();
}
break;
// 拍照
case REQUEST_IMAGE_CAPTURE:
File temp = new File(Environment.getExternalStorageDirectory() + "/" + IMAGE_FILE_NAME);
// startSmallPhotoZoom(Uri.fromFile(temp));
startBigPhotoZoom(temp);
}
}
}
/**
* 处理权限回调结果
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 200:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mPhotoPopupWindow.dismiss();
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
// 判断系统中是否有处理该 Intent 的 Activity
if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_IMAGE_GET);
} else {
Toast.makeText(getActivity(), "未找到图片查看器", Toast.LENGTH_SHORT).show();
}
} else {
mPhotoPopupWindow.dismiss();
}
break;
case 300:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mPhotoPopupWindow.dismiss();
imageCapture();
} else {
mPhotoPopupWindow.dismiss();
}
break;
}
}
/**
* 小图模式切割图片
* 此方式直接返回截图后的 bitmap,由于内存的限制,返回的图片会比较小
*/
public void startSmallPhotoZoom(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
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);
intent.putExtra("return-data", true);
startActivityForResult(intent, REQUEST_SMALL_IMAGE_CUTTING);
}
/**
* 判断系统及拍照
*/
private void imageCapture() {
Intent intent;
Uri pictureUri;
File pictureFile = new File(Environment.getExternalStorageDirectory(), IMAGE_FILE_NAME);
// 判断当前系统
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//记得填写自己的包名 别无脑的copy
// pictureUri = FileProvider.getUriForFile(getActivity(),
// "你的包名.fileProvider", pictureFile);
pictureUri = FileProvider.getUriForFile(getActivity(),
"com.yun.yunball.fileProvider", pictureFile);
} else {
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
pictureUri = Uri.fromFile(pictureFile);
}
// 去拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri);
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
}
/**
* 大图模式切割图片
* 直接创建一个文件将切割后的图片写入
*/
public void startBigPhotoZoom(File inputFile) {
// 创建大图文件夹
Uri imageUri = null;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String storage = Environment.getExternalStorageDirectory().getPath();
File dirFile = new File(storage + "/bigIcon");
if (!dirFile.exists()) {
if (!dirFile.mkdirs()) {
Log.e("TAG", "文件夹创建失败");
} else {
Log.e("TAG", "文件夹创建成功");
}
}
File file = new File(dirFile, System.currentTimeMillis() + ".jpg");
imageUri = Uri.fromFile(file);
mImageUri = imageUri; // 将 uri 传出,方便设置到视图中
}
// 开始切割
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(getImageContentUri(getActivity(), inputFile), "image/*");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1); // 裁剪框比例
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 600); // 输出图片大小
intent.putExtra("outputY", 600);
intent.putExtra("scale", true);
intent.putExtra("return-data", false); // 不直接返回数据
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // 返回一个文件
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
// intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent, REQUEST_BIG_IMAGE_CUTTING);
}
public void startBigPhotoZoom(Uri uri) {
// 创建大图文件夹
Uri imageUri = null;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String storage = Environment.getExternalStorageDirectory().getPath();
File dirFile = new File(storage + "/bigIcon");
if (!dirFile.exists()) {
if (!dirFile.mkdirs()) {
Log.e("TAG", "文件夹创建失败");
} else {
Log.e("TAG", "文件夹创建成功");
}
}
File file = new File(dirFile, System.currentTimeMillis() + ".jpg");
imageUri = Uri.fromFile(file);
mImageUri = imageUri; // 将 uri 传出,方便设置到视图中
}
// 开始切割
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1); // 裁剪框比例
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 600); // 输出图片大小
intent.putExtra("outputY", 600);
intent.putExtra("scale", true);
intent.putExtra("return-data", false); // 不直接返回数据
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // 返回一个文件
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
// intent.putExtra("noFaceDetection", true); // no face detection
startActivityForResult(intent, REQUEST_BIG_IMAGE_CUTTING);
}
public Uri getImageContentUri(Context context, File imageFile) {
String filePath = imageFile.getAbsolutePath();
Cursor cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Images.Media._ID},
MediaStore.Images.Media.DATA + "=? ",
new String[]{filePath}, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor
.getColumnIndex(MediaStore.MediaColumns._ID));
Uri baseUri = Uri.parse("content://media/external/images/media");
return Uri.withAppendedPath(baseUri, "" + id);
} else {
if (imageFile.exists()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, filePath);
return context.getContentResolver().insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
}
/**
* 小图模式中,保存图片后,设置到视图中
* 将图片保存设置到视图中
*/
private void setPicToView(Intent data) {
Bundle extras = data.getExtras();
if (extras != null) {
Bitmap photo = extras.getParcelable("data");
// 创建 smallIcon 文件夹
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
String storage = Environment.getExternalStorageDirectory().getPath();
File dirFile = new File(storage + "/smallIcon");
if (!dirFile.exists()) {
if (!dirFile.mkdirs()) {
Log.e("TAG", "文件夹创建失败");
} else {
Log.e("TAG", "文件夹创建成功");
}
}
File file = new File(dirFile, System.currentTimeMillis() + ".jpg");
// 保存图片
FileOutputStream outputStream;
try {
outputStream = new FileOutputStream(file);
photo.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
outputStream.flush();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 在视图中显示图片
infoSettingPic.setImageBitmap(photo);
}
}
}
到此为止,解决完毕