permission - permisos android manifest
Filtro de intención de Android: asociar la aplicación con la extensión de archivo (12)
Tengo un tipo de archivo / extensión personalizada con la que quiero asociar mi aplicación.
Por lo que yo sé, el elemento de datos está hecho para este propósito, pero no puedo hacerlo funcionar. http://developer.android.com/guide/topics/manifest/data-element.html Según los documentos y muchas publicaciones en el foro, debería funcionar así:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="application/pdf" />
</intent-filter>
Bueno, no funciona. ¿Qué hice mal? Simplemente quiero declarar mi propio tipo de archivo.
Aquellos que tienen problemas con otras aplicaciones File Manager / Explorer, como respondieron @yuku y @ phyrum-tea
Esto funciona con la aplicación de administrador de archivos predeterminada de LG
<intent-filter android:label="@string/app_name_decrypt">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:pathPattern=".*//.lock" />
<data android:pathPattern=".*//..*//.lock" />
<data android:pathPattern=".*//..*//..*//.lock" />
</intent-filter>
pero no pude trabajar con ES File Explorer y otros administradores de archivos, así que agregué
android:mimeType="*/*"
luego funciona con ES Explorer, pero el administrador de archivos de LG no pudo detectar el tipo de archivo, por lo que mi solución es
<intent-filter android:label="@string/app_name_decrypt">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:pathPattern=".*//.lock" />
<data android:pathPattern=".*//..*//.lock" />
<data android:pathPattern=".*//..*//..*//.lock" />
</intent-filter>
<intent-filter android:label="@string/app_name_decrypt">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file"/>
<data android:scheme="content" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*//.lock" />
<data android:pathPattern=".*//..*//.lock" />
<data android:pathPattern=".*//..*//..*//.lock" />
</intent-filter>
Contenido URI ftw y con el filtro de intención en el manifiesto ... si sus archivos tienen una extensión personalizada .xyz, agregue un tipo de mime coincidente:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="*"
android:mimeType="application/xyz"
android:scheme="content" />
</intent-filter>
Algunas aplicaciones, como el correo electrónico, parecen convertir la extensión en un tipo de mimo. Ahora puedo hacer clic en el archivo adjunto en el correo electrónico y abrirlo en mi aplicación.
El pathPattern
<data android:pathPattern=".*//.pdf" />
no funciona si la ruta del archivo contiene uno o más puntos antes de ".pdf".
Esto funcionará:
<data android:pathPattern=".*//.pdf" />
<data android:pathPattern=".*//..*//.pdf" />
<data android:pathPattern=".*//..*//..*//.pdf" />
<data android:pathPattern=".*//..*//..*//..*//.pdf" />
Agregue más si desea admitir más puntos.
He intentado hacer que esto funcione durante años y he intentado básicamente todas las soluciones sugeridas y todavía no logro que Android reconozca las extensiones de archivos específicas. Tengo un filtro de intención con un tipo de letra "*/*"
que es lo único que parece funcionar y los navegadores de archivos ahora muestran mi aplicación como una opción para abrir archivos. Sin embargo, ahora mi aplicación se muestra como una opción para abrir CUALQUIER Tipo de archivo aunque he especificado extensiones de archivo específicas utilizando la etiqueta pathPattern. Esto va tan lejos que, incluso cuando trato de ver / editar un contacto en mi lista de contactos, Android me pregunta si quiero usar mi aplicación para ver el contacto, y esa es solo una de muchas situaciones donde ocurre esto, MUY MUY molesto.
Eventualmente encontré esta publicación de Google Groups con una pregunta similar a la que respondió un ingeniero de framework de Android. Ella explica que Android simplemente no sabe nada sobre las extensiones de archivos, solo los tipos MIME ( https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0 ).
Por lo que he visto, probado y leído, Android simplemente no puede distinguir entre las extensiones de archivos y la etiqueta pathPattern es básicamente una gran pérdida de tiempo y energía. Si tiene la suerte de que solo necesita archivos de un cierto tipo de mime (por ejemplo, texto, video o audio), puede usar un filtro de intención con un tipo mime. Si necesita una extensión de archivo específica o un tipo de mimo desconocido para Android, entonces no tiene suerte.
Si me equivoco sobre algo de esto, por favor díganme, hasta ahora he leído todas las publicaciones e intenté todas las soluciones propuestas que pude encontrar, pero ninguna ha funcionado.
Podría escribir una o dos páginas más acerca de cuán común es este tipo de cosas en Android y qué tan jodida es la experiencia del desarrollador, pero te ahorraré mis enojos y desvaríos;). Espero haber salvado a alguien algunos problemas.
Las otras soluciones no funcionaron de manera confiable hasta que agregué:
android:mimeType="*/*"
Antes de eso, funcionó en algunas aplicaciones, en algunas no ...
solución completa para mí:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" android:host="*" android:pathPattern=".*//.EXT" android:mimeType="*/*" />
</intent-filter>
Las respuestas dadas por y son muy informativas.
Quiero agregar que a partir de Android 7.0 Nougat hay un cambio en la manera en que se maneja el intercambio de archivos entre las aplicaciones:
De los cambios oficiales de Android 7.0 :
En el caso de las aplicaciones orientadas a Android 7.0, Android Framework impone la política de la API StrictMode que prohíbe la exposición de los URI de archivo: // fuera de la aplicación. Si un intento que contiene un URI de archivo deja tu aplicación, la aplicación falla con una excepción FileUriExposedException.
Para compartir archivos entre aplicaciones, debe enviar un contenido: // URI y otorgar un permiso de acceso temporal en el URI. La forma más fácil de otorgar este permiso es mediante el uso de la clase FileProvider. Para obtener más información sobre permisos y compartir archivos, vea Compartir archivos.
Si tiene su propia finalización de archivo personalizada sin un tipo de mime-type
específico (o supongo que incluso con uno), puede que tenga que agregar un segundo valor de scheme
a su intent-filter
para que funcione también con FileProviders
.
Ejemplo:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:scheme="content" />
<data android:mimeType="*/*" />
<!--
Work around Android''s ugly primitive PatternMatcher
implementation that can''t cope with finding a . early in
the path unless it''s explicitly matched.
-->
<data android:host="*" />
<data android:pathPattern=".*//.sfx" />
<data android:pathPattern=".*//..*//.sfx" />
<data android:pathPattern=".*//..*//..*//.sfx" />
<data android:pathPattern=".*//..*//..*//..*//.sfx" />
<!-- keep going if you need more -->
</intent-filter>
Lo importante aquí es la adición de
<data android:scheme="content" />
al filtro.
Me costó enterarme de este pequeño cambio que impedía que mi actividad se abriera en dispositivos con Android 7.0, mientras que todo funcionaba bien en versiones anteriores. Espero que esto ayude a alguien.
Markus Ressel está en lo cierto. Android 7.0 Nougat ya no permite el intercambio de archivos entre aplicaciones usando un URI de archivo. Se debe usar un URI de contenido. Sin embargo, un URI de contenido no permite compartir una ruta de archivo, solo un tipo de mimo. Por lo tanto, no puede usar un URI de contenido para asociar su aplicación con su propia extensión de archivo.
Drobpox tiene un comportamiento interesante en Android 7.0. Cuando se encuentra con una extensión de archivo desconocida, parece formar un intento de URI de archivo, pero en lugar de lanzar el intento, llama al sistema operativo para averiguar qué aplicaciones pueden aceptar el intento. Si solo hay una aplicación que puede aceptar ese URI de archivo, entonces envía un URI de contenido explícito directamente a esa aplicación. Por lo tanto, para trabajar con Dropbox no necesita cambiar los filtros de intención en su aplicación. No requiere un filtro de intención de URI de contenido. Solo asegúrate de que la aplicación pueda recibir un URI de contenido y tu aplicación con tu propia extensión de archivo funcionará con Dropbox como lo hizo antes de Android 7.0.
Aquí hay un ejemplo de mi código de carga de archivo modificado para aceptar un URI de contenido:
Uri uri = getIntent().getData();
if (uri != null) {
File myFile = null;
String scheme = uri.getScheme();
if (scheme.equals("file")) {
String fileName = uri.getEncodedPath();
myFile = new File(filename);
}
else if (!scheme.equals("content")) {
//error
return;
}
try {
InputStream inStream;
if (myFile != null) inStream = new FileInputStream(myFile);
else inStream = getContentResolver().openInputStream(uri);
InputStreamReader rdr = new InputStreamReader(inStream);
...
}
}
Mis hallazgos:
Necesita varios filtros para tratar las diferentes formas de recuperar un archivo. es decir, mediante archivos adjuntos de Gmail, por explorador de archivos, por HTTP, por FTP ... Todos envían intenciones muy diferentes.
Y debe filtrar la intención que desencadena su actividad en su código de actividad.
Para el siguiente ejemplo, creé un tipo de archivo falso new.mrz. Y lo recuperé desde el archivo adjunto de Gmail y el explorador de archivos.
Código de actividad agregado en onCreate ():
Intent intent = getIntent();
String action = intent.getAction();
if (action.compareTo(Intent.ACTION_VIEW) == 0) {
String scheme = intent.getScheme();
ContentResolver resolver = getContentResolver();
if (scheme.compareTo(ContentResolver.SCHEME_CONTENT) == 0) {
Uri uri = intent.getData();
String name = getContentName(resolver, uri);
Log.v("tag" , "Content intent detected: " + action + " : " + intent.getDataString() + " : " + intent.getType() + " : " + name);
InputStream input = resolver.openInputStream(uri);
String importfilepath = "/sdcard/My Documents/" + name;
InputStreamToFile(input, importfilepath);
}
else if (scheme.compareTo(ContentResolver.SCHEME_FILE) == 0) {
Uri uri = intent.getData();
String name = uri.getLastPathSegment();
Log.v("tag" , "File intent detected: " + action + " : " + intent.getDataString() + " : " + intent.getType() + " : " + name);
InputStream input = resolver.openInputStream(uri);
String importfilepath = "/sdcard/My Documents/" + name;
InputStreamToFile(input, importfilepath);
}
else if (scheme.compareTo("http") == 0) {
// TODO Import from HTTP!
}
else if (scheme.compareTo("ftp") == 0) {
// TODO Import from FTP!
}
}
Filtro de adjuntos de Gmail:
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="application/octet-stream" />
</intent-filter>
- LOG: intento de contenido detectado: android.intent.action.VIEW: content: //gmail-ls/[email protected]/messages/2950/attachments/0.1/BEST/false: application / octet-stream: new. mrz
Filtro de explorador de archivos:
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:pathPattern=".*//.mrz" />
</intent-filter>
- LOG: intento de archivo detectado: android.intent.action.VIEW: file: ///storage/sdcard0/My%20Documents/new.mrz: null: new.mrz
Filtro HTTP:
<intent-filter android:label="@string/rbook_viewer">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:pathPattern=".*//.mrz" />
</intent-filter>
Funciones privadas usadas anteriormente:
private String getContentName(ContentResolver resolver, Uri uri){
Cursor cursor = resolver.query(uri, null, null, null, null);
cursor.moveToFirst();
int nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
if (nameIndex >= 0) {
return cursor.getString(nameIndex);
} else {
return null;
}
}
private void InputStreamToFile(InputStream in, String file) {
try {
OutputStream out = new FileOutputStream(new File(file));
int size = 0;
byte[] buffer = new byte[1024];
while ((size = in.read(buffer)) != -1) {
out.write(buffer, 0, size);
}
out.close();
}
catch (Exception e) {
Log.e("MainActivity", "InputStreamToFile exception: " + e.getMessage());
}
}
Necesita varios filtros de intención para abordar la situación diferente que desea manejar.
El ejemplo 1, maneja las solicitudes http sin tipos mimet:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:host="*" />
<data android:pathPattern=".*//.pdf" />
</intent-filter>
Manejar con tipos mimet, donde el sufijo es irrelevante:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:host="*" />
<data android:mimeType="application/pdf" />
</intent-filter>
Manejar el intento desde una aplicación de navegador de archivos:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:host="*" />
<data android:pathPattern=".*//.pdf" />
</intent-filter>
Para los archivos adjuntos de Gmail, puede usar:
<intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="application/pdf" /> <!-- .pdf -->
<data android:mimeType="application/msword" /> <!-- .doc / .dot -->
<data android:mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document" /> <!-- .docx -->
<data android:mimeType="application/vnd.ms-excel" /> <!-- .xls / .xlt / .xla -->
<data android:mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" /> <!-- .xlsx -->
<data android:mimeType="application/vnd.ms-powerpoint" /> <!-- .ppt / .pps / .pot / .ppa -->
<data android:mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation" /> <!-- .pptx -->
<data android:mimeType="application/vnd.openxmlformats-officedocument.presentationml.slideshow" /> <!-- .ppsx -->
<data android:mimeType="application/zip" /> <!-- .zip -->
<data android:mimeType="image/jpeg" /> <!-- .jpeg -->
<data android:mimeType="image/png" /> <!-- .png -->
<data android:mimeType="image/gif" /> <!-- .gif -->
<data android:mimeType="text/plain" /> <!-- .txt / .text / .log / .c / .c++ / ... -->
Agregue tantos tipos de mime como sea necesario. Solo los necesito para mi proyecto.
Prueba agregar
<action android:name="android.intent.action.VIEW"/>
<!--
Works for Files, Drive and DropBox
-->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:host="*" />
<data android:pathPattern=".*//.teamz" />
</intent-filter>
<!--
Works for Gmail
-->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT"/>
<data android:host="gmail-ls" android:scheme="content" android:mimeType="application/octet-stream"/>
</intent-filter>
Tenga en cuenta que esto hará que su aplicación abra todos los archivos adjuntos de Gmail, no hay forma de evitarlo