Android app線上下載更新
專案之前更新這塊用的是DownloadManager,DownloadManager是系統開放給第三方應用使用的類,包含兩個靜態內部類DownloadManager.Query和DownloadManager.Request。DownloadManager.Request用來請求一個下載,DownloadManager.Query用來查詢下載資訊。
簡單介紹一下之前做的邏輯:
-
啟動檢查是否有最新版本。通過介面上傳當前app版本號,由伺服器判斷是否有最新的版本,有則下發。
-
如果有最新的版本,對話方塊形式提示使用者更新app,選擇立即更新則優先判斷之前是否已經下載過最新的apk,若存在,則直接跳轉到安裝介面;如果不存在,則開啟下載任務;使用者若忽略更新不作處理,下次進入再次提醒
-
下載成功自動跳轉至安裝頁面,下載失敗提示錯誤資訊
關於DownloadManager的使用網上一搜一大把,這裡就不做分析介紹了。
本文基於Service + HttpURLConnection + Receiver的思路進行app線上下載更新的介紹。
app的更新下載適合在service中進行,而下載屬於耗時任務,需要在子執行緒中進行處理,這時IntentService便是最好的選擇,已經幫你做好了執行緒間的排程,重寫onHandleIntent(intent: Intent?)
方法,該方法便執行在子執行緒而非主執行緒。
在onHandleIntent
方法中執行下載任務
override fun onHandleIntent(intent: Intent?) { intent?.let { val savePath = intent.getStringExtra("savePath") val srcUrl = intent.getStringExtra("srcUrl") mType = intent.getStringExtra("type") isShowNotify = intent.getBooleanExtra("isShowProgress", false) //傳入儲存的父目錄,下載地址,進行下載處理 val file = downloadFile(savePath, srcUrl) file?.let { //下載完成後檔案重新命名,去除字尾.tmp val fileName = it.name val prefix = fileName.substring(fileName.lastIndexOf(".") + 1) val newFile: File? newFile = if ("tmp" == prefix) { renameFile(it.absolutePath, it.absolutePath.substring(0, it.absolutePath.lastIndexOf("."))) } else { it } //向主執行緒傳送下載成功的資訊 newFile?.let { val msg = Message.obtain() msg.what = DOWNLOAD_COMPLETE msg.obj = newFile handler.sendMessage(msg) } } } }
看看方法downloadFile
做了哪些處理
private fun downloadFile(savePath: String, srcUrl: String): File? { var input: InputStream? = null var fos: FileOutputStream? = null var file: File? = null try { //判讀本地是否已經存在下載過的 if (isFileExist(savePath, srcUrl)) { val fileDir = getFilePath(savePath, srcUrl) return File(fileDir) } else { //如果檔案不存在,則刪除當前目錄下臨時的.tmp檔案後再進行下載,檔案字尾新增.tmp val fileDir = getFilePath(savePath, "$srcUrl.tmp") file = File(fileDir) if (file.exists()) { file.delete() } if (!file.createNewFile()) { return null } } val url = URL(srcUrl) val conn = url.openConnection() input = conn.getInputStream() fos = FileOutputStream(file) val buf = ByteArray(1024) var len = 0 var total = 0 val fileSize = conn.contentLength var progress = 0 //下載進度資訊 val mRun: Runnable = object : Runnable { override fun run() { val msg = Message.obtain() msg.what = DOWNLOAD_PROGRESS msg.obj = progress handler.sendMessage(msg) handler.postDelayed(this, 500) if (progress == 100) { handler.removeCallbacks(this) } } } handler.postDelayed(mRun, 0) val msg = Message.obtain() msg.what = DOWNLOAD_PREPARE handler.sendMessage(msg) while (input.read(buf).let { len = it;it != -1 }) { fos.write(buf, 0, len) total += len progress = (total * 1.0 / fileSize * 100).toInt() } return file } catch (e: Exception) { e.printStackTrace() val msg = Message.obtain() msg.what = DOWNLOAD_FAIL handler.sendMessage(msg) if (file != null && file.exists()) { file.delete() } } finally { Utils.close(input) Utils.close(fos) } return null }
先到這,以後再補充