Initial commit - v1.1.9

This commit is contained in:
2026-02-22 12:03:04 +09:00
commit 27339dc7b7
180 changed files with 12908 additions and 0 deletions

View File

@@ -0,0 +1,187 @@
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 serverVersionName = json.getString("versionName")
val apkUrl = json.getString("apkUrl")
val changelog = json.optString("changelog", "버그 수정 및 성능 향상")
val pInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0)
val currentVersionName = pInfo.versionName ?: "0.0.0"
if (isNewerVersion(serverVersionName, currentVersionName)) {
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 isNewerVersion(server: String, current: String): Boolean {
try {
// Clean version strings (remove non-numeric suffixes if any)
val sClean = server.split("-")[0].split(" ")[0]
val cClean = current.split("-")[0].split(" ")[0]
val sParts = sClean.split(".").map { it.filter { char -> char.isDigit() }.let { p -> if (p.isEmpty()) 0 else p.toInt() } }
val cParts = cClean.split(".").map { it.filter { char -> char.isDigit() }.let { p -> if (p.isEmpty()) 0 else p.toInt() } }
val length = Math.max(sParts.size, cParts.size)
for (i in 0 until length) {
val s = if (i < sParts.size) sParts[i] else 0
val c = if (i < cParts.size) cParts[i] else 0
if (s > c) return true
if (s < c) return false
}
} catch (e: Exception) {
android.util.Log.e("AppUpdateManager", "Version comparison failed: ${e.message}")
return false
}
return false
}
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()
}
}
}