FileProvider çökmesi - npe, boş bir String'de XmlResourceParser öğesini çağırmaya çalışıyor


139

Bu benim tezahürümün bir parçası:

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

Bu, raw / xml / filepaths.xml'deki dosyayolları dosyasıdır

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

İnternetten bir video indiriyorum ve dahili depolamaya şu şekilde kaydediyorum:

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

Ben böyle kullanmaya çalışın:

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

}

Bu satırda:

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

Aşağıdaki hatayı alıyorum:

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)

"Bu dosyayolları dosyası" - tam olarak projenizde bu dosya nerede?
CommonsWare

1
raw / xml / filepaths.xml
JK

2
yetkililerde uygulama paketine eklenmiş .provider'ım var, ancak getUriForFile'ı çağırırken .provider eklemiyorum. belki şu anda, şu anda test ediyorum
JK

4
Evet sorun
JK

Yanıtlar:


264

Sorun şu ki, Manifest'te şu satır vardı:

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

ve getUriForFile'ı çağırırken geçiyordum:

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

Yani değişti "com.example.asd"etmek "com.example.asd.fileprovider"ve işe yaradı


1
Teşekkürler benim için çalıştı. İlk önce böyle yapıyordum. android: yetkililer = "$ {applicationId} .fileprovider Şimdi gerçek paket adımı com.memecreator.fileprovider olarak değiştirdim
Rayyan

2
@Ryanyan ile android:authorities="${applicationId}"her zaman kullanmak için en iyisi ; kod asla hatalı olmayacak.
sud007

Benim için çalıştı. Teşekkürler
landrykapela

2
Bu çözüm benim için işe yaramadı ... Bunun doğru olduğundan emin olmak için kontrol ettikten sonra hala boş işaretçi istisnası alıyorum.
wesley

44

Aynı cihazda birden varyantları çalıştırmak için güçlü olmak ek bir yararı ile paket adı hardcoding olmadan bunu (düşünebiliriz releaseve debugbirlikte applicationIdSuffixbakın bu konuları ):

Dayalı 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);

yanlış kullanıyor authorityve ContentProvider( info == null) bulamadı .

${applicationId}Manifestinizi olarak değiştirin ( yerini Manifest Merger alacaktır)

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

ve

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

.shareSonek durumda bir gerçek var, isteğe bağlıdır ContentProviderotorite olarak paket adı olması daha iyidir.


Benim için çalıştım ... Son iki çizgiyi ve çalışmasını mükemmel bir şekilde kullandım ...
Teşekkürler

24

Benim durumumda hatayı aldım çünkü

BuildConfig.APPLICATION_ID

ithal ediliyordu

import android.support.v4.BuildConfig;

Dolayısıyla, geri döndürdüğü dize "android.support.v4"proje paketimin adı yerine. İçe aktarma dosyasının başka birinden import project.Buildconfigdeğil , kendinizden geldiğini kontrol edin . Misal:

import com.example.yourProjectName.BuildConfig;

Son olarak, <provider>Manifest'teki etikette android:authorities="${applicationId}"proje paketi adımı her zaman otorite olarak almalıyım

<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 nedir: resource = "@ xml / ruta_fileprovider"
Ananta Prasad

1
@AnantaPrasad <? Xml sürüm = "1.0" kodlama = "utf-8"?> <yollar> <external-path name = "external_files" path = "." /> <dosya-yolu adı = "dosya" yolu = "." /> <önbellek yolu adı = "önbellek" yolu = "." /> </paths>
Prens

5

İlk olarak, sağlayıcınızın android:authoritiesdiğer sağlayıcılarınızla çakışmadığından emin olun . Bunun yanı sıra, adının son kısmı için herhangi bir ad seçebilirsiniz: "sağlayıcı", "dosya sağlayıcı" vb, ancak uygulama birden fazla android:authoritieslistelendiğinde kilitlenirken , belgeler listelenen birden çok değere izin verir.

file://planın targetSdkVersion> = 24 (Android N 7.0) üzerinde Intent ile eklenmesine izin verilmiyor, yalnızca content://tüm cihazlar için (Android 5, 6 ve 7) her zaman geçiriliyor. Ancak Xiaomi'nin bu Google sözleşmesini ihlal ettiği ve gönderdiği file://, dolayısıyla data.getData().getAuthority()boş bir dize verdiği karşılaştık.

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
}

Ayrıca, FileProvider.getUriForFile()çökme java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example/files/attachments/image.jpgile sonuçlanan hata Android Destek Kütüphanesi v24.2.0'da düzeltildi. Sorun FileProvider.java'nın dış yol klasörlerini görmemesiydi.


1

AUTHORITY ürününüzü çalışma zamanında oluşturuyorsanız BuildConfig, paket adınızı içeren tam sınıf adını kullandığınızdan emin olun.

Kötü:

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

İyi:

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


0

Aşağıdaki benim için çalıştı.

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

0

İşte sorunu düzeltmek için yaptım. Ben android tam adı verdim: isim. Android'de çalışır 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>

iç dizindeki dosya sağlayıcısını kullanarak paylaşım dosyası için kodunuzu paylaşabilir misiniz?
Vishal Patoliya ツ

0

Onu denemelisin:

  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

Yapman gereken bu:

Uri fileURI = FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".fileprovider", file);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.