Simply make a small tool for APP to detect updates, which is a bit rough. You can’t resume the upload at any time. It’s just for personal feeling that it’s not necessary. You can add more functions according to your ideas. This is just for beginners and simple people like me.
The effect is as follows:
The basic idea first, take my actual development as an example: First of all, of course, we need a network to request our server, get the apk version information and download path in the warehouse, and compare it with your current version number. If the version number is smaller than the version number in the warehouse, the user is prompted to download, and the download intensity operation is performed according to the update level (whether the download is forced or something). At the next time, monitor the progress of the file download to update the progress bar and progress information in the notification. When the download is completed, the user can click (close the notification) to enter the installation apk interface, so that it is completed.
This time I used the okhttp (okgo) network framework to download the files. I made sure to download the apk without filtering information, just download and install it directly.
The first thing that comes to mind is to use a singleton for download management, we need to pass in a context.
Context context;
private static final AppUpdateService INSTANCE = new AppUpdateService();
private static class LazyHolder {
public static AppUpdateService getThis(Context context) {
INSTANCE.context = context;
return INSTANCE;
}
}
public static AppUpdateService getInstance(Context context) {
return LazyHolder.getThis(context);
}
初始化Notification 、notificationCompat.Builder和notificationManager
//Initial notification
private void initNotification() { notificationManager = (NotificationManager) MyApplication.getInstance().getSystemService(Context.NOTIFICATION_SERVICE); builder = new NotificationCompat.Builder(MyApplication.getInstance()); builder.setContentTitle("Update. ..") //Set the notification title.setSmallIcon(R.mipmap.ic_launcher_round) .setLargeIcon(BitmapFactory.decodeResource(MyApplication.getInstance().getResources(), R.mipmap.ic_launcher_round)) //Set the large icon of the notification . setDefaults(Notification.DEFAULT_LIGHTS) //Set the reminder method of the notification: Breathing light.setPriority(NotificationCompat.PRIORITY_MAX) //Set the priority of the notification: maximum.setAutoCancel(false)//Set whether the notification is automatically canceled when clicked once
.setContentText("Download progress:" + "0%")
.setProgress(100, 0, false);
notification = builder.build();//build notification object
}
Download and update the core code of notification, you can directly choose whether to update Let the user click to install, or install directly.
public void download(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("click to install" ) .setAutoCancel(true);//Set whether the notification is automatically canceled when clicked once //Click to install the code block 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(context, 0, intent, 0);
notification = builder.setContentIntent(pi).build();
notificationManager.notify(1, notification);
//自动安装
// installApk(file);
}
//下载进度
@Override
public void downloadProgress(Progress progress) {
super.downloadProgress(progress);
Log.e("update", "downloadProgress: " + progress.fraction);
builder.setProgress(100, (int) (progress.fraction * 100), false);
builder.setContentText("下载进度:" + (int) (progress.fraction * 100) + "%");
notification = builder.build();
notificationManager.notify(1, notification);
}
@Override
public void onStart(Request<File, ? extends Request> request) {
super.onStart(request);
initNotification();
}
@Override
public void onError(Response<File> response) {
super.onError(response);
Toast.makeText(context, "Download error", Toast.LENGTH_SHORT).show();
}
});
}
Install apk
private void installApk(File file) { //New download apk file storage address File 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);//Cancel notification } Get the local version number
public int getVersionCode() { PackageManager packageManager = context.getPackageManager(); int versionCode = 0; try { PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); versionCode = packageInfo.versionCode; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return versionCode; } Get updated information and modify it according to your own network framework.
public void getUpdate() { MyApplication.getInstance().okGo.<String>post("*****").execute(new StringCallback() { @Override public void onSuccess(Response<String> response) { ApkSer apkSer = new ApkSer(); apkSer = new Gson().fromJson(response.body(), ApkSer.class); CustomDialog("A new version needs to be updated", 3, apkSer.getUpdatePath()); } }); } The prompt box information prompts the user.
public void CustomDialog(final String cominit, int updatelv, final String url) { CustomDialog.Builder dialog = new CustomDialog.Builder(context); dialog.setTitle("Version Update") .setMessage(cominit); dialog.setCancelable(false) ; //Update level 0: Normal 1: Key bug fix update 2: New function update 3: Configuration update 4: Special update, forcing users to update if (updatelv == 0 || updatelv == 2) { dialog.setCancelBtn(" Next reminder", new 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,"Added to download task" ,Toast.LENGTH_SHORT).show(); dialog.dismiss(); download(url, "path"); } }); dialog.create().show(); } Version information object field
public class ApkSer { public String type; //Update content type, apk installation package res resource public String apkName; public String packageName; //apk package name public Long versionCode; //library version number public String versionName; //library version name public int important; //Update level 0: Normal 1: Key bug fix update 2: New feature update 3: Configuration update 4: Special update, forcing users to update public String commit; //Update content public String updatePath; //Update download Address public String updateTime; //Update time } The complete code is as follows, welcome to comment.
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import 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; private Notification notification; //Download notification progress prompt private NotificationCompat.Builder builder; private boolean flag = false; //Send notification after the progress box disappears public static boolean isUpdate = false; //Is the context context being updated ; private static final AppUpdateService INSTANCE = new AppUpdateService();
private static class LazyHolder {
public static AppUpdateService getThis(Context context) {
INSTANCE.context = context;
return INSTANCE;
}
}
public static AppUpdateService getInstance(Context context) {
return LazyHolder.getThis(context);
}
private AppUpdateService() {
}
public void getUpdate() {
MyApplication.getInstance().okGo.<String>post(AppConfig.updateAPP_url)
.upJson("{'package':'包名'}")
.execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) { ApkSer apkSer = new ApkSer(); apkSer = new Gson().fromJson(response.body(), ApkSer.class); CustomDialog("A new version needs to be updated", 3 , apkSer.getUpdatePath()); } }); } public void CustomDialog(final String cominit, int updatelv, final String url) { CustomDialog.Builder dialog = new CustomDialog.Builder(context); dialog.setTitle("Version update" ) .setMessage(cominit); dialog.setCancelable(false); //Update level 0: Normal 1: Key bug fix update 2: New feature update 3: Configuration update 4: Special update, mandatory user update if (updatelv == 0 || updatelv == 2) {
dialog.setCancelBtn("下次提醒", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int i) {
dialog.dismiss();
}
});
} else {
dialog.setCanceledOnTouchOutside(false);
}
dialog.setCancelBtn("重点更新", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int i) {
Toast.makeText(context,"已添加到下载任务",Toast.LENGTH_SHORT).show();
dialog.dismiss();
download(url, "path");
}
});
dialog.create().show();
}
//Initialize notification
private void initNotification() { notificationManager = (NotificationManager) MyApplication.getInstance().getSystemService(Context.NOTIFICATION_SERVICE); builder = new NotificationCompat.Builder( MyApplication.getInstance()); builder.setContentTitle("Update...") //Set the notification title.setSmallIcon(R.mipmap.ic_launcher_round) .setLargeIcon(BitmapFactory.decodeResource(MyApplication.getInstance().getResources(), R.mipmap.ic_launcher_round)) //Set the large notification icon. setDefaults(Notification.DEFAULT_LIGHTS) //Set the notification method: breathing light
.setPriority(NotificationCompat.PRIORITY_MAX) //Set the priority of the notification:
maximum.setAutoCancel(false)//Set whether the notification is automatically canceled when
clicked once.setContentText("Download progress:" + "0%")
.setProgress(100, 0, false);
notification = builder.build();//Build notification object
}
public void download(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("Click to install")
.setAutoCancel(true);//Set whether the notification is automatically canceled when clicked once
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(context, 0, intent, 0);
notification = builder.setContentIntent (pi).build();
notificationManager.notify(1, notification);
//Automatic installation
// installApk(file);
}
//Download progress
@Override
public void downloadProgress(Progress progress) {
super.downloadProgress(progress);
Log.e("update", "downloadProgress: " + progress.fraction);
builder.setProgress(100, (int) (progress.fraction * 100), false);
builder.setContentText("下载进度:" + (int) (progress.fraction * 100) + "%");
notification = builder.build();
notificationManager.notify(1, notification);
}
@Override
public void onStart(Request<File, ? extends Request> request) {
super.onStart(request);
initNotification();
}
@Override
public void onError(Response<File> response) {
super.onError(response);
Toast.makeText(context, "下载错误", Toast.LENGTH_SHORT).show();
}
});
}
/**
* 安装apk
*/
private void installApk(File file) {
//新下载apk文件存储地址
File 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);//取消通知
}
/**
* 获取本地版本号
*
* @return
*/
public int getVersionCode() {
PackageManager packageManager = context.getPackageManager();
int versionCode = 0;
try {
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
versionCode = packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return versionCode;
}
}
Finally, I found that API>=24 is definitely not working with this method. For file:///storage/emulated/0/xxx, android N file access crash android.os.FileUriExposedException. If you want to go online, you will not repeat the introduction in many ways. Please see the introduction of the following bloggers.
https://blog.csdn.net/honjane/article/details/54411820
https://blog.csdn.net/ruancoder/article/details/67639621
https://blog.csdn.net/xiaoyu940601/article/details/54406725
Finally found for the file:///storage/emulated/0/xxx/... file. The path in our filepaths.xml must have the xxx path, so that the file can be found without error. I don't know too much. Anyway, the problem of error reporting is finally solved.