Access to the File Provider denied on Android

0

I have an associated activity for opening a type of file, using a file explorer, when selecting the document and that opens with my app, sometimes I receive:

  

Caused by: java.lang.SecurityException: Permission Denial: reading nextapp.fx.fileprovider.FileProvider uri content: //nextapp.fx.FileProvider/storage/emulated/0/Documents/Untitled4.md from pid = 31631, uid = 10442 requires the provider to be exported, or grantUriPermission ()

The code where it jumps:

public static String getFileName(Context context, @NonNull Uri uri) {
    String displayName = null;
    String uriString = uri.toString();
    if (uriString.startsWith("content://")) {
        try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
            }
        }
    } else if (uriString.startsWith("file://")) {
        File myFile = new File(uriString);
        displayName = myFile.getName();
    }
    return displayName;
}

When trying to resolve the content provider: context.getContentResolver()

AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

And the permission granted Android M > of WRITE_EXTERNAL_STORAGE set by the user dynamically.

Should other permissions be granted in order to use content providers?

Definition of content provider

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

Solution ??

Searching for SO I have fixed the error, before getting the name of the file , to intercept the opening intent:

List<ResolveInfo> resInfoList = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
    String packageName = resolveInfo.activityInfo.packageName;
    grantUriPermission(packageName, markDownFile, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}

I understand that this code what it does is grant reading and writing permission to all installed apps can use the uri of the content provider.

But is there a way to only grant permission to the concrete URL of the content provider, but only for the app that asks to open it?

    
asked by Webserveis 01.08.2018 в 09:05
source

1 answer

0

For applications that point to API 23+ it is necessary to handle the dynamic permissions , it was a major design change by which the permissions declared in the manifest are not granted at the time of download but are requested at the time of use. To solve the problem you have 2 options:

  • Changing the API target of your app to 22 is not recommended as it disables you from using the platform's modern features. but it takes you out of the problem quickly.
  • Using the dynamic permission strategy, each time you access the use of a "dangerous" permission " should you: Check if the permit was granted and if not, request it or handle the rejection:

        if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission. << Permiso >> ) != PackageManager.PERMISSION_GRANTED) { //Permiso no otorgado//Ya se negó el permiso antes, insistir con una explicación de por que se pide el permiso. 
            if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
                    Manifest.permission. << Permiso >> )) {
                // Mostrar un detalle de por que se pide el permiso
            } else {
                // No se negó el permiso antes, solicitar normalmente.
                ActivityCompat.requestPermissions(thisActivity,
                        new String[] {
                                Manifest.permission. << Permiso >>
                        }, requestcode);
    
                // Este pedido es asincronico, por lo que requestcode sirve para identificar el pedido luego en onRequestPermissionsResult
            }
        } else {
            // Permiso otorgado, usar normalmente
        }
    
  • With that you send the permission request and you should handle the answer accordingly:

    @Override
    public void onRequestPermissionsResult(int requestCode,
            String permissions[], int[] grantResults) {
        switch (requestCode) {
            case XXX: {
                // si no se otorgaron los permisos, el array vuelve vacio.
                if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // Permiso otorgado, usar normalmente
                } else {
                    // Permiso negado, manejar situación
                }
                return;
            }
    
        }
    }
    
        
    answered by 01.08.2018 в 14:38