基类代码
在ViewModel中使用协程需要引入
//viewModel协程
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-rc02'
在ViewModel调用版本更新检测的方法
class MainViewModel : ViewModel() {
val apkUrl = MutableLiveData<String>()
init {
versionUpdateDetection()
}
/**
* 版本更新检测
*/
fun versionUpdateDetection(){
viewModelScope.launch(Dispatchers.IO) {
queryVersion()?.let{
launch(Dispatchers.Main) {
apkUrl.value = it
}
}
}
}
/**
* 查询是否是最新版本,不是则返回apk地址
*/
private suspend fun queryVersion():String?{
//模拟网络请求
delay(500L)
return "https://raw.githubusercontent.com/xuexiangjys/XUpdate/master/apk/xupdate_demo_1.0.2.apk"
}
}
在Activity中观察apkUrl,有变化则弹出更新提示
viewModel.apkUrl.observe(this, Observer {
showInstallationDialog(it,PERMISSION_REQUEST_CODE)
})
更新提示
/**
* 安装apk Dialog
*/
fun showInstallationDialog(url: String,requestCode: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (packageManager.canRequestPackageInstalls()) {
showDialogN(url)
} else {
val builder = AlertDialog.Builder(this)
builder.setTitle("检测到新版本")
.setMessage("安装新版本需要打开未知来源权限,请去设置中开启权限")
.setPositiveButton("设置") { _, _ ->
val selfPackageUri = Uri.parse("package:$packageName")
val intentPermission =
Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, selfPackageUri)
//8.0以上跳转至“安装未知应用”权限界面,引导用户开启权限
startActivityForResult(intentPermission, requestCode)
}
.setNegativeButton("取消") { _, _ -> }
.setCancelable(false)
.show()
}
} else {
showDialogN(url)
}
}
/**
* 7.0以下新版本提示
*/
private fun showDialogN(url:String) {
val builder = AlertDialog.Builder(this)
builder.setTitle("提示")
.setMessage("检测到新版本是否更新")
.setPositiveButton("更新") { _, _ -> apkUpdate(url) }
.setNegativeButton("取消") { _, _ -> }
.setCancelable(false)
.show()
}
/**
* 下载apk
*/
private fun apkUpdate(url: String) {
val request = DownloadManager.Request(Uri.parse(url))
//设置什么网络情况下可以下载
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE or DownloadManager.Request.NETWORK_WIFI)
//设置漫游状态下是否可以下载,默认true
request.setAllowedOverRoaming(true)
//设置通知栏的标题
request.setTitle("下载")
//设置通知栏的message
request.setDescription("正在进行版本更新.....")
//是否在通知栏显示下载进度,默认显示
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
//设置文件存放目录
request.setDestinationInExternalFilesDir(
application,
Environment.DIRECTORY_DOWNLOADS,
apkName
)
//获取系统服务
downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
//进行下载
downloadManager?.let {
apkId = it.enqueue(request)
}
}
8.0以上的手机安装需要授权,在onActivityResult中查看授权状态
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PERMISSION_REQUEST_CODE){
viewModel.apkUrl.value?.let {
showInstallationDialog(it,PERMISSION_REQUEST_CODE)
}
}
}
下载完成后系统会发送DownloadManager.ACTION_DOWNLOAD_COMPLETE广播
registerExternalReceiver(receive,DownloadManager.ACTION_DOWNLOAD_COMPLETE)
在注册的广播中调用安装apk的程序
private val receive = object :BroadcastReceiver(){
override fun onReceive(context: Context?, intent: Intent?) {
intent?.let {
if (it.action == DownloadManager.ACTION_DOWNLOAD_COMPLETE){
val id = it.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
installation()
}
}
}
}
provider
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
file_paths
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path name="external" path="" />
</paths>
</resources>