1、去除https限制,因为服务器没有配置证书,所以要去掉限制,不需要的可以去除逻辑
2、做了MD5文件验证
3、适配绝大多数Android版本
4、注意filepath生成和provider地址就好了
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Environment
import androidx.core.content.FileProvider
import com.factory.machine.MyApp
import okhttp3.*
import okio.*
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.math.BigInteger
import java.security.MessageDigest
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.*
object DownloadUtil {
private val manager = object : X509TrustManager {
@Throws(CertificateException::class)
override fun checkClientTrusted(
x509Certificates: Array<X509Certificate?>?,
s: String?
) {
}
@Throws(CertificateException::class)
override fun checkServerTrusted(
x509Certificates: Array<X509Certificate?>?,
s: String?
) {
}
override fun getAcceptedIssuers(): Array<X509Certificate?> = arrayOfNulls(0)
}
private fun createSSLSocketFactory(): SSLSocketFactory? {
var sSLSocketFactory: SSLSocketFactory? = null
try {
val sc: SSLContext = SSLContext.getInstance("TLS")
sc.init(null, arrayOf<TrustManager>(manager), SecureRandom())
sSLSocketFactory = sc.socketFactory
} catch (e: Exception) {
e.printStackTrace()
}
return sSLSocketFactory
}
fun startDown(context: Context, url: String, fileMD5:String, calllback: (Int) -> Unit) {
val factory = createSSLSocketFactory()
factory?.let {
val client = OkHttpClient.Builder().run {
sslSocketFactory(it, manager)
.hostnameVerifier { _, _ -> true }
}.build()
val request = Request.Builder()
.url(url)
.addHeader("Connection", "close") //这里不设置可能产生EOF错误
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
e.printStackTrace()
}
override fun onResponse(call: Call, response: Response) {
response.body?.let { body ->
val digest = MessageDigest.getInstance("MD5")
digest?.let {
var bs: BufferedSource? = null
var out: BufferedSink? = null
try {
var sum: Long = 0
val byteLength = 4096
val buf = ByteArray(byteLength)
val total = body.contentLength()
var len: Int
bs = body.byteStream().source().buffer()
val filePath =
"${MyApp.context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)}/${System.currentTimeMillis()}.apk"
val file =
File(filePath)
out = file.sink().buffer()
var oldProcess = 0
var process = 0
while (bs.read(buf).also { len = it } != -1) {
out.write(buf, 0, len)
digest.update(buf, 0, len)
sum += len.toLong()
process = (sum * 100 / total.toFloat()).toInt()
if (process - oldProcess > 0) {
calllback(process)
}
oldProcess = process
}
out.flush()
val bigInt = BigInteger(1, digest.digest())
var md5 = bigInt.toString(16)
if(md5.length == 31){
md5 = "0$md5"
}
if(md5 == fileMD5){
installApk(context, filePath)
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
try {
bs?.close()
} catch (e: Exception) {
e.printStackTrace()
}
try {
out?.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
}
})
}
}
fun installApk(context: Context, downloadApk: String) {
val intent = Intent(Intent.ACTION_VIEW)
val file = File(downloadApk)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val apkUri: Uri = FileProvider.getUriForFile(
context,
"com.factory.machine.provider",
file
)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
} else {
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
val uri: Uri = Uri.fromFile(file)
intent.setDataAndType(uri, "application/vnd.android.package-archive")
}
context.startActivity(intent)
}
}