我正在尝试使用相机并保存图像。按照Commonware建议的步骤进行操作。我经常出错-
2018-11-12 02:10:54.588 3145-3173/inder.execE/Database aseUtils:写入异常到包裹inder.java:682安全异常:权限拒绝:写入android.support.v4.content.FileProvider uricontent://com.bisw.weac.provider/external_files/Android/data/com.bisw.weac/files/wallpaper/theme.jpg从pid=5566, uid=10071要求提供者被导出,或grantUriPersion()在android.content.ContentProvider.enforceWritePermission内(ContentProvider.java:713)在android.content.ContentProvider$Transport.enforceWritePermis(ContentProvider.java:519)在android.content.ContentProvider$Transport.enforceFilePermis(ContentProvider.java:491)在android.content.ContentProvider$Transport.openAssetFile(ContentProvider.java:389)在android.content.ContentProviderNative.onTransact(ContentProviderNative.java:251)在android.os.Bcom.bisw.weacTransact(Bjava.lang.)
我几乎尝试了所有类似-intent.add标志(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
但没有任何帮助。我正在从相机中裁剪图像。活动代码
public class LocalAlbumActivity extends BaseActivity implements View.OnClickListener {
private static final int REQUEST_IMAGE_CAPTURE_THEME = 1;
private static final int REQUEST_IMAGE_CAPTURE_QRCODE_LOGO = 4;
private static final int REQUEST_IMAGE_CROP_THEME = 2;
private static final int REQUEST_IMAGE_CROP_QRCODE_LOGO = 5;
private static final int REQUEST_ALBUM_DETAIL = 3;
public static final String ALBUM_PATH = "album_path";
public static final String ALBUM_NAME = "album_name";
private LocalAlbumAdapter mLocalAlbumAdapter;
private List<ImageBucket> mLocalAlbumList;
private AsyncTask<Void, Void, List<ImageBucket>> mBucketLoadTask;
private ListView mLocalAlbumListView;
/**
* 访问本地相册类型:0,主题;1,扫码;2,造码
*/
private int mRequestType;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OttoAppConfig.getInstance().register(this);
setContentView(R.layout.activity_local_album);
ViewGroup backGround = (ViewGroup) findViewById(R.id.background);
MyUtil.setBackgroundBlur(backGround, this);
initAdapter();
assignViews();
}
private void initAdapter() {
mLocalAlbumList = new ArrayList<>();
mLocalAlbumAdapter = new LocalAlbumAdapter(this, mLocalAlbumList);
//trying permission
mBucketLoadTask = new AsyncTask<Void, Void, List<ImageBucket>>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
// showLoading();
}
@Override
protected List<ImageBucket> doInBackground(Void... params) {
return LocalAlbumImagePickerHelper.getInstance(LocalAlbumActivity.this)
.getImagesBucketList();
}
@Override
protected void onPostExecute(List<ImageBucket> list) {
dismissLoadingDialog();
TextView emptyView = (TextView) findViewById(R.id.local_album_lv_empty);
mLocalAlbumListView.setEmptyView(emptyView);
mLocalAlbumList.addAll(list);
mLocalAlbumAdapter.notifyDataSetChanged();
}
};
mBucketLoadTask.execute();
}
private void dismissLoadingDialog() {
ViewGroup progressBarLlyt = (ViewGroup) findViewById(R.id.progress_bar_llyt);
progressBarLlyt.setVisibility(View.GONE);
}
private void assignViews() {
TextView loadingMsg = (TextView) findViewById(R.id.loading_msg);
loadingMsg.setText(R.string.scanning);
ImageView backBtn = (ImageView) findViewById(R.id.action_back);
TextView captureBtn = (TextView) findViewById(R.id.action_capture);
backBtn.setOnClickListener(this);
mRequestType = getIntent().getIntExtra(WeacConstants.REQUEST_LOCAL_ALBUM_TYPE, 0);
switch (mRequestType) {
// 主题
case 0:
// 造码
case 2:
captureBtn.setOnClickListener(this);
break;
// 扫码
case 1:
// 隐藏拍照按钮
captureBtn.setVisibility(View.GONE);
break;
}
mLocalAlbumListView = (ListView) findViewById(R.id.local_album_lv);
mLocalAlbumListView.setAdapter(mLocalAlbumAdapter);
mLocalAlbumListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (MyUtil.isFastDoubleClick()) {
return;
}
Intent intent = new Intent(LocalAlbumActivity.this, LocalAlbumDetailActivity.class);
intent.putParcelableArrayListExtra(ALBUM_PATH,
mLocalAlbumAdapter.getItem(position).bucketList);
intent.putExtra(ALBUM_NAME, mLocalAlbumAdapter.getItem(position).bucketName);
intent.putExtra(WeacConstants.REQUEST_LOCAL_ALBUM_TYPE, mRequestType);
startActivityForResult(intent, REQUEST_ALBUM_DETAIL);
}
});
// OverScrollDecoratorHelper.setUpOverScroll(mLocalAlbumListView);
}
private Uri mImageUri;
@Override
public void onClick(View v) {
switch (v.getId()) {
// 返回
case R.id.action_back:
myFinish();
break;
// 拍照
case R.id.action_capture:
PackageManager pm = getPackageManager();
// FEATURE_CAMERA - 后置相机
// FEATURE_CAMERA_FRONT - 前置相机
if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
// 访问相机类型
int requestType;
// 截取主题壁纸
if (mRequestType != 2) {
requestType = REQUEST_IMAGE_CAPTURE_THEME;
} else { // 截取二维码logo
requestType = REQUEST_IMAGE_CAPTURE_QRCODE_LOGO;
}
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//mImageUri = Uri.fromFile(MyUtil.getFileDirectory(this, "/Android/data/" +
// getPackageName() + "/capture/temporary.jpg"));
mImageUri = FileProvider.getUriForFile(this,BuildConfig.APPLICATION_ID+".provider",MyUtil.getFileDirectory(this, "/Android/data/" +
getPackageName() + "/capture/temporary.jpg"));
this.grantUriPermission(getPackageName(),mImageUri,Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
startActivityForResult(intent, requestType);
overridePendingTransition(0, R.anim.zoomin);
} else { // 没有可用相机
Intent intent = new Intent(this, MyDialogActivitySingle.class);
intent.putExtra(WeacConstants.TITLE, getString(R.string.prompt));
intent.putExtra(WeacConstants.DETAIL, getString(R.string.camera_error));
startActivity(intent);
}
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) {
// 截图/相机返回
overridePendingTransition(0, R.anim.zoomout);
return;
}
// 扫描二维码相册详细取消
if (data != null) {
boolean isFinishMe = data.getBooleanExtra(LocalAlbumDetailActivity.FINISH_ACTIVITY, false);
if (isFinishMe && !isFinishing()) {
myFinish2();
return;
}
}
switch (requestCode) {
// 拍照(截取主题壁纸)
case REQUEST_IMAGE_CAPTURE_THEME:
cropImage(0, REQUEST_IMAGE_CROP_THEME, WeacConstants.DIY_WALLPAPER_PATH);
break;
// 拍照(截取二维码logo)
case REQUEST_IMAGE_CAPTURE_QRCODE_LOGO:
cropImage(1, REQUEST_IMAGE_CROP_QRCODE_LOGO, WeacConstants.DIY_QRCODE_LOGO_PATH);
break;
// 截图(截取主题壁纸)
case REQUEST_IMAGE_CROP_THEME:
String filePath = MyUtil.getFilePath(this, WeacConstants.DIY_WALLPAPER_PATH);
// 更新壁纸信息
MyUtil.saveWallpaper(this, WeacConstants.WALLPAPER_PATH, filePath);
// 发送壁纸更新事件
OttoAppConfig.getInstance().post(new WallpaperEvent());
myFinish();
break;
// 截图(截取二维码logo)
case REQUEST_IMAGE_CROP_QRCODE_LOGO:
String logoPath = MyUtil.getFilePath(this, WeacConstants.DIY_QRCODE_LOGO_PATH);
// 保存自定义二维码logo地址
MyUtil.saveQRcodeLogoPath(this, logoPath);
// 发送自定义二维码logo截取地址事件
OttoAppConfig.getInstance().post(new QRcodeLogoEvent(logoPath));
myFinish();
break;
// 相册详细图片
case REQUEST_ALBUM_DETAIL:
assert data != null;
String url = data.getStringExtra(WeacConstants.IMAGE_URL);
OttoAppConfig.getInstance().post(new ScanCodeEvent(url));
myFinish2();
break;
}
}
private void cropImage(int type, int requestType, String path) {
ToastUtil.showLongToast(this, "path:"+path);
Intent intent = MyUtil.getCropImageOptions(this, mImageUri, path, type);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, requestType);
overridePendingTransition(0, 0);
} else {
// 不可以复制其他应用的内部文件
// TODO: 全屏裁剪&自定义裁剪功能
ToastUtil.showLongToast(this, getString(R.string.no_crop_action));
}
}
@Subscribe
public void finishMeEvent(FinishLocalAlbumActivityEvent event) {
myFinish2();
}
@Override
public void onBackPressed() {
myFinish();
}
private void myFinish() {
finish();
if (mRequestType != 2) {
overridePendingTransition(0, R.anim.zoomout);
} else {
overridePendingTransition(0, R.anim.move_out_bottom);
}
}
private void myFinish2() {
finish();
overridePendingTransition(0, 0);
}
@Override
protected void onDestroy() {
super.onDestroy();
OttoAppConfig.getInstance().unregister(this);
if (null != mBucketLoadTask && mBucketLoadTask.getStatus() == AsyncTask.Status.RUNNING) {
mBucketLoadTask.cancel(true);
}
}
}
帮助方法
/**
* Returns specified directory(/mnt/sdcard/...).
* directory will be created on SD card by defined path if card
* is mounted. Else - Android defines files directory on device's
* files(/data/data/<application package>/files) system.
*
* @param context context
* @param path file path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jp")
* @return File {@link File directory}
*/
public static File getFileDirectory(Context context, String path) {
File file = null;
if (isHasSDCard()) {
file = new File(Environment.getExternalStorageDirectory(), path);
if (!file.getParentFile().exists()) {
if (!file.getParentFile().mkdirs()) {
file = null;
}
}
}
if (file == null) {
// 使用内部缓存[MediaStore.EXTRA_OUTPUT ("output")]是无法正确写入裁切后的图片的。
// 系统是用全局的ContentResolver来做这个过程的文件io操作,app内部的存储被忽略。(猜测)
file = new File(context.getFilesDir(), path);
}
return file;
}
/**
* Returns specified directory(/mnt/sdcard/Android/data/<application package>/files/...).
* directory will be created on SD card by defined path if card
* is mounted. Else - Android defines files directory on device's
* files(/data/data/<application package>/files) system.
*
* @param context context
* @param path file path (e.g.: "/music/a.mp3", "/pictures/a.jpg")
* @return File {@link File directory}
*/
public static File getExternalFileDirectory(Context context, String path) {
File file = null;
if (isHasSDCard()) {
file = new File(context.getExternalFilesDir(null), path);
if (!file.getParentFile().exists()) {
if (!file.getParentFile().mkdirs()) {
file = null;
}
}
}
if (file == null) {
// 使用内部缓存[MediaStore.EXTRA_OUTPUT ("output")]是无法正确写入裁切后的图片的。
// 系统是用全局的ContentResolver来做这个过程的文件io操作,app内部的存储被忽略。(猜测)
file = new File(context.getFilesDir(), path);
}
return file;
}
public static boolean isHasSDCard() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
/**
* Returns directory absolutePath.
*
* @param context context
* @param path file path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jpg")
* @return /mnt/sdcard/Android/data/<application package>/files/....
*/
public static String getFilePath(Context context, String path) {
return getExternalFileDirectory(context, path).getAbsolutePath();
}
/**
* set intent options
*
* @param context context
* @param uri image path uri
* @param filePath save path (e.g.: "/AppDir/a.mp3", "/AppDir/files/images/a.jpg")
* @param type 0,截取壁纸/拍照;1,截取Logo
* @return Intent
*/
public static Intent getCropImageOptions(Context context, Uri uri, String filePath, int type) {
int width;
int height;
// 截取壁纸/拍照
if (type == 0) {
width = context.getResources().getDisplayMetrics().widthPixels;
height = context.getResources().getDisplayMetrics().heightPixels;
} else { // 截取logo
width = height = dip2px(context, 30);
}
//filePath="/Internal storage/Download/a.jpg";
LogUtil.e(LOG_TAG, " filePath:" + filePath );
Intent intent = new Intent();
intent.setAction("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra("crop", "true");
// 裁剪框比例
intent.putExtra("aspectX", width);
intent.putExtra("aspectY", height);
// 保存路径
//#ToDO: Uri.fromFile change to FileProvider.getUriForFile
Uri mImageUri;
//mImageUri=Uri.fromFile(getExternalFileDirectory(context, filePath));
intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(context,BuildConfig.APPLICATION_ID+".provider",getExternalFileDirectory(context, filePath)));
// 是否去除面部检测
intent.putExtra("noFaceDetection", true);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// 是否保留比例
intent.putExtra("scale", true);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
// 裁剪区的宽高
intent.putExtra("outputX", width);
intent.putExtra("outputY", height);
// 是否将数据保留在Bitmap中返回
intent.putExtra("return-data", false);
return intent;
}
您需要在清单文件中添加以下in-provider声明
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="<application-id>.fileprovider" // com.abc.def
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
我越来越- 在 我已经检查了这个帖子,但无法解决它。我该如何解决这个问题?
我试图用docker运行一个简单的命令,读取我的主目录中的文件,并在本地机器上的同一目录中写入输出文件(
我已经尝试了通过研究所能找到的一切。什么都没用。我有一个带有片段对话的活动。在这个对话框中,我有一个带有按钮的图像视图。按下此按钮时,会弹出一个警报,提示拍摄照片、从gallery中选择照片或取消。“取消”和“多媒体资料”按钮都很有效,但当我尝试拍照时,我会在标题中看到错误消息: 致命的例外:java。lang.SecurityException:权限拒绝:从ProcessRecord{c6d8b
我的应用程序中有一个活动,允许用户逐个从设备中选择多个文件,我正在使用这样的意图: 这工作得很好,我正在获取所选文件的Uri,它们看起来像这样: 然后,如果文件是图像,我将使用以下方式对其进行解码: 当用户单击按钮时,我通过 intent 将 Uris 列表传递给另一个活动,在此活动中,在 AsyncTask 中,我正在以 base64 编码文件以通过网络发送: 问题是,当我打开inputStre
这个错误真的很奇怪,我不知道如何重现它,也不知道如何修复它,因为我做了很多搜索,但没有什么有用的。 这是stacktrace: 这是我的AndroidManifest。xml 请不要费心问我是否在我的清单中有正确的INTERNET权限,因为这个应用程序已经上市2年了:P 我还注意到(来自Crittercism)所有错误都来自Android 4.1. x版本(JB)。我不知道设备是否已root或什么
我的Firestore数据库有一些用户和一些s。如果没有其他人认领,用户可以认领。他们通过在上创建一个文档来声明,该文档有一个名为的字段,该字段是对他们自己的用户文档的引用。 我想我已经在这些安全规则中捕捉到了: 但是,当为所有权删除文档时,我获得了: 我是这样做的: 如果我打开read和write设置为true的文档,就不会出现此异常。 我的规则怎么了?他们用模拟器测试正常。