java.lang.SecurityException: Permission Denial: writing android.support.v4.content.FileProvider uri

匿名 (未验证) 提交于 2019-12-03 01:45:01

问题:

I am trying to use camera and save image. Followed the steps as commonsware suggested. Constantly I am getting error -

2018-11-12 02:10:54.588 3145-3173/com.bisw.weac E/DatabaseUtils: Writing exception to parcel java.lang.SecurityException: Permission Denial: writing android.support.v4.content.FileProvider uri content://com.bisw.weac.provider/external_files/Android/data/com.bisw.weac/files/wallpaper/theme.jpg from pid=5566, uid=10071 requires the provider be exported, or grantUriPermission() at android.content.ContentProvider.enforceWritePermissionInner(ContentProvider.java:713) at android.content.ContentProvider$Transport.enforceWritePermission(ContentProvider.java:519) at android.content.ContentProvider$Transport.enforceFilePermission(ContentProvider.java:491) at android.content.ContentProvider$Transport.openAssetFile(ContentProvider.java:389) at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:251) at android.os.Binder.execTransact(Binder.java:682)

I have tried almost everything like - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); but nothing helps. I am croping the image from camera. Activity code

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);         }     } } 

Helper Methods

/**  * 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; } 

回答1:

You need to add the following in provider declaration in your manifest file

 <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> 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!