виставляється за межі програми через ClipData.Item.getUri


99

Я намагаюся вирішити проблему після додавання нової функції у файлову систему Android, але я отримую таку помилку:

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

Тож сподіваюся, хтось може допомогти мені це виправити :)

Дякую

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

Відповіді:


170

Для sdk 24 і новіших версій, якщо вам потрібно отримати Uri файлу поза сховищем програми, у вас є ця помилка.
Рішення @ eranda.del дозволяють змінити політику, щоб дозволити це, і це працює нормально.

Однак, якщо ви хочете слідувати вказівкам google без необхідності змінювати політику API вашого додатка, вам потрібно використовувати FileProvider.

Спочатку, щоб отримати URI файла, потрібно скористатися методом FileProvider.getUriForFile ():

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

Потім вам потрібно налаштувати свого постачальника у своєму маніфесті 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>

(В "повноваженнях" використовуйте те саме значення, що й другий аргумент методу getUriForFile () (підпис програми + ".provider"))

І нарешті, вам потрібно створити файл ресурсів: "file_paths". Цей файл потрібно створити в каталозі res / xml (можливо, вам також потрібно створити цей каталог):

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="." />
</paths>

79
"Полегшити життя розробникам" - це слоган кожного нового API, чи не так, Google?
Кирило Кармазін

12
Рішення, яке надає Брендон, є правильним, але воно не готове до копіювання, потрібно перевірити, чи відповідає воно вашим потребам, наприклад. <external-path ...використовується, коли ви хочете Environment.getExternalStorageDirectory (). і використовуйте, <files-path ...якщо вам потрібен Context.getFilesDir (). Вам краще спочатку перевірити офіційні документи: developer.android.com/reference/android/support/v4/content/…
Кирило Кармазін

9
Нагадування, якщо ви використовуєте androidx (новий простір імен підтримки), ви можете знайти тут ( developer.android.com/reference/androidx/core/content/… ) відповідну документацію.
Родрірокр

20
Зауважимо, що в androidxньому є:android:name="androidx.core.content.FileProvider"
smörkex

150

Додайте наступний блок коду перед початком перегляду камери або файлу

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

Будь ласка, ознайомтесь із строгим режимом посилання на реферал та з його поясненнями щодо використання та технічних деталей.


24
Це не правильний спосіб вирішити це, це в основному призведе до видалення жорстких політик. і буде ігнорувати попередження про безпеку
Ахсан Захір,

У цьому є деякі плюси і мінуси. Будь ласка , зверніться наступне , щоб отримати більше інформації stackoverflow.com/questions/18100161 / ...
eranda.del

Це працює, якщо є жодна нічия, тоді, будь ласка, дайте мені знати :)
Ханан

Код вирішив виняток для мене. Однак у верхньому коментарі тут сказано, як код не є правильним способом вирішити це. Хтось знає, яким тоді був би правильний метод?
Shn_Android_Dev

Google ненавидить програмістів.
Жубер Васкончелос

0

Потрібна жодна необхідна конфігурація постачальника лише для AndroidManifest Камера та Зберігання. Використовуйте наступний код для запуску камери:

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

Після захоплення зображення ви можете знайти своє захоплене зображення в:

"your_file_name_with_dir"

Краще пояснити конфігурацію провайдера в AndroidManifest, ніж надавати інший код.
fury.slay
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.