Simplemente crea una pequeña herramienta para que la aplicación detecte actualizaciones, lo cual es un poco tosco. No puede reanudar la carga en ningún momento. Es solo por un sentimiento personal de que no es necesario. Puede agregar más funciones de acuerdo con sus ideas. Esto es solo para principiantes y personas simples como yo.
El efecto es el siguiente:
La idea básica primero, tome mi desarrollo real como ejemplo: primero que todo, por supuesto, necesitamos una red para solicitar nuestro servidor, obtener la información de la versión apk y la ruta de descarga en el almacén, y compararla con su número de versión actual. Si el número de versión es menor que el número de versión en el almacén, se solicita al usuario que descargue y la operación de intensidad de descarga se realiza de acuerdo con el nivel de actualización (si la descarga es forzada o algo así). La próxima vez, supervise el progreso de la descarga del archivo para actualizar la barra de progreso y la información de progreso en la notificación. Cuando se complete la descarga, el usuario puede hacer clic en (cerrar la notificación) para ingresar a la interfaz de instalación del apk, de modo que esté terminado.
Esta vez usé el framework de red okhttp (okgo) para descargar los archivos, me aseguré de descargar el apk sin filtrar información, solo descárgalo e instálalo directamente.
Lo primero que me viene a la mente es usar un singleton para la gestión de descargas, necesitamos pasar en un contexto.
Contexto de contexto;
AppUpdateService final estático privado INSTANCE = new AppUpdateService ();
private static class LazyHolder { public static AppUpdateService getThis (contexto de contexto) { INSTANCE.context = context; volver INSTANCIA; } } getInstance público estático de AppUpdateService (contexto de contexto) { return LazyHolder.getThis (contexto); }初始化 Notificación 、 notificationCompat.Builder 和 notificationManager
// Notificación inicial
private void initNotification () { notificationManager = (NotificationManager) MyApplication.getInstance (). GetSystemService (Context.NOTIFICATION_SERVICE); builder = new NotificationCompat.Builder (MyApplication.getInstance ()); builder.setContentTitle ("Update. . ") // Establecer el título de notificación.setSmallIcon (R.mipmap.ic_launcher_round) .setLargeIcon (BitmapFactory.decodeResource (MyApplication.getInstance (). GetResources (), R.mipmap.ic_launcher_round)) // Establecer el icono grande del notification . setDefaults (Notification.DEFAULT_LIGHTS) // Establecer el método de recordatorio de la notificación: Breathing light.setPriority (NotificationCompat.PRIORITY_MAX) // Establecer la prioridad de la notificación: maximum.setAutoCancel (false) // Establecer si la notificación es automática cancelado cuando se hace clic una vez
.setContentText ("Progreso de la descarga:" + "0%")
.setProgress (100, 0, false);
notification = builder.build (); // crear objeto de notificación
}
Descarga el código central de la notificación de actualización, puedes elegir directamente si para actualizar Permita que el usuario haga clic para instalar o instalar directamente.
descarga pública void (String url, String filePath) { MyApplication.getInstance (). okGo. <File> post (url) .execute (new FileCallback () { @Override public void onSuccess (Response <File> response) { File file = response.body (); Log.e ("update", "onSuccess: download complete" + file.getPath () + file.getName ()); builder.setContentTitle ("download complete") .setContentText ("haga clic para instalar ") .setAutoCancel (true); // Establecer si la notificación se cancela automáticamente cuando se hace clic una vez // Haga clic para instalar el bloque de código Intent intent = new Intent (Intent.ACTION_VIEW); intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType (Uri.parse ("archivo: //" + archivo.toString ()), "aplicación / vnd.android.package-archive");
PendingIntent pi = PendingIntent.getActivity (contexto, 0, intención, 0);
notificación = builder.setContentIntent (pi) .build ();
notificationManager.notify (1, notificación);
// 自动 安装
// installApk (archivo);
}
// 下载 进度
@Override
public void downloadProgress (Progreso de progreso) { super.downloadProgress (progreso); Log.e ("actualización", "downloadProgress:" + progress.fraction);
builder.setProgress (100, (int) (progress.fraction * 100), falso);
builder.setContentText ("下载 进度:" + (int) (progress.fraction * 100) + "%");
notificación = constructor.build ();
notificationManager.notify (1, notificación);
}
@Override
public void onStart (Solicitud <Archivo,? Extiende Solicitud> solicitud) { super.onStart (solicitud); initNotification (); } @Override public void onError (Response <File> response) { super.onError (respuesta);
Toast.makeText (contexto, "Error de descarga", Toast.LENGTH_SHORT) .show ();
}
});
}
Instalar apk
private void installApk (File file) { // Nueva descarga de la dirección de almacenamiento del archivo apk Archivo apkFile = file; Intent intent = new Intent (Intent.ACTION_VIEW); intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType (Uri.parse (" file: // "+ apkFile.toString ())," application / vnd.android.package-archive "); context.startActivity (intent); notificationManager.cancel (1); // Cancelar notificación } Obtén el número de versión local
public int getVersionCode () { PackageManager packageManager = context.getPackageManager (); int versionCode = 0; intente { PackageInfo packageInfo = packageManager.getPackageInfo (context.getPackageName (), 0); versionCode = packageInfo.versionCode; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace (); } return versionCode; } Obtenga información actualizada y modifíquela de acuerdo con su propio marco de red.
public void getUpdate () { MyApplication.getInstance (). okGo. <String> post ("*****"). execute (new StringCallback () { @Override public void onSuccess (Response <String> respuesta) { ApkSer apkSer = new ApkSer (); apkSer = new Gson (). fromJson (response.body (), ApkSer.class); CustomDialog ("Es necesario actualizar una nueva versión", 3, apkSer.getUpdatePath ()); } }) ; } La información del cuadro de aviso solicita al usuario.
public void CustomDialog (cadena final cominit, int actualizadorv, cadena final url) { CustomDialog.Builder dialog = new CustomDialog.Builder (contexto); dialog.setTitle ("Actualización de versión") .setMessage (cominit); dialog.setCancelable (false) ; // Nivel de actualización 0: Normal 1: Actualización de corrección de errores clave 2: Actualización de nueva función 3: Actualización de configuración 4: Actualización especial, lo que obliga a los usuarios a actualizar if (updates == 0 || updates == 2) { dialog.setCancelBtn ( "Siguiente recordatorio", nuevo DialogInterface.OnClickListener () { @Override public void onClick (DialogInterface dialog, int i) { dialog.dismiss (); } }); } else {
dialog.setCanceledOnTouchOutside (false);
}
dialog.setCancelBtn ("Key Update", new DialogInterface.OnClickListener () { @Override public void onClick (DialogInterface dialog, int i) { Toast.makeText (context, "Agregado a la tarea de descarga", Toast.LENGTH_SHORT) .show (); dialog.dismiss (); download (url, "path"); } }); dialog.create (). Show (); } Campo de objeto de información de versión
public class ApkSer { public String type; // Actualizar el tipo de contenido, paquete de instalación apk res resource public String apkName; public String packageName; // apk nombre del paquete public Long versionCode; // número de versión de la biblioteca public String versionName; // nombre de la versión de la biblioteca public int important; // Nivel de actualización 0: Normal 1: Actualización de corrección de errores clave 2: Actualización de nueva función 3: Actualización de configuración 4: Actualización especial, que obliga a los usuarios a actualizar el compromiso de cadena pública; // Actualizar contenido public String updatePath; // Actualizar download Address public String updateTime; // Update time } El código completo es el siguiente, bienvenido a comentar.
importar android.app.Notification;
import android.app.NotificationManager;
importar android.app.PendingIntent;
importar android.content.Context;
importar android.content.DialogInterface;
importar android.content.Intent;
importar android.content.pm.PackageInfo;
importar android.content.pm.PackageManager;
importar android.graphics.BitmapFactory;
importar android.net.Uri;
importar android.support.v4.app.NotificationCompat;
importar android.util.Log;
importar android.widget.Toast;
import com.google.gson.Gson;
import com.hx.view.widget.CustomDialog;
import com.lzy.okgo.callback.FileCallback;
import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.model.Progress;
import com.lzy.okgo.model.Response;
import com.lzy.okgo.request.base.Request;
import com.pay.library.config.AppConfig;
import com.yhx .loan.R;
import com.yhx.loan.base.MyApplication;
import java.io.File;
public class AppUpdateService { private NotificationManager notificationManager; notificación de notificación privada; // Aviso de progreso de notificación de descarga generador privado NotificationCompat.Builder; marca booleana privada = false; // Envíe una notificación después de que desaparezca el cuadro de progreso y marque public static boolean isUpdate = false; // ¿Se está actualizando el contexto de contexto? Private static final AppUpdateService INSTANCE = new AppUpdateService ();
private static class LazyHolder { public static AppUpdateService getThis (contexto de contexto) { INSTANCE.context = context; volver INSTANCIA; } } getInstance público estático de AppUpdateService (contexto de contexto) { return LazyHolder.getThis (contexto); } private AppUpdateService () { } public void getUpdate () { MyApplication.getInstance (). okGo. <String> publicación (AppConfig.updateAPP_url) .upJson ("{'paquete': '包 名'}") .execute (nuevo StringCallback () { @Override
public void onSuccess (Response <String> response) { ApkSer apkSer = new ApkSer (); apkSer = new Gson (). fromJson (response.body (), ApkSer.class); CustomDialog ("Es necesario actualizar una nueva versión" , 3, apkSer.getUpdatePath ()); } }); } public void CustomDialog (cadena final cominit, int update, final String url) { CustomDialog.Builder dialog = new CustomDialog.Builder (contexto); dialog.setTitle ("Versión update ") .setMessage (cominit); dialog.setCancelable (false); // Nivel de actualización 0: Normal 1: Actualización de corrección de errores clave 2: Actualización de nueva función 3: Actualización de configuración 4: Actualización especial, actualización obligatoria para el usuario si (updatedv = = 0 || actualizatelv == 2) {
dialog.setCancelBtn ("下次 提醒", nuevo DialogInterface.OnClickListener () { @Override public void onClick (DialogInterface dialog, int i) { dialog.dismiss (); } }); } else { dialog.setCanceledOnTouchOutside (falso); } dialog.setCancelBtn ("重点 更新", new DialogInterface.OnClickListener () { @Override public void onClick (DialogInterface dialog, int i) { Toast.makeText (context, "已 添加 到 下载 任务", Toast.LENGTH_SHORT) .show (); dialog.dismiss (); descargar (url, "ruta"
}
});
dialog.create (). show ();
}
// Inicializar notificación
private void initNotification () { notificationManager = (NotificationManager) MyApplication.getInstance (). getSystemService (Context.NOTIFICATION_SERVICE); constructor = nuevo NotificationCompat.Builder ( MyApplication.getInstance ()); builder.setContentTitle ("Actualizar ...") // Establecer el título de la notificación.setSmallIcon (R.mipmap.ic_launcher_round) .setLargeIcon (BitmapFactory.decodeResource (MyApplication.getInstance (). GetResources (), R.mipmap.ic_launcher_round)) // Establecer el icono de notificación grande. SetDefaults (Notification.DEFAULT_LIGHTS) // Establecer el método de notificación: luz de respiración
.setPriority (NotificationCompat.PRIORITY_MAX) // Establezca la prioridad de la notificación:
máxima.setAutoCancel (false) // Establezca si la notificación se cancela automáticamente cuando se
hace clic una vez.setContentText ("Progreso de la descarga:" + "0%")
.setProgress (100, 0, falso);
notificación = builder.build (); // Crear objeto de notificación
}
descarga pública void (String url, String filePath) { MyApplication.getInstance (). OkGo. <File> post (url) .execute (new FileCallback () { @Override public void onSuccess (Response <File> response) { File file = response.body (); Log.e ("update", "onSuccess: download complete" + file.getPath () + file .getName ()); builder.setContentTitle ("Descarga completa")
.setContentText ("Haga clic para instalar")
.setAutoCancel (true); // Establezca si la notificación se cancela automáticamente cuando se hace clic una vez
Intent intent = new Intent (Intent.ACTION_VIEW);
intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType (Uri. Parse ("file: //" + file.toString ()), "application / vnd.android.package-archive");
PendingIntent pi = PendingIntent.getActivity (contexto, 0, intención, 0);
notificación = builder.setContentIntent (pi) .build ();
notificationManager.notify (1, notificación);
// Instalación automática
// installApk (archivo);
}
// Progreso de descarga
@Override
downloadProgress public void (progreso de progreso) { super.downloadProgress (progreso); Log.e ("actualización", "downloadProgress:" + progress.fraction); builder.setProgress (100, (int) (progress.fraction * 100), falso); builder.setContentText ("下载 进度:" + (int) (progress.fraction * 100) + "%"); notificación = constructor.build (); notificationManager.notify (1, notificación); } @Override public void onStart (Solicitar <Archivo,? Extiende Solicitud> solicitud) { super.onStart (solicitud); initNotification ();
@Override
public void onError (Response <File> response) { super.onError (respuesta); Toast.makeText (contexto, "下载 错误", Toast.LENGTH_SHORT) .show (); } }); } / ** * 安装 apk * / private void installApk (Archivo de archivo) { // 新 下载 apk 文件 存储 地址 Archivo apkFile = archivo; Intención Intención = nueva Intención (Intent.ACTION_VIEW); intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType (Uri.parse ("archivo: //" + apkFile.toString ()), "aplicación / vnd.android.package-archive"); context.startActivity (intención);
notificationManager.cancel (1); // 取消 通知
}
/ **
* 获取 本地 版本 号
*
* @return
* /
public int getVersionCode () { PackageManager packageManager = context.getPackageManager (); int versionCode = 0; intente { PackageInfo packageInfo = packageManager.getPackageInfo (context.getPackageName (), 0); versionCode = packageInfo.versionCode; } captura (PackageManager.NameNotFoundException e) { e.printStackTrace (); } return versionCode; } }
Finalmente, encontré que API> = 24 definitivamente no funciona con este método. Para file: /// storage / emulated / 0 / xxx, el acceso al archivo de Android N falla android.os.FileUriExposedException. Si desea conectarse, no repetirá la introducción de muchas formas. Consulte la introducción de los siguientes blogueros.
https://blog.csdn.net/honjane/article/details/54411820
https://blog.csdn.net/ruancoder/article/details/67639621
https://blog.csdn.net/xiaoyu940601/article/details/ 54406725
Finalmente encontrado para el archivo: /// almacenamiento / emulado / 0 / xxx / ... archivo. La ruta en nuestro filepaths.xml debe tener la ruta xxx, para que el archivo se pueda encontrar sin errores. No sé demasiado. De todos modos, el problema de la notificación de errores finalmente está resuelto.