Files
ShiftRing/app/src/main/java/com/example/shiftalarm/AppUpdateManager.kt
T

216 lines
8.5 KiB
Kotlin

package com.example.shiftalarm
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.view.LayoutInflater
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.FileProvider
import org.json.JSONObject
import java.io.BufferedInputStream
import java.io.File
import java.io.FileOutputStream
import java.net.HttpURLConnection
import java.net.URL
object AppUpdateManager {
private const val VERSION_URL = "https://git.webpluss.net/sanjeok77/ShiftRing/raw/branch/main/version.json"
fun checkUpdate(activity: Activity, silent: Boolean = false) {
val ctx = activity.applicationContext
val versionCheckUrl = "$VERSION_URL?t=${System.currentTimeMillis()}"
Thread {
try {
val url = URL(versionCheckUrl)
val connection = url.openConnection() as HttpURLConnection
connection.connectTimeout = 5000
connection.readTimeout = 5000
connection.requestMethod = "GET"
connection.useCaches = false
if (connection.responseCode == 200) {
val reader = connection.inputStream.bufferedReader()
val result = reader.readText()
reader.close()
val json = JSONObject(result)
val serverVersionCode = json.getInt("versionCode")
val serverVersionName = json.getString("versionName")
val apkUrl = json.getString("apkUrl")
val changelog = json.optString("changelog", "버그 수정 및 성능 향상")
val pInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0)
val currentVersionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
pInfo.longVersionCode.toInt()
} else {
@Suppress("DEPRECATION")
pInfo.versionCode
}
val currentVersionName = pInfo.versionName ?: "0.0.0"
if (serverVersionCode > currentVersionCode) {
activity.runOnUiThread {
showUpdateDialog(activity, serverVersionName, changelog, apkUrl)
}
} else if (!silent && serverVersionCode == currentVersionCode) {
activity.runOnUiThread {
Toast.makeText(ctx, "현재 최신 버전을 사용 중입니다. ($currentVersionName)", Toast.LENGTH_SHORT).show()
}
}
} else if (!silent) {
activity.runOnUiThread {
Toast.makeText(ctx, "서버 연결 실패", Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
e.printStackTrace()
if (!silent) {
activity.runOnUiThread {
Toast.makeText(ctx, "업데이트 확인 중 오류 발생", Toast.LENGTH_SHORT).show()
}
}
}
}.start()
}
private fun showUpdateDialog(activity: Activity, version: String, changelog: String, apkUrl: String) {
if (activity.isFinishing || activity.isDestroyed) return
val view = LayoutInflater.from(activity).inflate(R.layout.dialog_app_update_oneui, null)
val tvVersion = view.findViewById<TextView>(R.id.tvUpdateVersion)
val tvChangelog = view.findViewById<TextView>(R.id.tvChangelog)
val btnLater = view.findViewById<Button>(R.id.btnUpdateLater)
val btnNow = view.findViewById<Button>(R.id.btnUpdateNow)
tvVersion.text = "Version $version"
tvChangelog.text = changelog
val dialog = AlertDialog.Builder(activity)
.setView(view)
.setCancelable(true)
.create()
dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
btnLater.setOnClickListener {
dialog.dismiss()
}
btnNow.setOnClickListener {
dialog.dismiss()
downloadAndInstallApk(activity, apkUrl, version)
}
dialog.show()
val width = (activity.resources.displayMetrics.widthPixels * 0.88).toInt()
dialog.window?.setLayout(width, android.view.ViewGroup.LayoutParams.WRAP_CONTENT)
}
private fun downloadAndInstallApk(activity: Activity, apkUrl: String, version: String) {
if (activity.isFinishing || activity.isDestroyed) return
val view = LayoutInflater.from(activity).inflate(R.layout.dialog_update_progress_oneui, null)
val tvSub = view.findViewById<TextView>(R.id.tvProgressSub)
val progressBar = view.findViewById<ProgressBar>(R.id.downloadProgressBar)
val tvPercent = view.findViewById<TextView>(R.id.tvProgressPercent)
tvSub.text = "v$version 다운로드 중..."
val progressDialog = AlertDialog.Builder(activity)
.setView(view)
.setCancelable(false)
.create()
progressDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
progressDialog.show()
val width = (activity.resources.displayMetrics.widthPixels * 0.88).toInt()
progressDialog.window?.setLayout(width, android.view.ViewGroup.LayoutParams.WRAP_CONTENT)
Thread {
try {
val url = URL(apkUrl)
val connection = url.openConnection() as HttpURLConnection
connection.connectTimeout = 15000
connection.readTimeout = 15000
connection.requestMethod = "GET"
connection.connect()
val fileLength = connection.contentLength
val inputStream = BufferedInputStream(connection.inputStream)
val apkFile = File(activity.cacheDir, "update.apk")
val outputStream = FileOutputStream(apkFile)
val buffer = ByteArray(8192)
var total: Long = 0
var count: Int
while (inputStream.read(buffer).also { count = it } != -1) {
total += count
outputStream.write(buffer, 0, count)
if (fileLength > 0) {
val progress = (total * 100 / fileLength).toInt()
activity.runOnUiThread {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
progressBar.setProgress(progress, true)
} else {
progressBar.progress = progress
}
tvPercent.text = "$progress%"
}
}
}
outputStream.flush()
outputStream.close()
inputStream.close()
connection.disconnect()
activity.runOnUiThread {
progressDialog.dismiss()
installApk(activity, apkFile)
}
} catch (e: Exception) {
e.printStackTrace()
activity.runOnUiThread {
progressDialog.dismiss()
Toast.makeText(activity, "다운로드 실패: ${e.message}", Toast.LENGTH_LONG).show()
}
}
}.start()
}
private fun installApk(activity: Activity, apkFile: File) {
try {
val apkUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
FileProvider.getUriForFile(activity, "${activity.packageName}.provider", apkFile)
} else {
Uri.fromFile(apkFile)
}
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
}
activity.startActivity(intent)
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(activity, "설치 실패: ${e.message}", Toast.LENGTH_LONG).show()
}
}
}