Sự cố FileProvider - npe đang cố gắng gọi XmlResourceParser trên Chuỗi rỗng


139

Đây là một phần trong bảng kê khai của tôi:

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

Đây là tệp filepaths trong 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>

Tôi tải xuống một video từ internet và lưu nó vào bộ nhớ trong theo cách này:

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

Tôi cố gắng sử dụng nó như vậy:

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

}

Tại dòng này:

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

Tôi nhận được lỗi sau đây:

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)

"Đây là tệp filepaths" - nơi chính xác trong dự án của bạn là tệp này?
CommonsWare

1
raw / xml / filepaths.xml
JK

2
Trong các cơ quan chức năng, tôi có .provider, được thêm vào gói ứng dụng, nhưng khi gọi getUriForFile, tôi không nối thêm .provider. có thể là nó, tôi đang thử nghiệm ngay bây giờ
JK

4
Vâng, đó là vấn đề
JK

Câu trả lời:


264

Vấn đề là ở Manifest tôi có dòng này:

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

và khi gọi getUriForFile tôi đã vượt qua:

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

Vì vậy, thay đổi từ "com.example.asd"đến "com.example.asd.fileprovider"và nó làm việc


1
Cảm ơn đã làm việc cho tôi. Đầu tiên tôi đã làm như thế này. android: cơ quan = "$ {applicationId} .fileprovider Bây giờ tôi đã đổi nó thành com.memecreator.fileprovider tên gói thực tế của tôi
Rayyan

2
Đồng ý với @Rayyan, Tốt nhất để sử dụng android:authorities="${applicationId}"luôn; mã sẽ không bao giờ có lỗi.
sud007

Đã làm cho tôi. Cảm ơn
Landrykapela

2
Giải pháp này không hiệu quả với tôi ... Tôi vẫn nhận được ngoại lệ con trỏ null sau khi kiểm tra để đảm bảo rằng điều này là chính xác.
wesley franks

44

Bạn có thể làm điều này mà không thể xác định rõ tên gói với một lợi ích nữa của việc có thể chạy nhiều phiên bản trên cùng một thiết bị (suy nghĩ releasedebugvới applicationIdSuffix, xem những vấn đề này ):

Dựa trên 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);

bạn đã sử dụng sai authorityvà nó không tìm thấy ContentProvider( info == null).

Thay đổi bảng kê khai của bạn thành ( ${applicationId}sẽ được thay thế bằng Sáp nhập Manifest)

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

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

Các .sharehậu tố là không bắt buộc, trong trường hợp bạn có một thực tế ContentProviderđó là tốt hơn để có tên gói như thẩm quyền.


Làm việc cho tôi ... Tôi đã sử dụng hai dòng cuối cùng và nó hoạt động hoàn
hảo..Cảm ơn

24

Trong trường hợp của tôi, tôi đã nhận được lỗi vì

BuildConfig.APPLICATION_ID

đã được nhập khẩu từ

import android.support.v4.BuildConfig;

Vì vậy, chuỗi nó trả về là "android.support.v4"thay vì tên gói dự án của tôi. Kiểm tra các tập tin nhập là từ của bạn import project.Buildconfigchứ không phải khác. Thí dụ:

import com.example.yourProjectName.BuildConfig;

Cuối cùng, trong <provider>thẻ trong Manifest, tôi phải android:authorities="${applicationId}"luôn lấy tên gói dự án của mình làm cơ quan

<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 là gì: resource = "@ xml / ruta_fileprovider"
Ananta Prasad

1
@AnantaPrasad <? Xml version = "1.0" mã hóa = "utf-8"?> <Path> <tên ngoài đường dẫn = "bên ngoài_files" path = "." /> <files-path name = "files" path = "." /> <cache-path name = "cache" path = "." /> </ path>
Hoàng tử

5

Trước tiên, hãy chắc chắn rằng nhà cung cấp của android:authoritiesbạn không xung đột với các nhà cung cấp khác của bạn. Ngoài ra, bạn có thể chọn bất kỳ tên nào cho phần cuối của tên của nó: "nhà cung cấp", "fileprovider", v.v., nhưng ứng dụng gặp sự cố khi có nhiều hơn một android:authoritiesdanh sách, trong khi tài liệu nói rằng nó cho phép nhiều giá trị được liệt kê.

file://lược đồ hiện không được phép gắn với Intent trên targetSdkVersion> = 24 (Android N 7.0), chỉ content://luôn được truyền cho tất cả các thiết bị (Android 5, 6 và 7). Nhưng chúng tôi đã gặp phải rằng Xiaomi phá vỡ quy ước Google này và gửi file://, do đó data.getData().getAuthority()đưa ra chuỗi trống.

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
}

Ngoài ra, lỗi khi FileProvider.getUriForFile()xảy ra sự cố java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example/files/attachments/image.jpgđã được sửa trong Thư viện hỗ trợ Android v24.2.0. Vấn đề là FileProvider.java không thấy các thư mục đường dẫn bên ngoài.


1

Nếu bạn đang xây dựng AUTHORITY của mình trong thời gian chạy bằng cách sử dụng, BuildConfighãy đảm bảo bạn sử dụng tên lớp đầy đủ bao gồm tên gói của bạn.

Xấu:

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

Tốt

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


0

Sau đây làm việc cho tôi.

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

0

Đây là những gì tôi đã làm để khắc phục vấn đề. Tôi đã đưa ra tên đầy đủ trong Android: tên. Nó hoạt động trong 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>

bạn có thể vui lòng chia sẻ mã của bạn để chia sẻ tập tin bằng cách sử dụng nhà cung cấp tập tin từ thư mục nội bộ?
Vishal Patoliya

0

Bạn nên thử nó:

  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

Đây là những gì bạn cần làm:

Uri fileURI = FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".fileprovider", file);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.