Збій FileProvider - npe намагається викликати XmlResourceParser на нульовому рядку


139

Це частина мого маніфесту:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.asd"
    android:versionCode="118"
    android:versionName="118" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="19" />


    <application
        android:name="com.example.asd.AsdApplication"
        android:allowBackup="true"
        android:allowTaskReparenting="true"
        android:theme="@style/AsdTheme" >
        ...

        <provider
            android:name="com.example.asd.database.hq.ContentProviderDB"
            android:authorities="ourContentProviderAuthorities" >
        </provider>
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.asd.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" />
        </provider>

       ...
    </application>

</manifest>

Це файл filepaths в raw / xml / filepaths.xml

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

Я завантажую відео з Інтернету і зберігаю його у внутрішньому сховищі таким чином:

public static boolean saveInputStreamToInternalStorageFile(Context context, String filename, byte[] dataToWrite, Context ctx) {
    FileOutputStream fos;
    try {
        fos = new FileOutputStream(context.getFilesDir() + File.separator + filename);

        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(dataToWrite);
        oos.close();
        return true;
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        return false;
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
}

Я намагаюся використовувати його так:

private void playVideoFromDeviceWithWorkaround(String fileName) {

    File newFile = new File(getFilesDir(), fileName);
    Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "com.example.asd", newFile);

    try {
        vvVideoFullscreen.setVideoURI(contentUri);
        showMediaControls = true;
        playVideo();
    } catch (Exception e) {
        playVideoFromNetwork();
    }

}

У цьому рядку:

Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "com.example.asd", newFile); 

Я отримую таку помилку:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
at android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.java:560)
at android.support.v4.content.FileProvider.getPathStrategy(FileProvider.java:534)
at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:376)

"Це файл filepaths" - де саме у вашому проекті знаходиться цей файл?
CommonsWare

1
raw / xml / filepaths.xml
JK

2
в органах влади я .provider, додається до пакету додатків, але при виклику getUriForFile я не додаю .provider. можливо, що це, я зараз тестую
JK

4
Так, це була проблема
JK

Відповіді:


264

Проблема полягала в тому, що в "Маніфесті" у мене був такий рядок:

android:authorities="com.example.asd.fileprovider"

а під час дзвінка getUriForFile я проходив:

Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "com.example.asd", newFile); 

Так змінився з "com.example.asd"на "com.example.asd.fileprovider"і він спрацював


1
Спасибі працювали для мене. Спочатку я робив так. android: vlasti = "$ {applicationId} .fileprovider Тепер я змінив його на com.memecreator.fileprovider моє фактичне ім'я пакета
Rayyan

2
Погодьтеся з @Rayyan, найкраще використовувати android:authorities="${applicationId}"завжди; код ніколи не буде винним.
sud007

Працювали для мене. Спасибі
landrykapela

2
Це рішення не спрацювало для мене ... Я отримую нульове виключення вказівника ще після перевірки, щоб переконатися, що це правильно.
Wesley Franks

44

Ви можете зробити це без жорсткого кодування назви пакета з додатковою перевагою можливості запуску декількох варіантів на одному пристрої (подумайте releaseі debugз applicationIdSuffix, див. Ці проблеми ):

На основі FileProvider.java:560

final ProviderInfo info = context.getPackageManager()
        .resolveContentProvider(authority, PackageManager.GET_META_DATA);
final XmlResourceParser in = info.loadXmlMetaData( //560
        context.getPackageManager(), META_DATA_FILE_PROVIDER_PATHS);

ви використовували неправильно, authorityі він не знайшов ContentProvider( info == null).

Змініть свій маніфест на ( ${applicationId}замінить Маніфест злиття)

android:authorities="${applicationId}.share"

і

Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".share", result);

.shareСуфікс НЕ є обов'язковим, в разі , якщо у вас є реальний , ContentProviderякий краще мати ім'я пакета в якості органу.


Працював для мене ... Я використав останні два рядки та його роботу чудово.
Дякую

24

У моєму випадку я отримав помилку, оскільки

BuildConfig.APPLICATION_ID

імпортували з

import android.support.v4.BuildConfig;

