49

バックグラウンド

私は、プログラムによってキャプチャされたスクリーンショットを外部の電子メール アプリケーションに共有することをコア機能とするライブラリを管理しています。

FileProviderこれは、ライブラリのマニフェストにタグが含まれている<provider>ことを意味します。

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="${applicationId}.bugshaker.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>

filepaths.xmlは次のように定義されます。

<paths>
    <files-path path="bug-reports/" name="bug-reports" />
</paths>

FileProvider私のライブラリのコンシューマーには、ファイルを共有するためにそれ自体を使用するアプリケーションがあります。<provider>私の予想では、消費するアプリケーションが次のマニフェストタグを使用した場合、両方のプロバイダーがファイルを共有できるようになるはずです。

<provider
    android:authorities="${applicationId}.fileprovider;${applicationId}.bugshaker.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true"
    android:name="android.support.v4.content.FileProvider"
    tools:replace="android:authorities">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths"
        tools:replace="android:resource" />
</provider>

このマニフェスト エントリ:

  • (アプリケーション ファイル共有用) と(ライブラリ ファイル共有用) の 2 つのProvider権限を指定します。${applicationId}.fileprovider${applicationId}.bugshaker.fileprovider
  • 更新された を参照しますfilepaths.xml。これには、アプリケーション生成ファイルとライブラリ生成ファイルの個別のディレクトリ定義が含まれています。
<paths>
    <external-path
        name="redacted"
        path="" />
    <files-path
        name="bug-reports"
        path="bug-reports/" />
</paths>

アプリケーションをビルドした後、生成されたマニフェストの正しいノードがこれらの更新された値に置き換えられていることを確認しました。

ただし、この構成を使用するアプリケーションが (正常に) アセンブルされて実行されると、起動時にクラッシュが発生します。

E: FATAL EXCEPTION: main
   Process: com.stkent.bugshakertest, PID: 11636
   java.lang.RuntimeException: Unable to get provider android.support.v4.content.FileProvider: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
       at android.app.ActivityThread.installProvider(ActivityThread.java:5856)
       at android.app.ActivityThread.installContentProviders(ActivityThread.java:5445)
       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5384)
       at android.app.ActivityThread.-wrap2(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6119)
       at java.lang.reflect.Method.invoke(Native Method)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
    Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.PackageItemInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
       at android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.java:583)
       at android.support.v4.content.FileProvider.getPathStrategy(FileProvider.java:557)
       at android.support.v4.content.FileProvider.attachInfo(FileProvider.java:375)
       at android.app.ActivityThread.installProvider(ActivityThread.java:5853)
       at android.app.ActivityThread.installContentProviders(ActivityThread.java:5445) 
       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5384) 
       at android.app.ActivityThread.-wrap2(ActivityThread.java) 
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545) 
       at android.os.Handler.dispatchMessage(Handler.java:102) 
       at android.os.Looper.loop(Looper.java:154) 
       at android.app.ActivityThread.main(ActivityThread.java:6119) 
       at java.lang.reflect.Method.invoke(Native Method) 
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 

デバッガーを使用すると、メソッドが権限文字列でFileProvider.parsePathStrategy呼び出されることがわかります。その後、null を返し、この NPE につながります。PackageManager.resolveContentProvider"${applicationId}.fileprovider;${applicationId}.bugshaker.fileprovider"resolveContentProvider

resolveContentProviderこの命令で一時停止中に手動で呼び出して"${applicationId}.fileprovider" または "${applicationId}.bugshaker.fileprovider"を渡すと、resolveContentProvider代わりに null 以外のProviderInfoインスタンスが返されます (これは期待される結果のようです)。

<provider>要素のドキュメントには複数の権限がサポートされていると記載されているため、この違いは私を混乱させます。

コンテンツ プロバイダーが提供するデータを識別する 1 つ以上の URI 機関のリスト。複数の機関は、名前をセミコロンで区切ってリストします。競合を避けるために、機関名は Java スタイルの命名規則 (com.example.provider.cartoonprovider など) を使用する必要があります。通常、プロバイダーを実装する ContentProvider サブクラスの名前です。

デフォルトはありません。少なくとも 1 つの権限を指定する必要があります。

質問

  • FileProvider1 つのアプリケーションで複数の権限とファイル パスを 公開することは可能ですか?
    • もしそうなら、それを機能させるために何を変更する必要がありますか?
    • そうでない場合、このような競合を回避するためにライブラリ内でファイル共有を構成する他の方法はありますか?
4

2 に答える 2