184 lines
6.9 KiB
Kotlin
184 lines
6.9 KiB
Kotlin
package com.catlas.escapepenacony.data
|
|
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.net.Uri
|
|
import android.os.Build
|
|
import android.os.Environment
|
|
import android.provider.Settings
|
|
import androidx.core.content.FileProvider
|
|
import com.catlas.escapepenacony.BuildConfig
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.withContext
|
|
import org.json.JSONObject
|
|
import java.io.File
|
|
import java.io.FileOutputStream
|
|
import java.net.HttpURLConnection
|
|
import java.net.URL
|
|
|
|
data class ReleaseInfo(
|
|
val tagName: String,
|
|
val releaseTitle: String,
|
|
val changelog: String,
|
|
val apkDownloadUrl: String,
|
|
val isNewer: Boolean
|
|
)
|
|
|
|
object UpdateManager {
|
|
|
|
private const val GITHUB_RELEASES_API =
|
|
"https://api.github.com/repos/CAtlas0784/Escape-penacony/releases/latest"
|
|
|
|
private const val GITHUB_RAW_SCENES_URL =
|
|
"https://raw.githubusercontent.com/CAtlas0784/Escape-penacony/main/scenes.json"
|
|
|
|
suspend fun checkForAppUpdate(currentVersion: String = BuildConfig.VERSION_NAME): Result<ReleaseInfo?> =
|
|
withContext(Dispatchers.IO) {
|
|
try {
|
|
val url = URL(GITHUB_RELEASES_API)
|
|
val conn = url.openConnection() as HttpURLConnection
|
|
conn.connectTimeout = 8000
|
|
conn.readTimeout = 8000
|
|
conn.setRequestProperty("Accept", "application/vnd.github.v3+json")
|
|
conn.setRequestProperty("User-Agent", "Escape-Penacony-Android-App")
|
|
|
|
if (conn.responseCode == 200) {
|
|
val body = conn.inputStream.bufferedReader().use { it.readText() }
|
|
val json = JSONObject(body)
|
|
val tagName = json.getString("tag_name")
|
|
val title = json.optString("name", tagName)
|
|
val changelog = json.optString("body", "No changelog provided.")
|
|
|
|
var downloadUrl = ""
|
|
val assets = json.optJSONArray("assets")
|
|
if (assets != null) {
|
|
for (i in 0 until assets.length()) {
|
|
val asset = assets.getJSONObject(i)
|
|
val name = asset.optString("name", "")
|
|
if (name.endsWith(".apk", ignoreCase = true)) {
|
|
downloadUrl = asset.getString("browser_download_url")
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
val isNewer = isNewerVersion(currentVersion, tagName)
|
|
Result.success(
|
|
ReleaseInfo(
|
|
tagName = tagName,
|
|
releaseTitle = title,
|
|
changelog = changelog,
|
|
apkDownloadUrl = downloadUrl,
|
|
isNewer = isNewer
|
|
)
|
|
)
|
|
} else {
|
|
Result.success(null)
|
|
}
|
|
} catch (e: Exception) {
|
|
e.printStackTrace()
|
|
Result.failure(e)
|
|
}
|
|
}
|
|
|
|
suspend fun downloadApk(
|
|
context: Context,
|
|
downloadUrl: String,
|
|
onProgress: (Int) -> Unit
|
|
): Result<File> = withContext(Dispatchers.IO) {
|
|
try {
|
|
val url = URL(downloadUrl)
|
|
val conn = url.openConnection() as HttpURLConnection
|
|
conn.connectTimeout = 15000
|
|
conn.readTimeout = 15000
|
|
conn.setRequestProperty("User-Agent", "Escape-Penacony-Android-App")
|
|
|
|
val fileLength = conn.contentLength
|
|
val dir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) ?: context.filesDir
|
|
val apkFile = File(dir, "Escape-penacony-update.apk")
|
|
|
|
conn.inputStream.use { input ->
|
|
FileOutputStream(apkFile).use { output ->
|
|
val buffer = ByteArray(8 * 1024)
|
|
var total: Long = 0
|
|
var count: Int
|
|
while (input.read(buffer).also { count = it } != -1) {
|
|
total += count
|
|
if (fileLength > 0) {
|
|
val progress = ((total * 100) / fileLength).toInt()
|
|
withContext(Dispatchers.Main) {
|
|
onProgress(progress)
|
|
}
|
|
}
|
|
output.write(buffer, 0, count)
|
|
}
|
|
}
|
|
}
|
|
|
|
Result.success(apkFile)
|
|
} catch (e: Exception) {
|
|
e.printStackTrace()
|
|
Result.failure(e)
|
|
}
|
|
}
|
|
|
|
fun promptInstallApk(context: Context, apkFile: File) {
|
|
// Android 8.0+ Check Unknown App Sources permission
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
if (!context.packageManager.canRequestPackageInstalls()) {
|
|
val settingsIntent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
|
|
data = Uri.parse("package:${context.packageName}")
|
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
}
|
|
context.startActivity(settingsIntent)
|
|
return
|
|
}
|
|
}
|
|
|
|
val apkUri: Uri = FileProvider.getUriForFile(
|
|
context,
|
|
"${context.packageName}.fileprovider",
|
|
apkFile
|
|
)
|
|
|
|
val installIntent = Intent(Intent.ACTION_VIEW).apply {
|
|
setDataAndType(apkUri, "application/vnd.android.package-archive")
|
|
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
}
|
|
context.startActivity(installIntent)
|
|
}
|
|
|
|
suspend fun fetchLatestScenesJson(): Result<String> = withContext(Dispatchers.IO) {
|
|
try {
|
|
val url = URL(GITHUB_RAW_SCENES_URL)
|
|
val conn = url.openConnection() as HttpURLConnection
|
|
conn.connectTimeout = 8000
|
|
conn.readTimeout = 8000
|
|
conn.setRequestProperty("User-Agent", "Escape-Penacony-Android-App")
|
|
|
|
if (conn.responseCode == 200) {
|
|
val content = conn.inputStream.bufferedReader().use { it.readText() }
|
|
Result.success(content)
|
|
} else {
|
|
Result.failure(Exception("HTTP error ${conn.responseCode}"))
|
|
}
|
|
} catch (e: Exception) {
|
|
Result.failure(e)
|
|
}
|
|
}
|
|
|
|
private fun isNewerVersion(current: String, latest: String): Boolean {
|
|
val c = current.removePrefix("v").split(".").map { it.toIntOrNull() ?: 0 }
|
|
val l = latest.removePrefix("v").split(".").map { it.toIntOrNull() ?: 0 }
|
|
val maxLen = maxOf(c.size, l.size)
|
|
for (i in 0 until maxLen) {
|
|
val cv = c.getOrElse(i) { 0 }
|
|
val lv = l.getOrElse(i) { 0 }
|
|
if (lv > cv) return true
|
|
if (lv < cv) return false
|
|
}
|
|
return false
|
|
}
|
|
}
|