FileProvider crash - npe tente d'appeler XmlResourceParser sur une chaîne null


139

Ceci fait partie de mon manifeste:

<?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>

Il s'agit du fichier filepaths dans 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>

Je télécharge une vidéo depuis Internet et je l'enregistre dans la mémoire interne de cette façon:

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

J'essaye de l'utiliser comme ça:

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

}

À cette ligne:

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

J'obtiens l'erreur suivante:

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)

"Ceci est le fichier filepaths" - où se trouve exactement ce fichier dans votre projet?
CommonsWare

1
raw / xml / filepaths.xml
JK

2
dans les autorités, j'ai .provider, ajouté au package d'application, mais lorsque j'appelle getUriForFile, je n'ajoute pas .provider. peut-être que c'est ça, je teste en ce moment
JK

4
Oui, c'était le problème
JK

Réponses:


264

Le problème était que dans Manifest j'avais cette ligne:

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

et en appelant getUriForFile je passais:

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

Tellement changé de "com.example.asd"à "com.example.asd.fileprovider"et ça a marché


1
Merci a travaillé pour moi. D'abord je faisais comme ça. android: Authorities = "$ {applicationId} .fileprovider Maintenant, je l'ai changé en com.memecreator.fileprovider mon nom de package actuel
Rayyan

2
D'accord avec @Rayyan, il est préférable de android:authorities="${applicationId}"toujours l' utiliser ; le code ne sera jamais en faute.
sud007

A travaillé pour moi. Merci
landrykapela

2
Cette solution n'a pas fonctionné pour moi ... J'obtiens toujours une exception de pointeur nul après avoir vérifié que c'est correct.
wesley franks

44

Vous pouvez le faire sans coder en dur le nom du package avec un avantage supplémentaire de pouvoir exécuter plusieurs variantes sur le même appareil (pensez releaseet debugavec applicationIdSuffix, voyez ces problèmes ):

Basé sur 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);

vous utilisiez le mauvais authorityet il n'a pas trouvé le ContentProvider( info == null).

Remplacez votre manifeste par ( ${applicationId}sera remplacé par Manifest Merger)

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

et

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

Le .sharesuffixe est facultatif, au cas où vous auriez un réel, il ContentProvidervaut mieux avoir le nom du paquet comme autorité.


A travaillé pour moi ... J'ai utilisé les deux dernières lignes et son travail parfaitement
Merci

24

Dans mon cas, j'ai eu l'erreur parce que le

BuildConfig.APPLICATION_ID

était importé de

import android.support.v4.BuildConfig;

La chaîne renvoyée était donc à la "android.support.v4"place du nom de mon package de projet. Vérifiez que le fichier d'importation provient de vous import project.Buildconfiget non d'un autre. Exemple:

import com.example.yourProjectName.BuildConfig;

Enfin, dans la <provider>balise du manifeste, je dois android:authorities="${applicationId}"toujours obtenir le nom de mon package de projet en tant qu'autorité

<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
qu'est-ce qu'android: resource = "@ xml / ruta_fileprovider"
Ananta Prasad

1
@AnantaPrasad <? Xml version = "1.0" encoding = "utf-8"?> <chemin> <external-path name = "external_files" path = "." /> <files-path name = "files" path = "." /> <cache-path name = "cache" path = "." /> </paths>
Prince

5

Tout d'abord, assurez-vous que votre fournisseur android:authoritiesn'est pas en conflit avec vos autres fournisseurs. En plus de cela, vous pouvez choisir n'importe quel nom pour la dernière partie de son nom: "fournisseur", "fournisseur de fichiers", etc., mais l'application se bloque quand il y en a plusieurs android:authorities, alors que la documentation indique qu'elle autorise plusieurs valeurs.

file://Le schéma n'est désormais plus autorisé à être attaché avec Intent sur targetSdkVersion> = 24 (Android N 7.0), il content://n'est toujours transmis que pour tous les appareils (Android 5, 6 et 7). Mais nous avons constaté que Xiaomi enfreint cette convention Google et envoie file://, donc data.getData().getAuthority()donne une chaîne vide.

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
}

En outre, le bogue qui FileProvider.getUriForFile()provoquait un crash a java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example/files/attachments/image.jpgété corrigé dans la bibliothèque de support Android v24.2.0. Le problème était que FileProvider.java ne voyait pas les dossiers de chemin externe.


1

Si vous BuildConfigcréez votre AUTHORITY lors de l'exécution en utilisant, assurez-vous d'utiliser le nom complet de la classe, y compris le nom de votre package.

Mauvais:

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

Bien:

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


0

La suite a fonctionné pour moi.

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

0

Voici ce que j'ai fait pour résoudre le problème. J'ai donné un nom complet dans Android: nom. Cela fonctionne sous 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>

pouvez-vous s'il vous plaît partager votre code pour partager le fichier en utilisant le fournisseur de fichiers du répertoire interne?
Vishal Patoliya ツ

0

Tu devrais l'essayer:

  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

Voici ce que vous devez faire:

Uri fileURI = FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".fileprovider", file);
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.