FileProvider ขัดข้อง - npe พยายามเรียกใช้ XmlResourceParser บนสตริงที่ไม่มีค่า


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

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

"นี่คือไฟล์พา ธ " - ไฟล์นี้อยู่ที่ไหนในโครงการของคุณ?
CommonsWare

1
raw / xml / filepaths.xml
JK

2
ในหน่วยงานที่ฉันมี. provider ต่อท้ายแพ็คเกจแอป แต่เมื่อโทรหา getUriForFile ฉันไม่ต้องต่อท้ายด้วย. provider อาจจะเป็นเช่นนั้นฉันกำลังทดสอบอยู่ตอนนี้
JK

4
ใช่นั่นเป็นปัญหา
JK

คำตอบ:


264

ปัญหาคือว่าใน Manifest ฉันมีสายนี้:

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: ทางการ = "$ {applicationId} .fileprovider ตอนนี้ฉันเปลี่ยนเป็น com.memecreator.fileprovider ชื่อแพ็คเกจจริงของฉัน
Rayyan

2
เห็นด้วยกับ @Rayyan ที่ดีที่สุดที่จะใช้android:authorities="${applicationId}"เสมอ รหัสจะไม่เป็นความผิด
sud007

ทำงานให้ฉัน ขอบคุณ
landrykapela

2
โซลูชันนี้ใช้งานไม่ได้สำหรับฉัน ... ฉันได้รับข้อยกเว้นตัวชี้โมฆะแล้วหลังจากตรวจสอบเพื่อให้แน่ใจว่าถูกต้อง
เวสลีย์แฟรงค์

44

คุณสามารถทำได้โดยไม่ต้อง hardcoding ชื่อแพคเกจที่มีประโยชน์เพิ่มเติมของความสามารถในการเรียกใช้ตัวแปรหลายคนบนอุปกรณ์เดียวกัน (คิดreleaseและdebugมีapplicationIdSuffixให้ดูที่ปัญหาเหล่านี้ ):

ขึ้นอยู่กับ 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และไม่พบContentProvider( info == null)

เปลี่ยนรายการของคุณเป็น ( ${applicationId}จะถูกแทนที่โดย Manifest Merger)

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

และ

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

.shareต่อท้ายเป็นตัวเลือกในกรณีที่คุณมีจริงContentProviderซึ่งจะดีกว่าที่จะมีชื่อแพคเกจเป็นผู้มีอำนาจ


ทำงานให้ฉัน ... ฉันใช้สองบรรทัดสุดท้ายแล้วและมันทำงานได้อย่างสมบูรณ์แบบ
ขอบคุณ

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"
Ananta Prasad

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ไม่ขัดแย้งกับผู้ให้บริการรายอื่น นอกจากนั้นคุณสามารถเลือกชื่อใด ๆ สำหรับส่วนสุดท้ายของชื่อ: "ผู้ให้บริการ", "fileprovider" ฯลฯ แต่แอปขัดข้องเมื่อมีรายการมากกว่าหนึ่งandroid:authoritiesรายการในขณะที่เอกสารระบุว่าอนุญาตให้แสดงหลายค่า

file://แบบแผนไม่ได้รับอนุญาตให้แนบกับ Intent บน targetSdkVersion> = 24 (Android N 7.0) ระบบ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

นี่คือสิ่งที่ฉันทำเพื่อแก้ไขปัญหา ฉันให้ชื่อที่มีคุณสมบัติครบถ้วนใน Android: ชื่อ มันทำงานได้ใน 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.