fix: 업데이트 설치 버그 수정 및 Android 12+ 호환성 개선 (v1.11.4)

- BroadcastReceiver에 RECEIVER_NOT_EXPORTED 플래그 추가 (Android 12+)
- 다운로드 완료 후 리시버 자동 해제로 메모리 누수 방지
- FileProvider 경로 수정으로 APK 설치 실패 문제 해결
- 버전 1.11.4로 업데이트
This commit is contained in:
sanjeok77
2026-03-13 07:25:41 +09:00
parent 1c64245ca2
commit 4d44d8fb7a
6 changed files with 72 additions and 42 deletions

View File

@@ -24,8 +24,8 @@ android {
applicationId = "com.hotdeal.alarm" applicationId = "com.hotdeal.alarm"
minSdk = 31 minSdk = 31
targetSdk = 35 targetSdk = 35
versionCode = 20 versionCode = 21
versionName = "1.11.3" versionName = "1.11.4"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { vectorDrawables {

View File

@@ -172,10 +172,7 @@ class MainActivity : ComponentActivity() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
// 리시버 해제 ApkDownloadManager.unregisterDownloadCompleteReceiver(this)
downloadReceiver?.let {
ApkDownloadManager.unregisterDownloadCompleteReceiver(this, it)
}
} }
// 비저빌리티 콜백 - 백그라운드에서 포어그라운드 전환 시 새로고침 // 비저빌리티 콜백 - 백그라운드에서 포어그라운드 전환 시 새로고침

View File

@@ -477,22 +477,20 @@ private fun MoreTab(viewModel: MainViewModel) {
} }
} }
private fun downloadAndInstallApk(context: Context, updateInfo: com.hotdeal.alarm.util.UpdateInfo) { private fun downloadAndInstallApk(context: Context, updateInfo: com.hotdeal.alarm.util.UpdateInfo) {
// ApkDownloadManager를 사용하여 다운로드 시작 및 자동 설치 val downloadId = ApkDownloadManager.downloadApk(context, updateInfo)
val downloadId = ApkDownloadManager.downloadApk(context, updateInfo)
// 다운로드 완료 리시버 등록 - 완료 시 자동 설치 ApkDownloadManager.registerDownloadCompleteReceiver(
ApkDownloadManager.registerDownloadCompleteReceiver( context = context,
context = context, downloadId = downloadId,
downloadId = downloadId, onComplete = {
onComplete = { ApkDownloadManager.installApk(context)
ApkDownloadManager.installApk(context) },
}, onFailed = {
onFailed = { Toast.makeText(context, "다운로드 실패. 다시 시도해주세요.", Toast.LENGTH_SHORT).show()
Toast.makeText(context, "다운로드 실패. 다시 시도해주세요.", Toast.LENGTH_SHORT).show() }
} )
) }
}
// ==================== 공통 컴포넌트 ==================== // ==================== 공통 컴포넌트 ====================

View File

@@ -6,7 +6,9 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Environment import android.os.Environment
import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -19,8 +21,12 @@ import java.io.File
*/ */
object ApkDownloadManager { object ApkDownloadManager {
private const val TAG = "ApkDownloadManager"
private const val APK_FILE_NAME = "hotdeal-alarm-update.apk" private const val APK_FILE_NAME = "hotdeal-alarm-update.apk"
// 등록된 리시버 추적 (메모리 누수 방지)
private var registeredReceiver: BroadcastReceiver? = null
/** /**
* APK 다운로드 시작 * APK 다운로드 시작
*/ */
@@ -65,6 +71,9 @@ object ApkDownloadManager {
onComplete: () -> Unit, onComplete: () -> Unit,
onFailed: () -> Unit onFailed: () -> Unit
): BroadcastReceiver { ): BroadcastReceiver {
// 기존 리시버가 있으면 먼저 해제
unregisterDownloadCompleteReceiver(context)
val receiver = object : BroadcastReceiver() { val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) ?: -1 val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) ?: -1
@@ -79,8 +88,18 @@ object ApkDownloadManager {
val status = it.getInt(statusIndex) val status = it.getInt(statusIndex)
when (status) { when (status) {
DownloadManager.STATUS_SUCCESSFUL -> onComplete() DownloadManager.STATUS_SUCCESSFUL -> {
DownloadManager.STATUS_FAILED -> onFailed() Log.d(TAG, "다운로드 완료, 설치 시작")
onComplete()
// 설치 후 리시버 해제
unregisterDownloadCompleteReceiver(context)
}
DownloadManager.STATUS_FAILED -> {
Log.e(TAG, "다운로드 실패")
onFailed()
// 실패 시 리시버 해제
unregisterDownloadCompleteReceiver(context)
}
} }
} }
} }
@@ -88,10 +107,22 @@ object ApkDownloadManager {
} }
} }
context.registerReceiver( // Android 12+ 에서는 RECEIVER_NOT_EXPORTED 플래그 필요
receiver, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) 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 return receiver
} }
@@ -99,11 +130,15 @@ object ApkDownloadManager {
/** /**
* 다운로드 완료 리시버 해제 * 다운로드 완료 리시버 해제
*/ */
fun unregisterDownloadCompleteReceiver(context: Context, receiver: BroadcastReceiver) { fun unregisterDownloadCompleteReceiver(context: Context) {
try { registeredReceiver?.let { receiver ->
context.unregisterReceiver(receiver) try {
} catch (e: Exception) { context.unregisterReceiver(receiver)
// 이미 해제된 경우 무시 Log.d(TAG, "다운로드 리시버 해제됨")
} catch (e: Exception) {
Log.w(TAG, "리시버 해제 실패 (이미 해제됨): ${e.message}")
}
registeredReceiver = null
} }
} }

View File

@@ -2,7 +2,7 @@
<paths> <paths>
<external-files-path <external-files-path
name="downloads" name="downloads"
path="Download" /> path="." />
<cache-path <cache-path
name="cache" name="cache"
path="." /> path="." />

View File

@@ -1,10 +1,10 @@
{ {
"version": "1.11.3", "version": "1.11.4",
"versionCode": 20, "versionCode": 21,
"updateUrl": "https://git.webpluss.net/sanjeok77/hotdeal_alarm/releases/download/v1.11.3/app-release.apk", "updateUrl": "https://git.webpluss.net/sanjeok77/hotdeal_alarm/releases/download/v1.11.4/app-release.apk",
"changelog": [ "changelog": [
"뽐뿌 인기 게시물 뱃지 표시", "업데이트 설치 버그 수정",
"인기 게시물 감지 기능 추가", "Android 12+ 호환성 개선",
"DB 마이그레이션 (v4->v5)" "다운로드 리시버 생명주기 관리 개선"
] ]
} }