基類代碼
在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>