一、新建更新服务Service类
通知栏,对话框,吐司,换成自己的
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;
import java.io.File;
import java.util.Random;
/**
* createTime :2024/6/29 11:13
* createBy :lkl
*/
public class UpdateService extends Service {
private static Intent intentService;
public static void start(String version, String url) {
if (intentService != null) {
stop();
}
Context context = App.getContext();
intentService = new Intent(context, UpdateService.class);
intentService.putExtra("version", version);
intentService.putExtra("url", url);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intentService);
} else {
context.startService(intentService);
}
}
public static void stop() {
if (intentService == null) {
return;
}
Context context = App.getContext();
context.stopService(intentService);
intentService = null;
}
public static boolean isDownloading() {
return intentService != null;
}
public static void sendCancel() {
if (!isDownloading()) {
return;
}
Intent intent = new Intent(ACTION_CANCEL);
App.getContext().sendBroadcast(intent);
}
public static void sendChange() {
if (!isDownloading()) {
return;
}
Intent intent = new Intent(ACTION_CHANGE);
App.getContext().sendBroadcast(intent);
}
public static void sendSetUp() {
if (!isDownloading()) {
return;
}
Intent intent = new Intent(ACTION_SET_UP);
App.getContext().sendBroadcast(intent);
}
//取消
public static final String ACTION_CANCEL = "UpdateServiceCancel";
//更改(点击的动作,也就是PendIntent)
public static final String ACTION_CHANGE = "UpdateServiceChange";
//安装
public static final String ACTION_SET_UP = "UpdateServiceSetup";
public static int progress = 0;
private File apkFile;
private NotificationManager manager;
private int notifyId;
private Notification.Builder builder;
private BroadcastReceiver receiver;
private TipDialog tipDialog;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notifyId = new Random().nextInt(1000);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder = new Notification.Builder(this, NotifyUtils.minChannelId)
.setChannelId(NotifyUtils.minChannelId);
} else {
builder = new Notification.Builder(this);
}
//设置标题
builder.setContentTitle(App.instance.setAppName() + "正在下载更新")
//设置内容
.setContentText("下载中0%")
.setAutoCancel(false)
.setNumber(0)
//是否是进行中通知,如果是,用户将无法取消此通知
.setOngoing(true)
//设置创建时间
.setWhen(System.currentTimeMillis())
//设置状态栏图标
.setSmallIcon(R.mipmap.icon_move_up)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.app_icon))
.setContentIntent(getPendingIntent());
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
return;
}
switch (action) {
case ACTION_CANCEL:
if (tipDialog != null) {
tipDialog.dismiss();
}
tipDialog = TipDialog.create(App.instance.getTopActivity())
.title("是否取消更新?")
.setSureText("是")
.setCancelText("否")
.notOutSideClose()
.onClickListener(is -> {
if (is) {
UpdateService.stop();
MyToast.showToast("已取消更新");
}
});
tipDialog.show();
break;
case ACTION_CHANGE:
if (tipDialog != null) {
tipDialog.dismiss();
}
manager.notify(notifyId, builder
.setContentIntent(getPendingIntent())
.build());
break;
case ACTION_SET_UP:
BaseActivity<?> activity = (BaseActivity<?>) App.instance.getTopActivity();
activity.startActivity(createSetupIntent());
break;
}
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(UpdateService.ACTION_CANCEL);
filter.addAction(UpdateService.ACTION_CHANGE);
filter.addAction(UpdateService.ACTION_SET_UP);
registerReceiver(receiver, filter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(notifyId, builder.build());
manager.notify(notifyId, builder.build());
progress = 1;
String version = intent.getStringExtra("version");
String fileName = version + ".apk";
apkFile = new File(DirUtils.getDownLoadDir(), fileName);
String url = intent.getStringExtra("url");
DirUtils.downLoad(apkFile.getPath(), url, new DirUtils.OnDownLoadListener() {
@Override
public void onProgress(int p) {
LogUtils.i("下载中" + p + "," + DirUtils.fileSize(apkFile.length()));
manager.notify(notifyId, builder.setContentText("下载中" + p + "%").build());
progress = p;
MessageListener.callActionBack(Code.UPDATE, progress);
}
@Override
public void onFinish(File file) {
LogUtils.i("下载完成");
manager.notify(notifyId, builder
.setContentTitle(App.instance.setAppName() + "新版" + version + "已就绪")
.setContentText("如未自动安装,请点击这里开始安装")
.setContentIntent(getSetupIntent())
.build());
progress = 100;
MessageListener.callActionBack(Code.UPDATE, progress);
TipDialog.create(App.instance.getTopActivity())
.title("新版" + intent.getStringExtra("version") + "下载成功")
.content("是否立即安装更新")
.setSureText("立即安装")
.setCancelText("取消安装")
.notOutSideClose()
.onClickListener(is -> {
if (is) {
UpdateService.sendSetUp();
}
}).show();
}
@Override
public void onCancel() {
LogUtils.i("下载已取消");
manager.cancel(notifyId);
progress = 0;
MessageListener.callActionBack(Code.UPDATE, progress);
}
@Override
public void onError(String error) {
LogUtils.e("下载异常" + error);
manager.cancel(notifyId);
progress = 0;
MessageListener.callActionBack(Code.UPDATE, progress);
}
});
//“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
return START_NOT_STICKY;
}
private PendingIntent getPendingIntent() {
if (progress == 100) {
LogUtils.i("安装PendingIntent");
return getSetupIntent();
} else if (App.instance.isForeground()) {
LogUtils.i("取消下载PendingIntent");
return getCancelIntent();
} else {
LogUtils.i("主页PendingIntent");
return getMainIntent();
}
}
private PendingIntent getCancelIntent() {
Intent intent = new Intent(ACTION_CANCEL);
return PendingIntent.getBroadcast(this, 0, intent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
}
private PendingIntent getMainIntent() {
Class<?> mainClass;
try {
mainClass = Class.forName("com.test.android.MainActivity.class");
} catch (ClassNotFoundException e) {
return null;
}
Intent intent = new Intent(this, mainClass);
// //有activity就直接返回,没有就新建
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
return PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
}
private PendingIntent getSetupIntent() {
return PendingIntent.getActivity(this, 0, createSetupIntent(), PendingIntent.FLAG_IMMUTABLE);
}
private Intent createSetupIntent() {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra("showCancelTip", false);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(apkFile).toString());
String mimetype = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
//7.0以上需要
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri uri = FileProvider.getUriForFile(this, App.authority, apkFile);
intent.setDataAndType(uri, mimetype);
} else {
intent.setDataAndType(Uri.fromFile(apkFile), mimetype);
}
//有activity就直接返回,没有就新建
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
return intent;
}
@Override
public void onDestroy() {
super.onDestroy();
DirUtils.cancelDownload();
//文件不为空且未完成下载,就删除文件
if (apkFile != null && apkFile.exists() && progress != 100) {
LogUtils.i("apk文件删除:" + apkFile.delete());
}
if (receiver != null) {
unregisterReceiver(receiver);
}
if (tipDialog != null) {
tipDialog.dismiss();
tipDialog = null;
}
progress = 0;
MessageListener.callActionBack(Code.UPDATE, 0);
}
}
二、通过查到新版本后的操作,即准备更新的操作
if (data.isNeedUpdate()) {
TipDialog updateDialog;
Activity context = App.instance.getTopActivity();
if (data.foce == 1) {
updateDialog = TipDialog.createSingle(context).notClose();
} else {
updateDialog = TipDialog.create(context).notOutSideClose();
}
LincTextView tv = ViewBuilder.builder12(context).pad(SizeUtils.dp(10f))
createLincTextView();
tv.setHtml(data.description);
updateDialog.title("发现新版本v" + data.version).addView(tv)
.setSureText("立即更新")
.setCancelText("暂不更新")
.onClickListener(is -> {
if (is && !UpdateService.isDownloading()) {
UpdateService.start(data.version, data.url);
}
}).show();
//申请安装权限
String[] ps = new String[]{Manifest.permission.INSTALL_PACKAGES, Manifest.permission.REQUEST_INSTALL_PACKAGES};
checkPermission(ps,null);
} else if (showTip) {
toast("已是最新版本");
}
方法isNeedUpdate()
public boolean isNeedUpdate() {
//LogUtils.i("新版:" + version + ",当前版本:" + App.version);
return !TextUtils.isEmpty(version) && version.compareTo(App.version) > 0;
}
三、可选的优化
到这里,配置就已经完成了,但每次点击通知栏,都是会弹出“是否取消更新”的弹窗,我们希望回到桌面时,点击通知栏是打开程序,代码如下
逻辑解释如下:
1.在您的应用程序Application中定义好逻辑“程序是否进入在前台”,此标识用于区分点击通知栏的操作
2.应用前后台发生发变化时,会更改setContentIntent()内的值,发送不同的通知以达到上述效果
@Override
public void onActivityStarted(@NonNull Activity activity) {
super.onActivityStarted(activity);
if (!isForeground()) {
UpdateService.sendChange();
}
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
super.onActivityStopped(activity);
if (!isForeground()) {
UpdateService.sendChange();
}
}
网友评论