diekspos di luar aplikasi melalui ClipData.Item.getUri

99

Saya mencoba memperbaiki masalah setelah fitur baru ditambahkan di sistem file Android tetapi saya mendapatkan kesalahan ini:

android.os.FileUriExposedException: file:///storage/emulated/0/MyApp/Camera_20180105_172234.jpg exposed beyond app through ClipData.Item.getUri()

Jadi saya berharap seseorang dapat membantu saya memperbaiki ini :)

Terima kasih

private Uri getTempUri() {
    // Create an image file name
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
    String dt = sdf.format(new Date());
    imageFile = null;
    imageFile = new File(Environment.getExternalStorageDirectory()
            + "/MyApp/", "Camera_" + dt + ".jpg");
    AppLog.Log(
            TAG,
            "New Camera Image Path:- "
                    + Environment.getExternalStorageDirectory()
                    + "/MyApp/" + "Camera_" + dt + ".jpg");
    File file = new File(Environment.getExternalStorageDirectory() + "/MyApp");
    if (!file.exists()) {
        file.mkdir();
    }
    imagePath = Environment.getExternalStorageDirectory() + "/MyApp/"
            + "Camera_" + dt + ".jpg";
    imageUri = Uri.fromFile(imageFile);
    return imageUri;
}
JonathanNet
sumber

Jawaban:

170

Untuk sdk 24 dan yang lebih baru, jika Anda perlu mendapatkan Uri dari file di luar penyimpanan aplikasi Anda, Anda mengalami kesalahan ini.
Solusi @ eranda.del memungkinkan Anda mengubah kebijakan untuk mengizinkan ini dan berfungsi dengan baik.

Namun jika Anda ingin mengikuti pedoman google tanpa harus mengubah kebijakan API aplikasi Anda, Anda harus menggunakan FileProvider.

Pertama-tama untuk mendapatkan URI file, Anda perlu menggunakan metode FileProvider.getUriForFile ():

Uri imageUri = FileProvider.getUriForFile(
            MainActivity.this,
            "com.example.homefolder.example.provider", //(use your app signature + ".provider" )
            imageFile);

Kemudian Anda perlu mengonfigurasi penyedia Anda di manifes android:

<application>
  ...
     <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.example.homefolder.example.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <!-- ressource file to create -->
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths">  
        </meta-data>
    </provider>
</application>

(Dalam "otoritas", gunakan nilai yang sama dengan argumen kedua metode getUriForFile () (tanda tangan aplikasi + ".provider"))

Dan terakhir Anda perlu membuat file ressources: "file_paths". File ini perlu dibuat di bawah direktori res / xml (Anda mungkin perlu membuat direktori ini juga):

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="." />
</paths>
Brendon
sumber
79
"Jadikan hidup developer lebih mudah" - ini slogan untuk setiap API baru, bukan?
Kirill Karmazin
12
Solusi yang diberikan oleh Brendon adalah yang benar tetapi belum siap copy-paste, Anda perlu memeriksa apakah sesuai dengan kebutuhan Anda, misalnya. <external-path ...digunakan saat Anda menginginkan Environment.getExternalStorageDirectory (). dan gunakan <files-path ...jika Anda membutuhkan Context.getFilesDir (). Lebih baik Anda memeriksa dokumen resmi terlebih dahulu: developer.android.com/reference/android/support/v4/content/…
Kirill Karmazin
9
Sebuah pengingat jika Anda menggunakan androidx (namespace dukungan baru), Anda dapat menemukan di sini ( developer.android.com/reference/androidx/core/content/… ) dokumentasi yang tepat.
Rodrirokr
20
Perhatikan bahwa di androidxdalamnya adalah:android:name="androidx.core.content.FileProvider"
smörkex
150

Tambahkan blok kode berikut sebelum memulai penjelajahan kamera atau file

    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
    StrictMode.setVmPolicy(builder.build());

Silakan lihat mode ketat tautan rujukan dan itu menjelaskan semua penggunaan dan detail teknis.

eranda.del
sumber
24
Ini bukan cara yang tepat untuk menyelesaikan ini, ini pada dasarnya akan menghapus kebijakan mode ketat. dan akan mengabaikan peringatan keamanan
Ahsan Zaheer
Ada beberapa pro dan kontra tentang hal ini. Silakan merujuk yang berikut ini untuk mendapatkan informasi lebih lanjut stackoverflow.com/questions/18100161/…
eranda.del
Berhasil, jika ada hasil imbang maka beri tahu saya :)
Hanan
Kode tersebut memecahkan pengecualian untuk saya. Namun, komentar teratas di sini mengatakan bahwa kode tersebut bukanlah cara yang benar untuk menyelesaikan masalah ini. Adakah yang tahu apa metode yang tepat nantinya?
Shn_Android_Dev
Google membenci programmer.
Joubert Vasconcelos
0

Tidak ada konfigurasi penyedia yang diperlukan ke dalam AndroidManifest, hanya izin Kamera dan Penyimpanan yang diizinkan. Gunakan kode berikut untuk memulai kamera:

final int REQUEST_ACTION_CAMERA = 9;
void openCamra() {
Intent cameraImgIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

cameraImgIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID +".provider",
                new File("your_file_name_with_dir")));
startActivityForResult(cameraImgIntent, REQUEST_ACTION_CAMERA);
}

Setelah mengambil gambar, Anda dapat menemukan gambar yang Anda ambil di:

"your_file_name_with_dir"
Hemraj Patel
sumber
Lebih baik menjelaskan konfigurasi penyedia di AndroidManifest, daripada memberikan kode lain.
fury. Membunuh