Files
ShiftRing/app/src/main/java/com/example/shiftalarm/AppUpdateManager.kt
sanjeok77 26fb793ab9 feat: v1.3.0 - versionCode 기반 업데이트 체크
- 버전 1.2.5 → 1.3.0 (versionCode 1130)
- AppUpdateManager: versionCode로 업데이트 비교
- versionName 비교 로직 제거
- 더 정확한 업데이트 감지

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-02-28 18:50:55 +09:00

172 lines
6.8 KiB
Kotlin

package com.example.shiftalarm
import android.app.Activity
import android.app.ProgressDialog
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
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) {
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) {
com.google.android.material.dialog.MaterialAlertDialogBuilder(activity)
.setTitle("새로운 업데이트 발견 (v$version)")
.setMessage("업데이트 내용:\n$changelog\n\n지금 다운로드하시겠습니까?")
.setPositiveButton("다운로드") { _, _ ->
downloadAndInstallApk(activity, apkUrl, version)
}
.setNegativeButton("나중에", null)
.show()
}
private fun downloadAndInstallApk(activity: Activity, apkUrl: String, version: String) {
val progressDialog = ProgressDialog(activity).apply {
setTitle("업데이트 다운로드 중")
setMessage("v$version 다운로드 중...")
setProgressStyle(ProgressDialog.STYLE_HORIZONTAL)
setCancelable(false)
max = 100
show()
}
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 {
progressDialog.progress = 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()
}
}
}