Отже рядок, яку він повернув, був "android.support.v4"замість мого імені пакета проекту. Перевірте файл імпорту з вашого, import project.Buildconfigа не іншого. Приклад:

import com.example.yourProjectName.BuildConfig;

Нарешті, у <provider>тезі в Manifest я android:authorities="${applicationId}"завжди повинен отримувати своє ім'я пакета проекту як авторитет

<manifest>
   ..
   ..
   <application>
    ..
    ..
       <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/ruta_fileprovider" />
        </provider>

    </application>

</manifest>

1
що таке android: resource = "@ xml / ruta_fileprovider"
Ананта Прасад

1
@AnantaPrasad <? Xml version = "1.0" encoding = "utf-8"?> <paths> <external-path name = "external_files" path = "." /> <files-path name = "файли" шлях = "." /> <cache-path name = "кеш" шлях = ". /> </paths>
Князь

5

По-перше, будьте впевнені, що ваш постачальник android:authoritiesне суперечить іншим постачальникам. Крім того, ви можете вибрати будь-яке ім’я для останньої частини його назви: "провайдер", "файлпровідер" тощо, але програма виходить з ладу, коли їх є більшеandroid:authorities , в той час як у документації зазначено, що вона дозволяє перераховувати кілька значень.

file://схему тепер не дозволяється додавати з Intent on targetSdkVersion> = 24 (Android N 7.0), тільки content://завжди передається для всіх пристроїв (Android 5, 6 і 7). Але ми стикалися, що Xiaomi порушує цю умову Google і надсилає file://, отже, data.getData().getAuthority()дає порожню рядок.

final String uriScheme = currentUri.getScheme();
if ("content".equals(uriScheme)) {
    // getting full file path (works with some providers, i.e. Gallery)
    path = FileUtils.getPath(getContext(), currentUri);
    if (path != null) {
         currentFile = new File(path);
    }
} else if ("file".equals(uriScheme)) {
    // in a rare case we received file:// in currentUri, we need to:
    // 1. create new File variable from currentUri that looks like "file:///storage/emulated/0/download/50044382b.jpg"
    // 2. generate a proper content:// Uri for it
    currentFile = new File(currentUri.getPath());
    String authority = data.getData().getAuthority();
    if (authority != null && !authority.isEmpty()) {
        currentUri = FileProvider.getUriForFile(getActivity(), authority, currentFile);
    }
} else {
    // throw exception
}

Крім того, помилка, що FileProvider.getUriForFile()призвела до збоїв, java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example/files/attachments/image.jpgбула виправлена ​​в Android Support Library v24.2.0. Проблема полягала в тому, що FileProvider.java не бачив папки зовнішнього шляху.


1

Якщо ви будуєте свій АВТОРИТЕТ під час виконання BuildConfig переконайтеся, що ви використовуєте повне ім'я класу, включаючи назву пакета.

Погано:

final String AUTHORITY = BuildConfig.APPLICATION_ID + ".provider";

Добре:

final String AUTHORITY = com.mycompany.myapp.BuildConfig.APPLICATION_ID + ".provider";


0

Слідом працював для мене.

mUri = FileProvider.getUriForFile(this,
                    BuildConfig.APPLICATION_ID + ".provider",
                    fileObject);

0

Ось що я зробив, щоб виправити проблему. Я дав повноцінне ім’я в android: name. Працює в android 6,7,8

    <provider android:authorities="${applicationId}.opener.provider" 
        android:exported="false" android:grantUriPermissions="true" 
        android:name="io.github.pwlin.cordova.plugins.fileopener2.FileProvider">
        <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" />
    </provider>

Ви можете, будь ласка, поділитися своїм кодом для спільного використання файлів за допомогою постачальника файлів із внутрішнього каталогу?
Вішал Патолія ツ

0

Спробуйте:

  Context context = PostAdapter.this.activity;
                    StringBuilder stringBuilder2 = new StringBuilder();
                    stringBuilder2.append(PostAdapter.this.activity.getPackageName());
                    stringBuilder2.append(".provider");
                    Uri uri;
                    uri = FileProvider.getUriForFile(context,stringBuilder2.toString(), newFile);

0

Це те, що вам потрібно зробити:

Uri fileURI = FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".fileprovider", file);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.