Подтвердить что ты не робот

FileProvider crash - npe пытается вызвать XmlResourceParser на пустую строку

Это часть моего манифеста:

<?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)
4b9b3361

Ответ 1

Проблема заключалась в том, что в Manifest у меня была эта строка:

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

и при вызове getUriForFile я проходил мимо:

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

Так изменилось с "com.example.asd" на "com.example.asd.fileprovider", и он работал

Ответ 2

Вы можете сделать это без жесткого кодирования имени пакета с дополнительным преимуществом, чтобы иметь возможность запускать несколько вариантов на одном устройстве (подумайте 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, который лучше иметь имя пакета в качестве полномочий.

Ответ 3

В моем случае я получил ошибку, потому что

BuildConfig.APPLICATION_ID

был импортирован из

import android.support.v4.BuildConfig;

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

import com.example.yourProjectName.BuildConfig;

Наконец, в <provider> в манифесте у меня есть 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>

Ответ 4

Во-первых, убедитесь, что поставщик android:authorities не конфликтует с другими поставщиками. Кроме того, вы можете выбрать любое имя для последней части своего имени: "поставщик", "файлпровайдер" и т.д., Но приложение вылетает, когда перечислено более одного android:authorities, тогда как документация заявляет, что она допускает перечисление нескольких значений.

file:// теперь не допускается прикрепление с помощью Intent на 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 не видел папки внешнего пути.

Ответ 5

Если вы создаете свой АВТОРИТЕТ во время выполнения, используя BuildConfig, убедитесь, что вы используете полное имя класса, включая имя вашего пакета.

Плохо:

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

Хорошо:

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

Ответ 6

Вот что я сделал, чтобы исправить проблему. Я дал полное имя в 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>

Ответ 7

У меня была такая же проблема, и я решил, что я ошибся, что у меня было другое имя для папки:

<paths>
    <external-path
        name="IMG_"
        path="Android/data/maa.yourpackname/files/Pictures/folder_name" />
</paths>

Ответ 8

После меня работали.

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