puedo puede pasar instalar desde descargadas como archivos archivo abrir android

android - puede - ¿Podemos instalar un APK desde un ContentProvider?



no puedo instalar apk descargadas (4)

Estoy trabajando en una biblioteca para permitir que las aplicaciones se actualicen automáticamente , para aquellas que se están distribuyendo fuera de Android Market.

Mi plan original era incluir el código que descargaría el archivo APK en el almacenamiento interno y luego lo instalaría desde allí a través de un ContentProvider y un content:// Uri . Sin embargo, cuando lo intenté, el sistema del instalador volcó una advertencia "Skipping dir:" a LogCat y no lo instaló. Una vez que cambié a la descarga del APK al almacenamiento externo y ACTION_VIEW un file:// Uri con el instalador ACTION_VIEW Intent , funcionó.

El mensaje "Skipping dir:" parece estar registrado por parsePackage() en PackageParser , que parece asumir que está trabajando con un File . Eso sugeriría que no podemos usar el content:// valores de Uri .

¿Alguien ha utilizado con éxito ACTION_VIEW en una application/vnd.android.package-archive Intent con un content:// Uri ? Si es así, ¿hubo algún truco específico en la configuración del ContentProvider que lo hizo funcionar?

¡Gracias!


Estoy de acuerdo con el análisis de Jules y agregaría precisiones concretas:

En PackageInstallerActivity , que es llamada por ACTION_VIEW en un apk, hay esto en el método onCreate() :

315 String apkPath = mPackageURI.getPath(); 316 File apkFile = new File(apkPath);

Y antes de eso, este método de PackageUtil se llama:

73 public static PackageParser.Package getPackageInfo(Uri packageURI) { 74 final String archiveFilePath = packageURI.getPath(); 75 PackageParser packageParser = new PackageParser(archiveFilePath); 76 File sourceFile = new File(archiveFilePath); 77 DisplayMetrics metrics = new DisplayMetrics(); 78 metrics.setToDefaults(); 79 return packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0); 80 }

Todo esto tiende a confirmar que el PackageManager espera solo archivos Uris.

El registro que tiene, Skipping dir: se encuentra en packageParser.parsePackage , que prueba si la ruta dada en el Uri es un archivo o no.


La documentación para ACTION_INSTALL_PACKAGE es incorrecta. También solo aceptará archivos.

Por lo tanto, mi única sugerencia sería crear una copia del archivo en el área de archivos de las aplicaciones, hacer que sea legible para todo el mundo y limpiar los archivos que queden en una fecha posterior.

Respuesta incorrecta anterior : en 4.0 y versiones superiores hay un ACTION_INSTALL_PACKAGE que acepta un contenido: // URI ( JavaDoc ), pero, antes de eso, está limitado a la instalación a través de ACTION_VIEW que asume que el URI aprobado es un archivo: / / URI.


Supongo que esto no es posible, ya que la API de Java no parece permitirlo. El openFile() ContentProvider devuelve un ParcelFileDescriptor , desde el cual puede obtener un java.io.FileDescriptor . Luego puede usar este FileDescriptor para abrir un FileInputStream o un FileOutputStream . Desafortunadamente, no puede usarlo para abrir un RandomAccessFile (a pesar de que RandomAccessFile funciona en los descriptores de la misma manera que el resto, el constructor que necesitaría simplemente falta en la API).

Como los archivos APK son archivos ZIP, que deben leerse desordenados (hay que buscar hasta el final para encontrar el directorio de archivos), asumo que la implementación de la instalación requerirá un RandomAccessFile , por lo que no habría sido posible respaldar caso estás tratando de implementar.


Tengo esto en una de mis aplicaciones, que me permite acceder al almacenamiento local (las preferencias del usuario se pueden seleccionar antes de que lo intentes;))

import java.io.*; import android.content.*; import android.database.*; import android.net.*; import android.os.*; import android.preference.PreferenceManager; import android.util.Log; public class LocalFileContentProvider extends ContentProvider { private static final String URI_PREFIX = "content://your.content.provider.as.per.manifest"; public static String constructUri(String url) { Uri uri = Uri.parse(url); return uri.isAbsolute() ? url : URI_PREFIX + url; } @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(getContext()); boolean allowLocal = app_preferences.getBoolean("allowLocalFiles", false); if (allowLocal) { try { File file = new File(uri.getPath()); if (file.isDirectory()) return null; ParcelFileDescriptor parcel = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); return parcel; } catch (Exception e) { return null; } } else { return null; } } @Override public boolean onCreate() { return true; } @Override public int delete(Uri uri, String s, String[] as) { throw new UnsupportedOperationException("Not supported by this provider"); } @Override public String getType(Uri uri) { throw new UnsupportedOperationException("Not supported by this provider"); } @Override public Uri insert(Uri uri, ContentValues contentvalues) { throw new UnsupportedOperationException("Not supported by this provider"); } @Override public Cursor query(Uri uri, String[] as, String s, String[] as1, String s1) { throw new UnsupportedOperationException("Not supported by this provider"); } @Override public int update(Uri uri, ContentValues contentvalues, String s, String[] as) { throw new UnsupportedOperationException("Not supported by this provider"); } }

Mi manifiesto contiene

<provider android:name="it.automated.android.kiosk.se.LocalFileContentProvider" android:authorities="it.automated" />

y luego para iniciar la instalación (o acción)

Intent viewIntent = new Intent(Intent.ACTION_VIEW); viewIntent.setDataAndType(Uri.parse(url), mimeType);