MVVM之DownLoadManager更新apk

基類代碼

BaseMVVMActivity

在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>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章