前言:最近公司项目版本需要把以前的版本更新代码更新一下,换成Service和前台通知栏形式的,所以在此记录一下。
目次
1.检测版本更新(省略)
2.创建Service开启前台通知栏,而且执行下载任务,将下载进度通知到通知栏,下载完成后举行安装
完整的Service代码
Service所用到的变量增补
2.开启一个透明InstallApkActivity执行安装Apk操纵
Activity代码
工具类代码
3.注意事项:因为24版本之后读取文件需要设置FileProvider,否则无法读取到apk文件
在res目次下建一个xml文件夹,然后创建file_path.xml文件
AndroidManifest.xml设置
OnlineFileProvider类代码
1.检测版本更新(省略)
这一步一般是通过背景接口对比当前APP版本是否低于服务器版本,从而获取最新版本的下载链接。这一步比力简单所以省略了。
2.创建Service开启前台通知栏,而且执行下载任务,将下载进度通知到通知栏,下载完成后举行安装
完整的Service代码
- package com.qtz.online.service;import android.app.Notification;import android.app.NotificationChannel;import android.app.NotificationManager;import android.app.Service;import android.content.Context;import android.content.Intent;import android.os.Build;import android.os.IBinder;import androidx.annotation.Nullable;import androidx.core.app.NotificationCompat;import com.qtz.online.R;import com.qtz.online.common.AppService;import com.qtz.online.event_bus.DownloadApkMessage;import com.qtz.online.mvp.activitys.InstallApkActivity;import com.qtz.online.network.callback.ServiceDownloadObserver;import com.qtz.online.network.client.DownLoadClient;import com.qtz.online.utils.LogUtil;import org.greenrobot.eventbus.EventBus;import io.reactivex.Observable;import io.reactivex.android.schedulers.AndroidSchedulers;import io.reactivex.schedulers.Schedulers;import okhttp3.ResponseBody;/** * @author Created by PengGuiChu on 2020/12/19 19:32. * @explain 版本更新服务 */public class DownloadApkService extends Service { private static final String TAG=DownloadApkService.class.getSimpleName(); private String url;//下载 private String fileDir; private String fileName; private NotificationManager notificationManager; private NotificationCompat.Builder notificationBuilder; private static final String name="download_apk"; private static final String id="Download_APK"; private static final int startForegroundId=777; private int downLoadProgress; @Override public void onCreate() { super.onCreate(); notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationBuilder = getNotificationBuilder(notificationManager,getString(R.string.version_upgrade),getString(R.string.downloading,"0%")); notificationBuilder.setProgress(100,0,false); startForeground(startForegroundId,notificationBuilder.build());// notificationManager.notify(2,notificationBuilder.build()); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent!=null){ url=intent.getStringExtra("url"); fileDir=intent.getStringExtra("fileDir"); fileName=intent.getStringExtra("fileName"); //该下载请求是我项目的下载请求,需要替换成你项目的下载文件的请求 downloadFile(DownLoadClient.getService(AppService.class).download(url), new ServiceDownloadObserver(fileDir,fileName) { @Override public void onDownloadStart() { } @Override public void onDownloading(long progress, long total) { int down= (int) (progress*100/total); if (down!=downLoadProgress){ downLoadProgress=down; if (notificationBuilder!=null){ notificationBuilder.setContentText(getString(R.string.downloading,downLoadProgress+"%")); notificationBuilder.setProgress(100, downLoadProgress,false); } if (notificationManager!=null){ notificationManager.notify(startForegroundId,notificationBuilder.build()); } } } @Override public void onDownloadSuccess(ResponseBody responseBody, String filePath) { LogUtil.d(TAG,"下载完成,开启一个空缺Activity执行安装窗口,包管用户在任何地方都能开启安装步调");// EventBus.getDefault().post(new DownloadApkMessage(0,filePath)); Intent intent=new Intent(getApplicationContext(), InstallApkActivity.class); intent.putExtra("filePath",filePath); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); stopForeground(true); stopSelf(); } @Override public void onDownloadError(String msg) { LogUtil.d(TAG,"下载堕落"); EventBus.getDefault().post(new DownloadApkMessage(1,msg)); stopForeground(true); stopSelf(); } }); } return super.onStartCommand(intent, flags, startId); } private NotificationCompat.Builder getNotificationBuilder(NotificationManager notificationManager, String title, String message) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(DownloadApkService.id, DownloadApkService.name, NotificationManager.IMPORTANCE_LOW); //闪光灯 channel.enableLights(false); //是否允许震动 channel.enableVibration(false); //设置可绕过 请勿打搅模式 channel.setBypassDnd(false); channel.setSound(null,null); notificationManager.createNotificationChannel(channel); } NotificationCompat.Builder notification = new NotificationCompat.Builder(this, DownloadApkService.id); notification.build().flags= Notification.FLAG_ONGOING_EVENT; notification.setContentTitle(title); notification.setDefaults(NotificationCompat.DEFAULT_VIBRATE); notification.setContentText(message); notification.setSmallIcon(R.mipmap.ic_launcher); notification.setAutoCancel(false); notification.setCategory(Notification.CATEGORY_PROGRESS); return notification; } protected void downloadFile(Observable downloadObservable, final ServiceDownloadObserver downloadObserver) { downloadObservable.subscribeOn(Schedulers.io())//请求网络 在调理者的io线程 .observeOn(Schedulers.io()) //指定线程生存文件 .doOnNext(downloadObserver::saveFile) .observeOn(AndroidSchedulers.mainThread()) //在主线程中更新ui .subscribe(downloadObserver); }}
复制代码 Service所用到的变量增补
2.开启一个透明InstallApkActivity执行安装Apk操纵
Activity代码
- package com.qtz.online.mvp.activitys;import android.content.Intent;import android.content.pm.PackageManager;import android.os.Bundle;import androidx.annotation.NonNull;import androidx.annotation.Nullable;import androidx.appcompat.app.AppCompatActivity;import com.qtz.online.R;import com.qtz.online.utils.InstallApkUtil;import java.io.File;public class InstallApkActivity extends AppCompatActivity { private InstallApkUtil installApkUtil; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_install_apk); String filePath = getIntent().getStringExtra("filePath"); initInstallApkUtil(new File(filePath)); } private void initInstallApkUtil(File file) { if (installApkUtil == null) { installApkUtil = new InstallApkUtil(InstallApkActivity.this, file.getAbsolutePath()); } installApkUtil.installApk(); } //更具用户授权回调执行安装操纵 @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 101) { if (installApkUtil != null) { installApkUtil.installApk(); } }else if (requestCode==102){ finish(); } }}
复制代码 工具类代码
- package com.qtz.online.utils;import android.app.AlertDialog;import android.content.Context;import android.content.Intent;import android.net.Uri;import android.os.Build;import android.provider.Settings;import androidx.appcompat.app.AppCompatActivity;import androidx.core.content.FileProvider;import com.qtz.online.BuildConfig;import com.qtz.online.base.BaseActivity;import com.qtz.online.view.ChoiceDialog;import org.greenrobot.eventbus.EventBus;import java.io.File;/** * @author Created by PengGuiChu on 2020/12/19 15:53. * @explain */public class InstallApkUtil { private AppCompatActivity baseActivity; private String apkPath; private ChoiceDialog choiceDialog; public InstallApkUtil(AppCompatActivity baseActivity, String apkPath) { this.baseActivity = baseActivity; this.apkPath=apkPath; } public void installApk() { if (Build.VERSION.SDK_INT >= 26) { //来判定应用是否有权限安装apk boolean installAllowed = baseActivity.getPackageManager().canRequestPackageInstalls(); //有权限 if (installAllowed) { //安装apk install(); } else {//这里弹出一个选择对话框,提示用户需要授权第三方安装应用,需要自己实现 if (choiceDialog==null){ choiceDialog = new ChoiceDialog(baseActivity, new ChoiceDialog.ClauseDialogCallBack() { @Override public void onExit() { baseActivity.finish(); } @Override public void onAgree() { Uri packageURI = Uri.parse("package:" + baseActivity.getPackageName()); Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI); baseActivity.startActivityForResult(intent, 101); } }, "安装应用需要打开未知泉源权限,请去设置中开启权限", "权限申请", "取消", "前往"); } choiceDialog.show(); } } else { install(); } } public void install() { if (Build.VERSION.SDK_INT >= 24) { Uri apkUri = FileProvider.getUriForFile(baseActivity, BuildConfig.APPLICATION_ID + ".myprovider", new File(apkPath)); Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive"); baseActivity.startActivityForResult(installIntent,102); } else { Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(Uri.parse("file://" + apkPath), "application/vnd.android.package-archive"); baseActivity.startActivityForResult(intent,102); } }}
复制代码 3.注意事项:因为24版本之后读取文件需要设置FileProvider,否则无法读取到apk文件
在res目次下建一个xml文件夹,然后创建file_path.xml文件
因为我是把apk下载在了Android/Data/包名/cache/apk目次下所以这样设置,这里需要根据你的详细情况举行设置
- 代表设备的根目次new File("/");
- 代表context.getFilesDir()
- 代表context.getCacheDir()
- 代表Environment.getExternalStorageDirectory()
- 代表context.getExternalFilesDirs()
- 代表getExternalCacheDirs()
AndroidManifest.xml设置
OnlineFileProvider类代码
- package com.qtz.online.utils;import androidx.core.content.FileProvider;/** * @author Created by PengGuiChu on 2020/12/19 16:39. * @explain */public class OnlineFileProvider extends FileProvider {}
复制代码
来源:https://blog.csdn.net/pengguichu/article/details/112022040
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |