geturiforfile - import file provider android
Accidente de FileProvider: npe que intenta invocar XmlResourceParser en una cadena nula (8)
Esta es una parte de mi manifiesto:
<?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>
Este es el archivo filepaths en 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>
Descargo un video de Internet y lo guardo en el almacenamiento interno de esta manera:
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;
}
}
Intento usarlo así:
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();
}
}
En esta línea:
Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "com.example.asd", newFile);
Obtuve el siguiente error:
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)
Deberías probarlo:
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);
El problema era que en Manifiesto tenía esta línea:
android:authorities="com.example.asd.fileprovider"
y al llamar a getUriForFile estaba pasando:
Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "com.example.asd", newFile);
Así que cambió de
"com.example.asd"
a
"com.example.asd.fileprovider"
y funcionó
En mi caso, recibí el error porque el
BuildConfig.APPLICATION_ID
estaba siendo importado de
import android.support.v4.BuildConfig;
Entonces, la cadena que devolvió fue
"android.support.v4"
lugar del nombre del paquete de mi proyecto.
Echa un vistazo a que el archivo de importación es de tu
import project.Buildconfig
.
Ejemplo:
import com.example.yourProjectName.BuildConfig;
Finalmente, en la etiqueta
<provider>
en Manifest tengo
android:authorities="${applicationId}"
para obtener siempre el nombre del paquete de mi proyecto como autoridad
<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>
Esto es lo que hice para solucionar el problema. Di nombre completo en Android: nombre. Funciona en 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>
Lo siguiente funcionó para mí.
mUri = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".provider",
fileObject);
Primero, asegúrese de que su proveedor de
android:authorities
no entren en conflicto con sus otros proveedores.
Además de eso, puede elegir cualquier nombre para la última parte de su nombre: "proveedor", "proveedor de archivos", etc., pero la aplicación se bloquea cuando hay más de un
android:authorities
enumeradas, mientras que la documentación indica que permite que se enumeren varios valores.
file://
esquema
file://
ahora no se puede adjuntar con Intent en targetSdkVersion> = 24 (Android N 7.0), solo el
content://
siempre se pasa para todos los dispositivos (Android 5, 6 y 7).
Pero descubrimos que Xiaomi rompe esta convención de Google y envía el
file://
, de ahí
data.getData().getAuthority()
da una cadena vacía.
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
}
Además, el error cuando
FileProvider.getUriForFile()
resultó en un bloqueo
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example/files/attachments/image.jpg
se corrigió en la Biblioteca de soporte de Android v24.2.0.
El problema era que FileProvider.java no veía carpetas de ruta externa.
Puede hacerlo sin codificar el nombre del paquete con un beneficio adicional de poder ejecutar múltiples variantes en el mismo dispositivo (piense en
release
y
debug
con
applicationIdSuffix
, vea
estos problemas
):
Basado en
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);
estaba utilizando la
authority
incorrecta y no encontró
ContentProvider
(
info == null
).
Cambie su manifiesto a (
${applicationId}
será reemplazado por Manifest Merger)
android:authorities="${applicationId}.share"
y
Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".share", result);
El sufijo
.share
es opcional, en caso de que tenga un
ContentProvider
real que es mejor tener el nombre del paquete como autoridad.
Si está creando su AUTORIDAD en tiempo de ejecución con
BuildConfig
asegúrese de usar el nombre completo de la clase, incluido el nombre del paquete.
Malo:
final String AUTHORITY = BuildConfig.APPLICATION_ID + ".provider";
Bueno:
final String AUTHORITY = com.mycompany.myapp.BuildConfig.APPLICATION_ID + ".provider";