[android] FileProvider 충돌-null 문자열에서 XmlResourceParser를 호출하려고 시도합니다.

이것은 내 매니페스트의 일부입니다.

<?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의 파일 경로 파일입니다.

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



답변

문제는 매니페스트 에서이 줄을 가지고 있다는 것입니다.

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

그리고 getUriForFile을 호출 할 때 나는 통과했다 :

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

그래서에서 "com.example.asd"로 바뀌었고 "com.example.asd.fileprovider"효과가있었습니다.


답변

당신은 동일한 장치 (생각의 여러 변종 실행할 수있는의 추가 혜택과 함께 패키지 이름을 하드 코딩하지 않고이 작업을 수행 할 수 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권한으로 패키지 이름을 가지고하는 것이 좋습니다.


답변

제 경우에는 오류로 인해

BuildConfig.APPLICATION_ID

에서 수입되었습니다

import android.support.v4.BuildConfig;

그래서 반환 된 문자열 "android.support.v4"은 내 프로젝트 패키지 이름 대신이었습니다. 가져 오기 파일이 import project.Buildconfig다른 파일이 아닌 다른 파일인지 확인하십시오 . 예:

import com.example.yourProjectName.BuildConfig;

마지막으로 <provider>Manifest의 태그에서 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>


답변

먼저, 귀하의 제공자 android:authorities가 다른 제공자와 충돌하지 않는지 확인하십시오 . 그 외에도 이름의 마지막 부분에 “provider”, “fileprovider”등의 이름을 선택할 수 있지만 android:authorities문서에 여러 값을 허용하면 문서에 나와있는 것처럼 표시됩니다.

file://체계는 이제 targetSdkVersion> = 24 (Android N 7.0)에서 Intent로 첨부 할 수 없으며 content://모든 장치 (Android 5, 6 및 7) 에만 항상 전달됩니다. 그러나 우리는 샤오 미이 구글의 규칙을 깨고 보내는 발생 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 지원 라이브러리 v24.2.0에서 수정되었습니다. 문제는 FileProvider.java가 외부 경로 폴더를 볼 수 없다는 것입니다.


답변

런타임에 AUTHORITY를 사용하여 빌드하는 경우 BuildConfig패키지 이름을 포함한 전체 클래스 이름을 사용해야합니다.

나쁜:

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

좋은:

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


답변

다음은 나를 위해 일했습니다.

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


답변

다음은 문제를 해결하기 위해 수행 한 작업입니다. android : name에서 정규화 된 이름을 지정했습니다. 그것은 안드로이드 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>