새로운 버전의 애플리케이션을 배포할 때는 그 사실을 사용자에게 알리고 싶어집니다. 치명적인 버그를 수정했든, 새로운 기능을 추가했든, 아니면 앱이 더 부드럽고 빠르게 실행되도록 개선했든 간에 사용자가 이를 알아야 하기 때문입니다.
앱 개발자라면 누구나 모든 사용자가 항상 최신 버전을 사용하기를 바랍니다.
그렇다면 어떻게 해야 사용자가 새 버전의 출시를 인지하도록 만들 수 있을까요?
답은 생각보다 간단합니다. 새 버전이 출시되면 사용자에게 직접 알려주면 되는 것입니다.
방법은 여러 가지가 있습니다:
- 푸시 알림(push notification) 활용하기
- 앱 실행 시점에 알림 표시하기
이 글에서는 푸시 알림은 다루지 않습니다. 대신 패키지 한두 개를 활용해 새 버전 출시 사실을 다이얼로그로 알려주고, 업데이트를 처리하는 방법에 집중해 보겠습니다.
잠깐, 이 기능은 이미 기본으로 제공되지 않나요?
이런 기능은 이미 최신 모바일 OS에 포함되어 있어야 한다고 생각할 수 있습니다. 맞습니다. 하지만 안드로이드에만 해당하는 이야기입니다.
iOS는 현재 개발자가 새 버전 출시 여부를 확인하고 사용자에게 알릴 수 있는 기능을 제공하지 않습니다. 반면 안드로이드에는 Google Play 라이브러리의 일부인 In-App Update 라이브러리가 있습니다.
이러한 상황과 플러터가 두 플랫폼을 모두 지원한다는 점을 고려하여, 앱 버전 업데이트 처리에 도움을 주는 두 가지 대표적인 패키지를 소개하겠습니다:
- Upgrader
- In App Update
두 패키지 모두 원하는 결과를 얻을 수 있지만, 작동 방식은 크게 다릅니다.
시작하기 전에 반드시 Google Play 스토어에서 직접 설치한 버전의 애플리케이션이 필요하다는 점을 숙지해야 합니다. 두 패키지 모두 Google Play 서비스와 앱 소유자 검증 기능에 의존하기 때문입니다.
이 조건을 충족하지 못하면 패키지 사용 시 다음과 같은 오류가 발생합니다:
Install Error(-10): The app is not owned by any user on this device. An app is "owned" if it has been acquired from Play.
In App Update 패키지 사용 방법
먼저 알아야 할 점은 이 패키지는 안드로이드에서만 작동한다는 것입니다. 내부적으로 Android의 In-App Update 라이브러리에 의존하기 때문입니다.
이 패키지는 사실상 Android 라이브러리의 래퍼(wrapper) 역할을 합니다. 제공되는 API 메서드는 다음과 같습니다:
Future<AppUpdateInfo> checkForUpdate(): 업데이트 가능 여부를 확인합니다.Future<AppUpdateResult> performImmediateUpdate(): 즉시 업데이트를 수행합니다(전체 화면).Future<AppUpdateResult> startFlexibleUpdate(): 유연한 업데이트를 시작합니다(백그라운드 다운로드).Future<void> completeFlexibleUpdate(): 다운로드된 유연한 업데이트를 실제로 설치합니다.
✋ 즉시 업데이트(immediate update)와 유연한 업데이트(flexible update)의 차이점이 궁금하다면 공식 문서를 참고하세요.
패키지 설정 방법
먼저 pubspec.yaml 파일에 패키지를 추가합니다:
dependencies:
flutter:
sdk: flutter
in_app_update: ^3.0.0
그다음 pub get을 실행합니다.
앱 내에서 인앱 업데이트 로직을 처리할 위치에 다음 import 문을 추가합니다:
import 'package:in_app_update/in_app_update.dart';
우선 앱에 업데이트가 존재하는지 확인하는 로직이 필요합니다. 이를 위해 checkForUpdate 메서드를 사용합니다. 반환값은 업데이트의 가용성과 진행 상태 정보를 담은 Future입니다.
updateAvailability 속성으로 업데이트 가능 여부를 확인할 수 있습니다. 업데이트가 있는 경우 값이 UPDATE_AVAILABLE이 됩니다. 따라서 메서드는 다음과 같이 작성할 수 있습니다:
InAppUpdate.checkForUpdate().then((updateInfo) {
if (updateInfo.updateAvailability == UpdateAvailability.updateAvailable) {
//Logic to perform an update
}
});
다음으로 어떤 유형의 업데이트를 트리거할지 결정해야 합니다. 유연한(flexible) 업데이트 또는 즉시(immediate) 업데이트 중 하나를 선택합니다.
즉시 업데이트는 사용자에게 필수적인 앱 업데이트에만 사용해야 합니다. 예를 들어 치명적인 버그를 수정하거나 중요한 신규 기능을 제공하는 버전 등이 해당됩니다.
즉시 업데이트를 시작하려면 performImmediateUpdate 메서드를 사용합니다. 이 메서드는 업데이트 성공 여부를 알려주는 AppUpdateResult 열거형(enum)을 반환합니다.
호출 전에 즉시 업데이트가 허용되는지 먼저 확인해야 합니다. AppUpdateInfo 객체의 immediateUpdateAllowed 플래그로 확인할 수 있습니다.
유연한 업데이트를 트리거하려면 startFlexibleUpdate 메서드를 사용합니다. 이 메서드는 백그라운드에서 실행되며, 즉시 업데이트와 마찬가지로 AppUpdateResult 열거형을 반환합니다.
유연한 업데이트가 성공했다면 completeFlexibleUpdate 메서드를 호출해 앱에 업데이트를 설치해야 합니다.
위 코드 스니펫에 두 가지 업데이트 유형에 대한 로직을 모두 추가하면 다음과 같습니다:
InAppUpdate.checkForUpdate().then((updateInfo) {
if (updateInfo.updateAvailability == UpdateAvailability.updateAvailable) {
if (updateInfo.immediateUpdateAllowed) {
// Perform immediate update
InAppUpdate.performImmediateUpdate().then((appUpdateResult) {
if (appUpdateResult == AppUpdateResult.success) {
//App Update successful
}
});
} else if (updateInfo.flexibleUpdateAllowed) {
//Perform flexible update
InAppUpdate.startFlexibleUpdate().then((appUpdateResult) {
if (appUpdateResult == AppUpdateResult.success) {
//App Update successful
InAppUpdate.completeFlexibleUpdate();
}
});
}
}
});
Upgrader 패키지 사용 방법
첫 번째 옵션과 달리, Upgrader는 iOS와 Android 모두 지원하는 솔루션입니다. 스토어에서 데이터를 가져온 뒤 앱 자체의 현재 정보와 비교하는 방식으로 동작합니다.
데이터를 조회하는 API 대신, 이 패키지는 내부적으로 로직을 수행하는 위젯(widget)을 제공합니다.
패키지 설정 방법
먼저 pubspec.yaml 파일에 패키지를 추가합니다:
dependencies:
flutter:
sdk: flutter
upgrader: ^5.0.0
그다음 pub get을 실행합니다.
앱 내에서 인앱 업데이트 로직을 처리할 위치에 다음 import 문을 추가합니다:
import 'package:upgrader/upgrader.dart';
두 옵션의 주요 차이점은 UI 방식이므로, 자신의 앱에 더 잘 맞는 것을 선택하면 됩니다.
패키지를 통합하려면 body 위젯을 UpgradeAlert 또는 UpgradeCard로 감싸야 합니다. 아래는 예시입니다:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: applicationName,
home: UpgradeAlert( /// <------------------
child: MainPage(
key: Key("YOUR_KEY"),
title: applicationName
),
)
);
}
}
스토어에 새 버전이 존재하면 다음과 같은 업데이트 안내 화면이 표시됩니다.
테스트를 진행하려면 main.dart 파일의 main 메서드 안에 다음 코드를 추가하세요:
await Upgrader.clearSavedSettings()
참고로 Upgrader 패키지에는 설정할 수 있는 구성 옵션이 매우 다양합니다. 공식 문서를 확인해 보시길 강력히 권장합니다.
패키지 테스트 방법
어떤 패키지를 선택하든, 로직이 올바르게 작동하는지 반드시 검증해야 합니다.
그런데 공식 버전을 출시하지 않고 어떻게 테스트할 수 있을까요? Google Play Console의 내부 테스트(internal testing) 기능을 활용하면 됩니다. 내부 테스터에게 새 버전을 배포하면 공개 릴리즈 없이도 업데이트 기능을 테스트할 수 있습니다.
필요한 단계는 다음과 같습니다:
- Google Play Console 계정에 로그인하고, 업데이트 로직을 적용한 앱으로 이동합니다.
- Setup → Internal App Sharing → Manage Testers에서 테스터가 공유된 앱을 다운로드·설치할 수 있도록 허용합니다. 링크 방식 또는 이메일 방식 중 선택할 수 있습니다.
- Testing → Internal Testing으로 이동한 뒤 오른쪽 상단의 Create new release 버튼을 클릭합니다.
- 릴리즈를 완료한 후 Internal Testing 메인 페이지로 돌아가 Testers 탭을 클릭합니다. 테스터 이메일 목록(처음에는 비어 있음)이 보이는데, 파란색 화살표 아이콘을 클릭합니다.
- 이 화면의 Add email addresses에 본인을 내부 테스터로 추가합니다.
- 완료 후 Internal Testing 화면으로 돌아가 맨 아래로 스크롤하면 How testers join your test 섹션과 함께 Copy link 버튼이 보입니다.
이제 버튼을 클릭해 링크를 본인에게 전송하면, 새 버전의 앱을 다운로드할 수 있습니다.
위 단계 중 하나라도 누락되면 생성된 링크가 404(페이지를 찾을 수 없음) 오류로 연결됩니다.
모든 과정을 성공적으로 완료했다면 링크 클릭 시 정상적인 테스트 참여 페이지가 나타납니다.
만약 다음과 같은 오류가 발생한다면:
Install Error(-6): The download/install is not allowed, due to the current device state (e.g. low battery, low disk space, ...)
에뮬레이터에서 앱을 실행 중일 가능성이 높습니다. 에뮬레이터에 Google Play Store가 설치되어 있고 계정에 로그인되어 있어야 합니다.
마무리
이 글은 필자가 직접 자신의 앱에 인앱 업데이트 패키지를 통합하며 겪었던 과정을 바탕으로 작성되었습니다.
Google Play 스토어에서 해당 앱을 확인해 보실 수 있으며, 전체 소스 코드도 공개되어 있으니 참고해 보세요.
읽어주셔서 감사합니다!