Android: instale .apk programáticamente

Hice esto con la ayuda de los problemas de descarga de archivos binarios de Android e instalé la aplicación programáticamente en Android .

Quiero hacer la actualización automática y la instalación automática de una vez. Es local, por lo que es una aplicación no de mercado.

Aquí está mi código para esto:

public void Update(String apkurl){ try { URL url = new URL(apkurl); HttpURLConnection c = (HttpURLConnection) url.openConnection(); c.setRequestMethod("GET"); c.setDoOutput(true); c.connect(); String PATH = Environment.getExternalStorageDirectory() + "/download/"; File file = new File(PATH); file.mkdirs(); File outputFile = new File(file, "app.apk"); FileOutputStream fos = new FileOutputStream(outputFile); InputStream is = c.getInputStream(); byte[] buffer = new byte[1024]; int len1 = 0; while ((len1 = is.read(buffer)) != -1) { fos.write(buffer, 0, len1); } fos.close(); is.close();//till here, it works fine - .apk is download to my sdcard in download file Intent promptInstall = new Intent(Intent.ACTION_VIEW) .setData(Uri.parse(PATH+"app.apk")) .setType("application/android.com.app"); startActivity(promptInstall);//installation is not working } catch (IOException e) { Toast.makeText(getApplicationContext(), "Update error!", Toast.LENGTH_LONG).show(); } } 

Mis permisos son INTERNET , WRITE_EXTERNAL_STORAGE , INSTALL_PACKAGES y DELETE_PACKAGES .

Cuando se carga Intent promptInstall , la aplicación falla = /

Entonces, ¿me faltan permisos o mi código es incorrecto o hay una forma mejor de hacerlo?

Resolví el problema. setData(Uri) error en setData(Uri) y setType(String) .

 Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/" + "app.apk")), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); 

Eso es correcto ahora, mi actualización automática está funcionando. Gracias por la ayuda. =)

Editar 20.7.2016:

Después de mucho tiempo, tuve que usar esta forma de actualizar nuevamente en otro proyecto. Me encontré con una serie de problemas con la solución anterior. Muchas cosas han cambiado en ese momento, así que tuve que hacer esto con un enfoque diferente. Aquí está el código:

  //get destination to update file and set Uri //TODO: First I wanted to store my update .apk file on internal storage for my app but apparently android does not allow you to open and install //aplication with existing package from there. So for me, alternative solution is Download directory in external storage. If there is better //solution, please inform us in comment String destination = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/"; String fileName = "AppName.apk"; destination += fileName; final Uri uri = Uri.parse("file://" + destination); //Delete update file if exists File file = new File(destination); if (file.exists()) //file.delete() - test this, I think sometimes it doesnt work file.delete(); //get url of app on server String url = Main.this.getString(R.string.update_app_url); //set downloadmanager DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.setDescription(Main.this.getString(R.string.notification_description)); request.setTitle(Main.this.getString(R.string.app_name)); //set destination request.setDestinationUri(uri); // get download service and enqueue file final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); final long downloadId = manager.enqueue(request); //set BroadcastReceiver to install app when .apk is downloaded BroadcastReceiver onComplete = new BroadcastReceiver() { public void onReceive(Context ctxt, Intent intent) { Intent install = new Intent(Intent.ACTION_VIEW); install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); install.setDataAndType(uri, manager.getMimeTypeForDownloadedFile(downloadId)); startActivity(install); unregisterReceiver(this); finish(); } }; //register receiver for when .apk download is compete registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); 

Para ICS he implementado su código e hice una clase que amplía AsyncTask . ¡Espero que lo aprecies! Gracias por su código y solución.

 public class UpdateApp extends AsyncTask{ private Context context; public void setContext(Context contextf){ context = contextf; } @Override protected Void doInBackground(String... arg0) { try { URL url = new URL(arg0[0]); HttpURLConnection c = (HttpURLConnection) url.openConnection(); c.setRequestMethod("GET"); c.setDoOutput(true); c.connect(); String PATH = "/mnt/sdcard/Download/"; File file = new File(PATH); file.mkdirs(); File outputFile = new File(file, "update.apk"); if(outputFile.exists()){ outputFile.delete(); } FileOutputStream fos = new FileOutputStream(outputFile); InputStream is = c.getInputStream(); byte[] buffer = new byte[1024]; int len1 = 0; while ((len1 = is.read(buffer)) != -1) { fos.write(buffer, 0, len1); } fos.close(); is.close(); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File("/mnt/sdcard/Download/update.apk")), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // without this flag android returned a intent error! context.startActivity(intent); } catch (Exception e) { Log.e("UpdateAPP", "Update error! " + e.getMessage()); } return null; } } 

Para usarlo, en su llamada de actividad principal de esta manera:

 atualizaApp = new UpdateApp(); atualizaApp.setContext(getApplicationContext()); atualizaApp.execute("http://serverurl/appfile.apk"); 

Esta pregunta es muy útil, PERO no olvide montar la tarjeta SD en su emulador, si no lo hace, no funciona.

Pierdo mi tiempo antes de descubrir esto.

 /* * Code Prepared by **Muhammad Mubashir**. * Analyst Software Engineer. Email Id : muhammad.mubashir.bscs@gmail.com Skype Id : muhammad.mubashir.ansari Code: **August, 2011.** Description: **Get Updates(means New .Apk File) from IIS Server and Download it on Device SD Card, and Uninstall Previous (means OLD .apk) and Install New One. and also get Installed App Version Code & Version Name.** All Rights Reserved. */ package com.SelfInstall01; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import com.SelfInstall01.SelfInstall01Activity; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.AlertDialog.Builder; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class SelfInstall01Activity extends Activity { class PInfo { private String appname = ""; private String pname = ""; private String versionName = ""; private int versionCode = 0; //private Drawable icon; /*private void prettyPrint() { //Log.v(appname + "\t" + pname + "\t" + versionName + "\t" + versionCode); }*/ } public int VersionCode; public String VersionName=""; public String ApkName ; public String AppName ; public String BuildVersionPath=""; public String urlpath ; public String PackageName; public String InstallAppPackageName; public String Text=""; TextView tvApkStatus; Button btnCheckUpdates; TextView tvInstallVersion; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //Text= "Old".toString(); Text= "New".toString(); ApkName = "SelfInstall01.apk";//"Test1.apk";// //"DownLoadOnSDcard_01.apk"; // AppName = "SelfInstall01";//"Test1"; // BuildVersionPath = "http://10.0.2.2:82/Version.txt".toString(); PackageName = "package:com.SelfInstall01".toString(); //"package:com.Test1".toString(); urlpath = "http://10.0.2.2:82/"+ Text.toString()+"_Apk/" + ApkName.toString(); tvApkStatus =(TextView)findViewById(R.id.tvApkStatus); tvApkStatus.setText(Text+" Apk Download.".toString()); tvInstallVersion = (TextView)findViewById(R.id.tvInstallVersion); String temp = getInstallPackageVersionInfo(AppName.toString()); tvInstallVersion.setText("" +temp.toString()); btnCheckUpdates =(Button)findViewById(R.id.btnCheckUpdates); btnCheckUpdates.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { GetVersionFromServer(BuildVersionPath); if(checkInstalledApp(AppName.toString()) == true) { Toast.makeText(getApplicationContext(), "Application Found " + AppName.toString(), Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(getApplicationContext(), "Application Not Found. "+ AppName.toString(), Toast.LENGTH_SHORT).show(); } } }); }// On Create END. private Boolean checkInstalledApp(String appName){ return getPackages(appName); } // Get Information about Only Specific application which is Install on Device. public String getInstallPackageVersionInfo(String appName) { String InstallVersion = ""; ArrayList apps = getInstalledApps(false); /* false = no system packages */ final int max = apps.size(); for (int i=0; i apps = getInstalledApps(false); /* false = no system packages */ final int max = apps.size(); for (int i=0; i apps.get(i).versionCode) { isInstalled = true; /*Toast.makeText(getApplicationContext(), "Install Code is better.!", Toast.LENGTH_SHORT).show();*/ DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case DialogInterface.BUTTON_POSITIVE: //Yes button clicked //SelfInstall01Activity.this.finish(); Close The App. DownloadOnSDcard(); InstallApplication(); UnInstallApplication(PackageName.toString()); break; case DialogInterface.BUTTON_NEGATIVE: //No button clicked break; } } }; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("NO need to Install.").setPositiveButton("Install Forcely", dialogClickListener) .setNegativeButton("Cancel.", dialogClickListener).show(); } } } return isInstalled; } private ArrayList getInstalledApps(boolean getSysPackages) { ArrayList res = new ArrayList(); List packs = getPackageManager().getInstalledPackages(0); for(int i=0;i= '0' && s.charAt(i) <= '9' || s.charAt(i) == '.')) { temp = temp.toString().concat(Character.toString(s.charAt(i))) ; i++; } // s = s.substring(i); // Move to Next to Process.! temp = temp + " "; // Separate wrt Space Version Code and Version Name. } String[] fields = temp.split(" ");// Make Array for Version Code and Version Name. VersionCode = Integer.parseInt(fields[0].toString());// .ToString() Return String Value. VersionName = fields[1].toString(); baos.close(); } catch (MalformedURLException e) { Toast.makeText(getApplicationContext(), "Error." + e.getMessage(), Toast.LENGTH_SHORT).show(); e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "Error." + e.getMessage(), Toast.LENGTH_SHORT).show(); } //return true; }// Method End. // Download On My Mobile SDCard or Emulator. public void DownloadOnSDcard() { try{ URL url = new URL(urlpath.toString()); // Your given URL. HttpURLConnection c = (HttpURLConnection) url.openConnection(); c.setRequestMethod("GET"); c.setDoOutput(true); c.connect(); // Connection Complete here.! //Toast.makeText(getApplicationContext(), "HttpURLConnection complete.", Toast.LENGTH_SHORT).show(); String PATH = Environment.getExternalStorageDirectory() + "/download/"; File file = new File(PATH); // PATH = /mnt/sdcard/download/ if (!file.exists()) { file.mkdirs(); } File outputFile = new File(file, ApkName.toString()); FileOutputStream fos = new FileOutputStream(outputFile); // Toast.makeText(getApplicationContext(), "SD Card Path: " + outputFile.toString(), Toast.LENGTH_SHORT).show(); InputStream is = c.getInputStream(); // Get from Server and Catch In Input Stream Object. byte[] buffer = new byte[1024]; int len1 = 0; while ((len1 = is.read(buffer)) != -1) { fos.write(buffer, 0, len1); // Write In FileOutputStream. } fos.close(); is.close();//till here, it works fine - .apk is download to my sdcard in download file. // So please Check in DDMS tab and Select your Emulator. //Toast.makeText(getApplicationContext(), "Download Complete on SD Card.!", Toast.LENGTH_SHORT).show(); //download the APK to sdcard then fire the Intent. } catch (IOException e) { Toast.makeText(getApplicationContext(), "Error! " + e.toString(), Toast.LENGTH_LONG).show(); } } } 

Gracias por compartir esto. Lo tengo implementado y funcionando. Sin embargo:

1) Instalo el ver 1 de mi aplicación (no hay problemas) 2) Pongo el ver 2 en el servidor. la aplicación recupera ver2 y guarda en la tarjeta SD y solicita al usuario que instale el nuevo paquete ver2 3) ver2 se instala y funciona como se esperaba 4) El problema es que cada vez que se inicia la aplicación, el usuario desea volver a instalar la versión 2.

Así que estaba pensando que la solución era simplemente eliminar el APK en la tarjeta SD, pero la tarea Async simplemente recuperaría el ver2 nuevamente para el servidor.

Por lo tanto, la única manera de detenerse al tratar de instalar la apk v2 nuevamente es eliminarla de la tarjeta SD y del servidor remoto.

Como se puede imaginar, eso no va a funcionar, ya que nunca sabré cuándo todos los usuarios han recibido la última versión.

Cualquier ayuda para resolver esto es muy apreciada.

IMPLEMENTÉ EL MÉTODO “LDUNIZIZ” MENCIONADO ANTERIORMENTE.

NUEVA EDICIÓN: Estaba pensando que todos mis APK tienen el mismo nombre. ¿Debería nombrar myapk_v1.0xx.apk y en esa versión establecer de forma proactiva la ruta remota para buscar v.2.0 cada vez que se lance?

Probé la teoría y resuelve el problema. Debe nombrar el archivo de su archivo APK como un control de versiones, recordando siempre configurar su NEXT versión # en su aplicación actualmente lanzada. No es ideal, sino funcional.

¿Existe algún método para leer la versión de Android remota de APK como se inició en el Manifiesto, o descargar el archivo APK disponible en el servidor y antes de solicitar la instalación hacer una comparación de versión para ver si el APK descargado es = o