FileProviderクラッシュ-null文字列でXmlResourceParserを呼び出そうとするnpe


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>

これは、raw / xml / filepaths.xml内のfilepathsファイルです。

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

1
raw / xml / filepaths.xml
JK

2
当局では.providerをアプリパッケージに追加していますが、getUriForFileを呼び出すときに.providerを追加しません。たぶんそれ、それは今テスト中です
JK

4
はい、それが問題でした
JK 2015年

回答:


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:authorities = "$ {applicationId} .fileproviderこれで、実際のパッケージ名をcom.memecreator.fileproviderに変更しました
Rayyan

2
@Rayyanに同意しandroid:authorities="${applicationId}"ます。常に使用することをお勧めします。コードに問題はありません。
sud007 2017

私のために働いた。ありがとう
landrykapela

2
このソリューションは私にとってはうまくいきませんでした...これが正しいことを確認した後も、nullポインタ例外が発生します。
ウェズリーフランク

44

パッケージ名をハードコーディングすることなくこれを行うことができ、同じデバイスで複数のバリアントを実行できるという追加の利点があります(releasedebugapplicationIdSuffixこれらの問題を参照してください)。

に基づく 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いて、ContentProviderinfo == null)が見つかりませんでした。

マニフェストを次のように変更します(${applicationId}マニフェストマージに置き換えられます)

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

そして

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

.share接尾辞は、あなたが本当の持っている場合には、オプションであるContentProvider権威としてパッケージ名を持っている方が良いです。


私のために働いた...私は最後の2行とその作品を完璧に使用しました。
ありがとう

24

私の場合、エラーが発生しました

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>

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 = "files" path = "。" /> <cache-path name = "cache" path = "。" /> </ paths>
王子(

5

まず、プロバイダーandroid:authoritiesが他のプロバイダーと競合しないことを確認してください。さらに、名前の最後の部分には「プロバイダー」、「ファイルプロバイダー」など、任意の名前を選択できますがandroid:authorities、複数の値がリストされているとアプリがクラッシュします。

file://スキームは、targetSdkVersion> = 24(Android N 7.0)でIntentにアタッチすることができなくなり、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

実行時にAUTHORITYを構築する場合は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>

内部ディレクトリのファイルプロバイダーを使用して、共有ファイルのコードを共有できますか?
Vishal Patoliyaツノヴ

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);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.