用前台服务实现下载更新自动安装(kotlin)

流程分析

  • 流程分析
  • MainActivity
  • BaseActivity
  • DownloadService
  • fileprovider
  • AndroidManifest.xml

流程分析

在这里插入图片描述

1.检查更新的页面
2.接受广播的页面(BaseActivity)每个activity都继承它,这样随时都可以弹出更新弹框
3.前台服务

注意:activity 和service用android studio自动生成否则自己往
AndroidManifest里面加内容。

MainActivity

package com.rengda.updateapplication

import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AlertDialog
import androidx.core.app.NotificationCompat

class MainActivity : BaseActivity() {

    val myPackageName="com.rengda.updateapplication" //包名
    val TAG="MainActivity"
    lateinit var context: Context
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        context=this
        getVersion()

    }


    //去服务器查询最新版本
    private fun getVersion(){
        var latestVersion=12;//虚假的得到 其实要去服务
        checkUpdate(latestVersion)
    }


    private  fun checkUpdate(latestVersion:Int){
        val version:Int= if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            packageManager.getPackageInfo(myPackageName, 0).longVersionCode.toInt()
        } else {
            packageManager.getPackageInfo(myPackageName, 0).versionCode
        }
      //  Log.d(TAG, "当前版本号:${version},最新版本号:${latestVersion}")
        //小于接口版本号 发送广播
        if (version

BaseActivity

package com.rengda.updateapplication

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.appcompat.app.AlertDialog

open class BaseActivity : AppCompatActivity() {
    val updateAction="com.renda.com" //广播的动作,根据这个来接受广播
    lateinit var receiver:UpdateReceiver
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_base)

        //广播接收器 注册
        val intentFilter= IntentFilter()
        intentFilter.addAction(updateAction)
        receiver=UpdateReceiver()
        registerReceiver(receiver,intentFilter)
    }
    //广播接收器
    inner class UpdateReceiver: BroadcastReceiver(){
        override fun onReceive(context: Context?, intent: Intent?) {
            showUpdateDialog()
        }
    }
    //显示更新下载框  点击确定进行下载  开启通知
    private fun showUpdateDialog(){
        AlertDialog.Builder(this).apply {
            setTitle("更新")
            setMessage("当前版本低于最新版本,请前往更新!")
            setCancelable(false)
            setPositiveButton("确定"){
                dialog, which ->
                val intent=Intent(context,DownloadService::class.java)
                startService(intent)
            }
            show()
        }
    }
    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(receiver)
    }

}

DownloadService

如果要自动安装涉及到fileprovider 这里就没详写

package com.rengda.updateapplication

import android.R.attr.path
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Binder
import android.os.Build
import android.os.Environment
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.content.FileProvider
import java.io.File
import java.io.FileOutputStream
import java.net.HttpURLConnection
import java.net.URL
import javax.net.ssl.HttpsURLConnection
import kotlin.concurrent.thread


class DownloadService : Service() {
    private lateinit var context:Context
    private var downloadFile:String=""
    override fun onBind(intent: Intent): IBinder {
        TODO("Return the communication channel to the service.")
    }
    override fun onCreate() {
        super.onCreate()
        context=this
        setForground()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        thread {
            doDownLoad("下载地址")//去下载
        }
        return super.onStartCommand(intent, flags, startId)
    }



    private  fun doDownLoad(url:String){
        var connection: HttpsURLConnection? = null
        val url = URL(url)
        connection = url.openConnection() as HttpsURLConnection
        connection.connectTimeout = 10000
        connection.readTimeout = 10000
        connection.requestMethod = "GET"
        val input = connection.inputStream
        val intcount=connection.getContentLength()//获取总长度
        var byteArray=ByteArray(1024)

        val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)

        val  file= File(storageDir?.absolutePath+"/仓储一体化.apk")
        if (file.exists()){
            file.delete()
        }else{
            file.createNewFile()
        }
        downloadFile=storageDir?.absolutePath+"/仓储一体化.apk"
        val fos = FileOutputStream(file)
        var downLoadSize=0;

        while (true){
            var numread=input.read(byteArray)
            if (numread==-1){
                break
            }else{
                fos.write(byteArray,0,numread)
                downLoadSize=downLoadSize+numread
                var process=((downLoadSize.toDouble()/intcount)*100).toInt()
                sendNotification("下载进度:${process}%")
            }
        }
        if (intcount==downLoadSize){
            sendSuccessNotification("下载成功!")
            doInstall()
        }else{
            sendNotification("下载失败!")
            if (file.exists()){
                file.delete()
            }
            stopSelf()
        }


    }



    //开启前台服务
    private fun setForground(){
        val manager=getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
        if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
            val channel=NotificationChannel("my_service","前台Service通知",NotificationManager.IMPORTANCE_DEFAULT)
            manager.createNotificationChannel(channel)
        }
        val notification=NotificationCompat.Builder(this,"my_service")
                .setContentTitle("开启下载")
                .setSmallIcon(R.mipmap.ic_launcher)
                .build()
        startForeground(1,notification)

    }

    private fun sendNotification(msg:String){
        val manager=getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
        if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
            val channel=NotificationChannel("my_service","前台Service通知",NotificationManager.IMPORTANCE_DEFAULT)
            manager.createNotificationChannel(channel)
        }
        val notification=NotificationCompat.Builder(this,"my_service")
                .setContentTitle("下载")
                .setContentText(msg)
                .setSmallIcon(R.mipmap.ic_launcher)
                .build()
        startForeground(2,notification)
    }




    //前台服务 这个可以进行点击跳转到安装页面
    private fun sendSuccessNotification(msg:String){
        val manager=getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager;
        if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
            val channel=NotificationChannel("my_service","前台Service通知",NotificationManager.IMPORTANCE_DEFAULT)
            manager.createNotificationChannel(channel)
        }
        val pi= PendingIntent.getActivity(context,0,getInstallIntent(),0)
        val notification=NotificationCompat.Builder(this,"my_service")
                .setContentTitle("下载")
                .setContentText(msg)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pi)
                .build()
        startForeground(3,notification)
    }


    private fun getInstallIntent():Intent{
        val intent = Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            //这里的authority是自己在AndroidManifest.xml定义的
            var apkUri = FileProvider.getUriForFile(context,"com.rengda.fileprovider",File(downloadFile))
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(File(downloadFile)), "application/vnd.android.package-archive");
        }
        return intent
    }

    private fun doInstall(){
        context.startActivity(getInstallIntent());
    }
}

fileprovider

file_paths.xml



    

AndroidManifest.xml

权限的声明,activity和service和fileprovider的声明。



    
    
    
    

    
        

        

        
            
                

                
            
        
        
            
        
    

你可能感兴趣的:(Kotlin,Android,kotlin,android)