Android.os.FileUriExposedException: file.jpg выставляется вне приложения через ClipData.Item.getUri()
Я пытаюсь сделать кнопку, открывающую камеру и съемку. мой код здесь
//for imports check on bottom of this code block
public class HomeProfileActivity extends AppCompatActivity {
//Button camera
public static final String TAG = HomeProfileActivity.class.getSimpleName();
public static final int REQUEST_TAKE_PHOTO = 0;
public static final int REQUEST_TAKE_VIDEO = 1;
public static final int REQUEST_PICK_PHOTO = 2;
public static final int REQUEST_PICK_VIDEO = 3;
public static final int MEDIA_TYPE_IMAGE = 4;
public static final int MEDIA_TYPE_VIDEO = 5;
private Uri mMediaUri;
private ImageView photobutton;
private Button buttonUploadImage, buttonTakeImage;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_profile);
ButterKnife.bind(this);
}
@OnClick(R.id.buttonTakeImage)
void takePhoto() {
mMediaUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);
if (mMediaUri == null) {
Toast.makeText(this,
"There was a problem accessing your device external storage.",
Toast.LENGTH_LONG).show();
}
else {
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
startActivityForResult(takePhotoIntent, REQUEST_TAKE_PHOTO);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK){
if (requestCode == REQUEST_TAKE_PHOTO) {
Intent intent = new Intent(this, ViewImageActivity.class);
intent.setData(mMediaUri);
startActivity(intent);
}
}
else if (resultCode != RESULT_CANCELED){
Toast.makeText(this, "Sorry, there was an error", Toast.LENGTH_SHORT).show();
}
}
private Uri getOutputMediaFileUri(int mediaType) {
// check for external storage
if (isExternalStorageAvailable()) {
// get the URI
// 1. Get the external storage directory
File mediaStorageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
// 2. Create a unique file name
String fileName = "";
String fileType = "";
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
if (mediaType == MEDIA_TYPE_IMAGE) {
fileName = "IMG_" + timeStamp;
fileType = ".jpg";
} else if (mediaType == MEDIA_TYPE_VIDEO) {
fileName = "VID_" + timeStamp;
fileType = ".mp4";
} else {
return null;
}
// 3. Create the file
File mediaFile;
try {
mediaFile = File.createTempFile(fileName, fileType, mediaStorageDir);
Log.i(TAG, "File: " + Uri.fromFile(mediaFile));
// 4. Return the file URI
return Uri.fromFile(mediaFile);
}
catch (IOException e) {
Log.e(TAG, "Error creating file: " +
mediaStorageDir.getAbsolutePath() + fileName + fileType);
}
}
// something went wrong
return null;
}
private boolean isExternalStorageAvailable(){
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)){
return true;
}
else {
return false;
}
}
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import butterknife.ButterKnife;
import butterknife.OnClick;
У меня также проблема с startActivityForResult
в методе onclick
и импорт java.text.SimpleDateFormat;
также перескакивает во время выполнения исключения
Я работаю с buildtoolsversion sdk 25
Ответы
Ответ 1
Помимо решения, использующего FileProvider, есть еще один способ обойти это. Проще говоря
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
в методе Application.onCreate(). Таким образом, VM игнорирует экспозицию URI файла.
Ответ 2
Эта информация от: FileUriExposedException
Это выбрасывается только для приложений, ориентированных на N или выше. Приложениям, ориентированным на более ранние версии SDK, разрешено предоставлять общий доступ к файлу://Uri, но это настоятельно не рекомендуется.
Поэтому, если ваш файл app/build.gradle
compileSdkVersion
(цель сборки) имеет Android N (уровень API 24) или выше, эта ошибка выдается, если вы пишете файл, к которому другие приложения могут получить доступ. Самое главное, вот как вы должны делать это, двигаясь вперед:
взяты отсюда: FileProvider
Изменить:
return Uri.fromFile(mediaFile);
быть
return FileProvider.getUriForFile(getApplicationContext(), getPackageName()+".fileprovider", mediaFile);
Примечание: если вы контролируете mydomain.com
вы также можете заменить getPackageName()+".fileprovider"
на "com.mydomain.fileprovider"
(то же самое относится и к вашему AndroidManifest.xml
ниже.
Также вам нужно добавить следующее в ваш файл AndroidManifest.xml
прямо перед </application>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
Затем вам нужно добавить файл с именем filepaths.xml
в каталог app/src/main/res/xml
со следующим содержимым
<paths>
<external-files-path name="Pictures" path="Pictures" />
</paths>
Примечание: для всех остальных мы использовали выше external-files-path
, так как Омер использовал в getExternalFilesDir(Environment.DIRECTORY_PICTURES)
. Для любого другого расположения, пожалуйста, проверьте FileProvider в разделе "Указание доступных файлов" и измените external-files-path
к external-files-path
одним из следующих в зависимости от того, где находятся ваши файлы:
files-path
cache-path
external-path
external-files-path
external-cache-path
Кроме того, измените Pictures
выше, чтобы они стали именем вашей папки.
Один важный if (Build.VERSION.SDK_INT < 24) {
следует избегать, это то, что вы НЕ должны использовать if (Build.VERSION.SDK_INT < 24) {
чтобы позволить вам сделать это по-старому, потому что это требует не их версия Android, а ваша версия сборки (I пропустил это в первый раз, когда я это закодировал).
Я знаю, что это больше работы, однако это позволяет Android разрешать только другому приложению, с которым вы делитесь, временный доступ к файлу, что более безопасно для конфиденциальности пользователя.
Ответ 3
Add the below code where the SharingIntent called:-
if(Build.VERSION.SDK_INT>=24){
try{
Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
m.invoke(null);
shareImage(Uri.fromFile(new File(Path)));
}catch(Exception e){
e.printStackTrace();
}
}