FileProvider-Absturz - npe versucht, XmlResourceParser für eine Nullzeichenfolge aufzurufen

139

Dies ist ein Teil meines Manifests:

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

Dies ist die Dateipfaddatei in 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>

Ich lade ein Video aus dem Internet herunter und speichere es folgendermaßen im internen Speicher:

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

Ich versuche es so zu benutzen:

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

}

In dieser Zeile:

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

Ich erhalte folgende Fehlermeldung:

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)
JK
quelle
"Dies ist die Dateipfaddatei" - wo genau in Ihrem Projekt befindet sich diese Datei?
CommonsWare
1
raw / xml / filepaths.xml
JK
2
In Behörden habe ich .provider, an das App-Paket angehängt, aber wenn ich getUriForFile aufrufe, füge ich .provider nicht hinzu. Vielleicht ist es das, ich teste gerade
JK
4
Ja, das war das Problem
JK

Antworten:

264

Das Problem war, dass ich in Manifest diese Zeile hatte:

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

und als ich getUriForFile aufrief, ging ich vorbei:

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

Also wechselte von "com.example.asd"zu "com.example.asd.fileprovider"und es funktionierte

JK
quelle
1
Danke hat für mich funktioniert. Zuerst habe ich so gemacht. android: behörden = "$ {applicationId} .fileprovider Jetzt habe ich meinen tatsächlichen Paketnamen in com.memecreator.fileprovider geändert
Rayyan
2
Stimmen Sie mit @Rayyan überein. Am besten android:authorities="${applicationId}"immer verwenden. Code wird niemals schuld sein.
Sud007
Hat für mich gearbeitet. Vielen Dank
Landrykapela
2
Diese Lösung hat bei mir nicht funktioniert ... Ich erhalte immer noch eine Nullzeiger-Ausnahme, nachdem ich überprüft habe, ob dies korrekt ist.
Wesley Franks
44

Sie können dies zu tun , die Paketnamen mit einem zusätzlichen Nutzen von mehreren Varianten auf demselben Gerät (denken Sie laufen zu können , ohne hartzucodieren releaseund debugmit applicationIdSuffix, sieht diese Probleme ):

Beyogen auf 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);

Sie haben das falsche verwendet authorityund es hat das ContentProvider( info == null) nicht gefunden.

Ändern Sie Ihr Manifest in ( ${applicationId}wird durch Manifest Merger ersetzt)

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

und

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

Das .shareSuffix ist optional, falls Sie ein Real haben, ContentProviderdas besser den Paketnamen als Autorität hat.

TWiStErRob
quelle
Arbeitete für mich ... Ich habe die letzten beiden Zeilen und ihre Arbeit perfekt verwendet.
Danke
24

In meinem Fall habe ich den Fehler bekommen, weil die

BuildConfig.APPLICATION_ID

wurde aus importiert

import android.support.v4.BuildConfig;

Die zurückgegebene Zeichenfolge war also "android.support.v4"anstelle meines Projektpaketnamens. Überprüfen Sie, ob die Importdatei von Ihrer import project.Buildconfigund nicht von einer anderen stammt. Beispiel:

import com.example.yourProjectName.BuildConfig;

Schließlich muss <provider>ich im Tag in Manifest android:authorities="${applicationId}"immer meinen Projektpaketnamen als Autorität erhalten

<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>
Gian Gomen
quelle
1
Was ist Android: resource = "@ xml / ruta_fileprovider"
Ananta Prasad
1
@AnantaPrasad <? Xml version = "1.0" encoding = "utf-8"?> <Pfade> <external-path name = "external_files" path = "." /> <files-path name = "files" path = "." /> <cache-path name = "cache" path = "." /> </ path>
Prinz
5

Stellen Sie zunächst sicher, dass Ihr Anbieter android:authoritiesnicht mit Ihren anderen Anbietern in Konflikt steht. Außerdem können Sie einen beliebigen Namen für den letzten Teil des Namens auswählen: "Provider", "Fileprovider" usw. Die App stürzt jedoch ab, wenn mehrere android:authoritiesaufgeführt sind. In der Dokumentation wird angegeben, dass mehrere Werte aufgelistet werden dürfen.

file://Das Schema darf jetzt nicht mit Intent auf targetSdkVersion> = 24 (Android N 7.0) angehängt werden, sondern content://wird immer nur für alle Geräte (Android 5, 6 und 7) übergeben. Wir haben jedoch festgestellt, dass Xiaomi gegen diese Google-Konvention verstößt und sendet file://und daher data.getData().getAuthority()eine leere Zeichenfolge angibt.

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
}

Außerdem wurde der Fehler, der zum FileProvider.getUriForFile()Absturz java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example/files/attachments/image.jpgführte, in der Android Support Library v24.2.0 behoben. Das Problem war, dass FileProvider.java keine Ordner mit externen Pfaden sah.

Soshial
quelle
1

Wenn Sie Ihre AUTHORITY zur Laufzeit mit BuildConfigerstellen , stellen Sie sicher, dass Sie den vollständigen Klassennamen einschließlich Ihres Paketnamens verwenden.

Schlecht:

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

Gut:

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

Vahid Amiri
quelle
0

Das Folgende hat bei mir funktioniert.

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

Hier ist, was ich getan habe, um das Problem zu beheben. Ich gab voll qualifizierten Namen in Android: Name. Es funktioniert in 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>
Arup Nayak
quelle
Können Sie bitte Ihren Code für die Freigabedatei mit dem Dateianbieter aus dem internen Verzeichnis freigeben?
Vishal Patoliya
0

Du solltest es versuchen:

  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);
Chirag Patel
quelle
0

Folgendes müssen Sie tun:

Uri fileURI = FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".fileprovider", file);
MrGuy
quelle