diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a87c9cc..7be8dc2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -24,8 +24,8 @@ android { applicationId = "com.hotdeal.alarm" minSdk = 31 targetSdk = 35 - versionCode = 20 - versionName = "1.11.3" + versionCode = 21 + versionName = "1.11.4" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/java/com/hotdeal/alarm/presentation/main/MainActivity.kt b/app/src/main/java/com/hotdeal/alarm/presentation/main/MainActivity.kt index 685537b..b006ce3 100644 --- a/app/src/main/java/com/hotdeal/alarm/presentation/main/MainActivity.kt +++ b/app/src/main/java/com/hotdeal/alarm/presentation/main/MainActivity.kt @@ -172,10 +172,7 @@ class MainActivity : ComponentActivity() { override fun onDestroy() { super.onDestroy() - // 리시버 해제 - downloadReceiver?.let { - ApkDownloadManager.unregisterDownloadCompleteReceiver(this, it) - } + ApkDownloadManager.unregisterDownloadCompleteReceiver(this) } // 비저빌리티 콜백 - 백그라운드에서 포어그라운드 전환 시 새로고침 diff --git a/app/src/main/java/com/hotdeal/alarm/presentation/settings/SettingsScreen.kt b/app/src/main/java/com/hotdeal/alarm/presentation/settings/SettingsScreen.kt index 3c8f3dc..01b543b 100644 --- a/app/src/main/java/com/hotdeal/alarm/presentation/settings/SettingsScreen.kt +++ b/app/src/main/java/com/hotdeal/alarm/presentation/settings/SettingsScreen.kt @@ -477,22 +477,20 @@ private fun MoreTab(viewModel: MainViewModel) { } } -private fun downloadAndInstallApk(context: Context, updateInfo: com.hotdeal.alarm.util.UpdateInfo) { - // ApkDownloadManager를 사용하여 다운로드 시작 및 자동 설치 - val downloadId = ApkDownloadManager.downloadApk(context, updateInfo) - - // 다운로드 완료 리시버 등록 - 완료 시 자동 설치 - ApkDownloadManager.registerDownloadCompleteReceiver( - context = context, - downloadId = downloadId, - onComplete = { - ApkDownloadManager.installApk(context) - }, - onFailed = { - Toast.makeText(context, "다운로드 실패. 다시 시도해주세요.", Toast.LENGTH_SHORT).show() - } - ) -} + private fun downloadAndInstallApk(context: Context, updateInfo: com.hotdeal.alarm.util.UpdateInfo) { + val downloadId = ApkDownloadManager.downloadApk(context, updateInfo) + + ApkDownloadManager.registerDownloadCompleteReceiver( + context = context, + downloadId = downloadId, + onComplete = { + ApkDownloadManager.installApk(context) + }, + onFailed = { + Toast.makeText(context, "다운로드 실패. 다시 시도해주세요.", Toast.LENGTH_SHORT).show() + } + ) + } // ==================== 공통 컴포넌트 ==================== diff --git a/app/src/main/java/com/hotdeal/alarm/util/ApkDownloadManager.kt b/app/src/main/java/com/hotdeal/alarm/util/ApkDownloadManager.kt index 6b1ed56..3c18541 100644 --- a/app/src/main/java/com/hotdeal/alarm/util/ApkDownloadManager.kt +++ b/app/src/main/java/com/hotdeal/alarm/util/ApkDownloadManager.kt @@ -6,7 +6,9 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.net.Uri +import android.os.Build import android.os.Environment +import android.util.Log import android.widget.Toast import androidx.core.content.FileProvider import kotlinx.coroutines.Dispatchers @@ -19,8 +21,12 @@ import java.io.File */ object ApkDownloadManager { + private const val TAG = "ApkDownloadManager" private const val APK_FILE_NAME = "hotdeal-alarm-update.apk" + // 등록된 리시버 추적 (메모리 누수 방지) + private var registeredReceiver: BroadcastReceiver? = null + /** * APK 다운로드 시작 */ @@ -65,6 +71,9 @@ object ApkDownloadManager { onComplete: () -> Unit, onFailed: () -> Unit ): BroadcastReceiver { + // 기존 리시버가 있으면 먼저 해제 + unregisterDownloadCompleteReceiver(context) + val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) ?: -1 @@ -72,15 +81,25 @@ object ApkDownloadManager { val downloadManager = context?.getSystemService(Context.DOWNLOAD_SERVICE) as? DownloadManager val query = DownloadManager.Query().setFilterById(downloadId) val cursor = downloadManager?.query(query) - + cursor?.use { if (it.moveToFirst()) { val statusIndex = it.getColumnIndex(DownloadManager.COLUMN_STATUS) val status = it.getInt(statusIndex) - + when (status) { - DownloadManager.STATUS_SUCCESSFUL -> onComplete() - DownloadManager.STATUS_FAILED -> onFailed() + DownloadManager.STATUS_SUCCESSFUL -> { + Log.d(TAG, "다운로드 완료, 설치 시작") + onComplete() + // 설치 후 리시버 해제 + unregisterDownloadCompleteReceiver(context) + } + DownloadManager.STATUS_FAILED -> { + Log.e(TAG, "다운로드 실패") + onFailed() + // 실패 시 리시버 해제 + unregisterDownloadCompleteReceiver(context) + } } } } @@ -88,10 +107,22 @@ object ApkDownloadManager { } } - context.registerReceiver( - receiver, - IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) - ) + // Android 12+ 에서는 RECEIVER_NOT_EXPORTED 플래그 필요 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + context.registerReceiver( + receiver, + IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), + Context.RECEIVER_NOT_EXPORTED + ) + } else { + context.registerReceiver( + receiver, + IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) + ) + } + + registeredReceiver = receiver + Log.d(TAG, "다운로드 리시버 등록됨, downloadId=$downloadId") return receiver } @@ -99,11 +130,15 @@ object ApkDownloadManager { /** * 다운로드 완료 리시버 해제 */ - fun unregisterDownloadCompleteReceiver(context: Context, receiver: BroadcastReceiver) { - try { - context.unregisterReceiver(receiver) - } catch (e: Exception) { - // 이미 해제된 경우 무시 + fun unregisterDownloadCompleteReceiver(context: Context) { + registeredReceiver?.let { receiver -> + try { + context.unregisterReceiver(receiver) + Log.d(TAG, "다운로드 리시버 해제됨") + } catch (e: Exception) { + Log.w(TAG, "리시버 해제 실패 (이미 해제됨): ${e.message}") + } + registeredReceiver = null } } diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml index c842ff4..b955a7b 100644 --- a/app/src/main/res/xml/file_paths.xml +++ b/app/src/main/res/xml/file_paths.xml @@ -2,7 +2,7 @@ + path="." /> diff --git a/version.json b/version.json index 31e6e79..57a4bb8 100644 --- a/version.json +++ b/version.json @@ -1,10 +1,10 @@ { - "version": "1.11.3", - "versionCode": 20, - "updateUrl": "https://git.webpluss.net/sanjeok77/hotdeal_alarm/releases/download/v1.11.3/app-release.apk", + "version": "1.11.4", + "versionCode": 21, + "updateUrl": "https://git.webpluss.net/sanjeok77/hotdeal_alarm/releases/download/v1.11.4/app-release.apk", "changelog": [ - "뽐뿌 인기 게시물 뱃지 표시", - "인기 게시물 감지 기능 추가", - "DB 마이그레이션 (v4->v5)" + "업데이트 설치 버그 수정", + "Android 12+ 호환성 개선", + "다운로드 리시버 생명주기 관리 개선" ] }