Flutter - 앱 버전 업데이트 구현하기, 파이어베이스로 버전 관리하기(FlutterFire RemoteConfig)

반응형

Overview

현재 회사에서 새롭게 리뉴얼해서 2.0 버전으로 만드는 앱이 있다.

앱이 신버전으로 출시 될 때, 사용자들은 앱이 출시됐는지를 확인하기 어렵다.

즉, 개발자는 앱 사용자들이 새로운 버전의 앱이 출시되었을 때 최신버전의 앱을 사용하도록 유도해야한다.

좀 더 자세히 말하면, 구글 플레이 스토어를 통해 앱을 업데이트하도록 해서 최신 버전을 사용할 수 있게 하여야 한다.

이는 Firebase의 RemoteConfig를 사용하면 버전 관리 기능은 손쉽게 구현할 수 있다.

 

아래는 예시 이미지이다.

버전 정보가 다르면 업데이트 해달라는 문구가 출력되고,

업데이트하기 버튼을 누르면 구글 플레이 스토어로 연결되어 업데이트를 진행하는 기능이다.

<RemoteConfig 를 이용하여 버전 확인 후 버전이 다르면 업데이트를 유도하는 화면>


이번 포스팅에서는...

  1. 파이어베이스의 원격 구성을 이용하여 앱의 최신 버전을 확인하고,
  2. 최신 버전이 아니면 앱 스토어로 이동하여 업데이트를 유도하는 기능을 구현하도록 한다.

단, 이 포스팅에서는 안드로이드를 기준으로 구글 플레이 스토어에 출시한 앱을 최신 버전으로 업데이트 하기 위하여 작성되었기 때문에 현재로써는 iOS에 관해서는 따로 내용을 기술하지 않았다.


파이어베이스와 플러터파이어로 앱 연동이 되어 있지 않은 상태라면 아래의 포스팅을 참고하자.

[ 파이어베이스 프로젝트 생성, 파이어베이스 CLI 설치 참고 페이지 ]

[ 앱에 파이어베이스 연동 참고 페이지 ]


[ 포스팅에서의 환경 ]

포스팅의 환경은 윈도우OS를 사용중이며, IDE툴은 VS Code를 사용한다.

업데이트 기능 구현을 위해 기본적으로 FlutterFire 연동을 통해 RemoteConfig를 사용한다.

또한, 추가적으로 패키지 정보를 확인하는 package_info_plus 패키지와

URL 링크로 이동할 수 있도록 하는 url_launcher 패키지를 사용한다.

그리고 업데이트를 위해 연결되는 링크는 구글 플레이 스토어를 기준으로 한다.


파이어베이스 원격 구성(Firebase RemoteConfig)란?

클라우드에서 앱의 매개변수를 정의하고 값을 업데이트하면 앱 업데이트를 배포하지 않고도 앱의 모양과 동작을 수정할수 있는 클라우드 서비스이다.

원격 구성을 사용하여 모든 앱 사용자 또는 사용자층의 특정 세그먼트에 대한 기본값을 재정의할 수 있다.

또한 업데이트 적용 시점을 앱에서 제어할 수 있으며 성능에 거의 영향을 주지 않고 업데이트를 자주 확인하여 적용할 수 있는 기능을 가지고 있다.

파이어베이스 원격 구성에서 제공하는 주요 기능은 다음과 같다.

  • 앱 사용자층에 변경사항을 빠르게 적용
  • 사용자층의 특정 세그먼트에 앱 맞춤설정
  • 원격 구성 맞춤설정을 사용하여 개별 사용자에 맞게 앱을 지속적으로 자동 맞춤설정하고 전략적 목표에 맞게 최적화
  • A/B 테스트를 실행하여 앱 개선

쉽게 말하면, 앱 자체에서 제공되는 변수의 값으로 제어되는게 아닌 파이어베이스 원격 구성의 매개변수를 통해 앱에서 제어할 수 있도록 해서 앱의 자체적인 수정 없이 파이어베이스 원격 구성의 매개변수 값 변경만을 통하여 앱의 동작 방식을 수정할 수 있는 기능을 말한다.


파이어베이스 콘솔 매개변수 설정

파이어베이스 콘솔에 접속하고 플러터파이어와 연동된 프로젝트를 선택한다.

 

좌측의 빌드 > Remote Config 를 눌러 페이지를 이동 후, 매개변수를 만들기 위해 '구성 만들기' 버튼을 누른다.

이미 매개변수가 존재하는 프로젝트라면 Remote Config 페이지에서 '매개변수 추가' 버튼을 누르면 된다.

(혹은 기존에 존재하는 매개변수를 이용하여도 된다.)

<매개변수를 만들기 위해 파이어베이스콘솔에서 구성 만들기 버튼을 누른 화면>

 

매개변수의 이름을 설정한다.

포스팅에서는 매개변수를 통해 버전 관리를 하고 앱 업데이트를 하는 기능을 구현할 것이므로

매개변수의 이름을 latest_version 으로 정의하였다. 값은 1.6으로 설정하였다.

보통 초기값은 1.0으로 설정하여 버전 업 시 조금씩 숫자가 커진다.

(포스팅에서 다루는 앱은 조금 특수한 경우로 기존에 출시되어 있는 앱이 있어서 버전을 이어갔다.)

 

이제 이 매개변수의 값(1.6)이 앱 실행 시 파이어베이스 remoteConfig 를 통해 앱으로 값이 넘어오고,

넘어온 값을 통해 앱의 버전 정보를 비교해보고 최신 버전인지 아닌지를 판단한다.

그리고 최신 버전이 아니라면 최신 버전으로 앱을 업데이트할 수 있도록 버전 관리를 해야한다.


안드로이드 버전 설정

플러터 프로젝트에서 android > app > build.gradle 파일을 연다.

defaultConfig 부분을 살펴보면 versionName 부분의 버전을 확인한다.

혹은 기존의 버전이 존재한다면 더 상위 버전으로 올려준다.

포스팅에서는 기존의 출시되어 있는 앱 버전이 1.6이므로 1.7로 설정하였다.

defaultConfig {
    // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
    applicationId // 자신의 앱 ID 입력 (패키지 이름)
    // You can update the following values to match your application needs.
    // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
    minSdkVersion 21 // flutter.minSdkVersion
    targetSdkVersion 33 // flutter.targetSdkVersion
    versionCode 8 // 빌드 번호
    versionName "1.7" // 버전
}

앱 정보 확인하기 (package_info_plus 패키지 사용)

포스팅에서는 안드로이드 기준으로 앱의 버전을 build.gradle에서 1.7로 설정하였다.

플러터 앱 내에서 앱 버전을 확인할 수 있어야한다.

앱 내 정보를 쉽게 확인하기 위한 패키지가 존재한다.

package_info_plus 패키지를 사용하여 앱 버전을 쉽게 확인할 수 있다.

이는 파이어베이스 콘솔에서 전달 받은 매개변수(버전 정보)와 현재 앱의 버전 정보를 대조하기 위함이다.

  • 앱 내 버전 정보 확인을 위한 package_info_plus 패키지 설치
flutter pub add package_info_plus
  • package_info_plus 패키지 호출
import 'package:package_info_plus/package_info_plus.dart';
  • 버전 정보를 확인하기 위해서는 단 두 줄의 코드면 된다.
// 앱 버전 정보 가져오기
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String appVersion = packageInfo.version;

print(
    "### App Version : $appVersion");
   
// 콘솔 출력 내용
// ### App Version : 1.7

Firebase RemoteConfig 설정

이제 앱이 최신 버전을 확인하고 버전 관리를 할 수 있는 기능을 구현하기 위해 환경을 구성해보자.

터미널에서 파이어베이스 원격 구성을 사용하기 위해 각각의 패키지를 설치해준다.

사용자의 조건부 타겟팅(특정 사용자 별로 다르게 작동하는)을 위해서는 구글 애널리틱스가 필수로 있어야한다.


Firebase Remote Config 패키지 설치

  • 파이어베이스 원격 구성 패키지 설치
flutter pub add firebase_remote_config
  • 구글 애널리틱스용 Firebase SDK 설치
flutter pub add firebase_analytics

파이어베이스 매개변수 값 호출

Firebase RemoteConfig 패키지를 사용하려면 우선 호출을 하여야한다.

import 'package:firebase_remote_config/firebase_remote_config.dart';

 

remoteConfig 인스턴스를 생성하고 파이어베이스 콘솔의 매개변수 값을 호출해보자.

  • setConfigSettings
    • 원격 구성 기본 설정을 하는 메서드
  • fetchTimeout
    • 데이터를 가져오는데 허용하는 시간을 의미
  • minimumFetchInterval
    • 데이터를 가져오는 시간 간격을 의미
    • 앱에서 단기간에 가져오기를 너무 많이 수행하면 가져오기 호출이 제한될 수 있다.
    • 원격 구성의 가져오기 간격 최솟값은 12시간을 기본값으로 한다.
    • 개발 중에는 가져오기 간격 최솟값을 상대적으로 낮게 설정하는 것이 좋다. 
  • fetchAndActivate
    • 호출 한 번으로 값을 가져오고 활성화하는 메서드
    • fetch() : 백엔드에 설정한 모든 값을 가져와 원격 구성 객체에 저장하는 메서드이다.
    • activate() : 가져온 매개변수 값을 앱에 적용하기 위한 메서드이다.
    • 즉, fetchAndActivate() 메서드는 한 번의 요청으로 값을 가져와 앱에서 사용할 수 있도록 한다.
// remoteConfig 인스턴스 생성
final remoteConfig = FirebaseRemoteConfig.instance;

// 데이터 가져오기 시간 간격 : 12시간
await remoteConfig.setConfigSettings(RemoteConfigSettings(
  fetchTimeout: const Duration(minutes: 1), // 데이터를 가져오는데 허용하는 시간
  minimumFetchInterval: const Duration(hours: 12), // 데이터 가져오기 간격
));

// 12시간마다 버전 확인
await remoteConfig.fetchAndActivate();

// 파이어베이스 버전 정보 가져오기 : latest_version 은 파이어베이스 매개변수명을 의미
String firebaseVersion = remoteConfig.getString("latest_version");

버전 관리

버전 관리 절차

[ 최신 버전 출시를 위한 버전 관리 절차 ]

1. 앱 버전을 출시할 최신 버전 정보와 동일하게 버전을 수정한다.

2. 파이어베이스 콘솔에서 버전 정보가 담겨있는 매개변수의 값을 최신 버전의 값으로 수정한다.

3. 앱을 출시한다.

 

[ 앱에서의 버전 확인 절차 ]

1. 앱 버전을 확인한다.

2. 파이어베이스 콘솔에서 매개변수로 정의한 버전 값을 가져와 확인한다.

3. 앱 버전과 파이어베이스 콘솔에서 가져온 버전 값을 확인하고 최신 버전이 출시되었는지 확인한다.

3-1. 서로 버전 정보가 상이하면 버전 업데이트를 위한 코드를 정의한다.

3-2. 버전 정보가 같으면 앱의 메인 페이지로 이동한다.


앱에서 버전 확인하기

위에서 작성한 코드를 기반으로 한다.

파이어베이스 콘솔의 매개변수 값을 저장한 변수(firebaseVersion)와

현재 앱의 버전 정보를 저장한 변수(appVersion)의 값을 대조해보자.

print("###Remote Config activated : Firebase Version : $firebaseVersion, App Version : $appVersion");

// 콘솔 출력 내용
// ###Remote Config activated : Firebase Version : 1.6, App Version : 1.7

앱 내 최신 버전 업데이트 기능 구현

확인한 앱 버전과 파이어베이스 콘솔에서 확인한 버전 값이 다르면

앱 스토어로 연결하여 업데이트를 할 수 있도록 해보자.

 

[ 클래스 초기화 ]

처음 페이지 호출 시 초기화 함수에서 버전 체크를 하는 함수를 호출해보자.

  @override
  void initState() {
    super.initState();

    // 버전 확인 사용자 정의 함수
    checkAppVersion();
  }

 

[ 버전 체크 함수 정의 (checkAppVersion) ]

이제 버전 체크를 하는 함수를 정의해보자.

현재 앱의 버전과 파이어베이스 콘솔에서의 버전 정보를 확인하고,

파이어베이스 콘솔에서의 버전 정보가 앱의 버전 정보보다 더 높을 경우 업데이트할 수 있도록 하였다.

if문에서 버전 체크 후 함수를 호출하여 각각 업데이트 화면, 메인 화면으로 이동하게끔 설정하였다. 

// 파이어베이스 버전 확인
  Future<void> checkAppVersion() async {
    final remoteConfig = FirebaseRemoteConfig.instance;

	/* ##### 파이어베이스 매개변수 값 호출 ##### */
    // 데이터 가져오기 시간 간격 : 12시간
    await remoteConfig.setConfigSettings(RemoteConfigSettings(
      fetchTimeout: const Duration(minutes: 1),
      minimumFetchInterval: const Duration(hours: 12),
    ));
    await remoteConfig.fetchAndActivate();


	/* ##### 버전 정보 가져오기 ##### */
    // 파이어베이스 버전 정보 가져오기 : 매개변수명 latest_version
    String firebaseVersion = remoteConfig.getString("latest_version");

    // 앱 버전 정보 가져오기
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    String appVersion = packageInfo.version;


	/* ##### 버전 체크 ##### */
    // 최신 버전이 존재하면 버전 업데이트 화면으로 이동
    if (double.parse(firebaseVersion) > double.parse(appVersion)) {
      showUpdateDialog();
    }
    // 앱이 최신 버전이면 앱 메인 화면으로 이동
    else {
      showMainPage();
    }
  }

 

[ 업데이트 화면 기능 정의 (showUpdateDialog) ]

해당 포스팅은 구글 플레이 스토어로 연결되게끔 설정하였다.

애플 스토어일 경우에는 url을 애플 스토어의 주소로 변경하여 진행하면된다.

구글 플레이 스토어로 이동하기 위해서는 url_launcher 패키지를 사용하였다.

  • 터미널에서 url_launcher 패키지 추가
flutter pub add url_launcher
  • url_launcher 패키지 호출
import 'package:url_launcher/url_launcher.dart';

 

 

구글 플레이 스토어의 경우는 아래의 플레이 스토어 URL 에서 id 부분 뒤에 자신의 패키지 이름을 입력하면 된다.

 

업데이트하기 버튼을 누르면 구글 플레이 스토어로 연결되고, 앱 종료 버튼을 누르면 앱이 종료되도록 기능 정의를 하였다.

또한, 업데이트를 하지 않으면 앱을 사용하지 못하도록 showDialog의 속성 barrierDismissible 값을 false로 하여 다이얼로그 외부는 터치가 허용되지 않도록 설정하였다.

  // 버전 업데이트가 존재하면 업데이트 문구 출력
  Future<void> showUpdateDialog() {
    return showDialog(
        context: context,
        barrierDismissible: false,
        builder: (context) {
          return AlertDialog(
              title: const Center(child: Text("업데이트 알림")),
              content: const Text(
                "앱의 최신 버전이 등록되었습니다.\n앱 업데이트를 진행해 주세요.\n앱 업데이트를 진행하지 않을 경우에는\n서비스를 이용하실 수 없습니다.",
                textAlign: TextAlign.center,
              ),
              actions: <Widget>[
                ElevatedButton(
                    onPressed: () async {
                      const url =
                          'https://play.google.com/store/apps/details?id=com.edubase.aimath';
                      if (await canLaunchUrl(Uri.parse(url))) {
                        await launchUrl(Uri.parse(url));
                      }
                    },
                    style: const ButtonStyle(
                        backgroundColor: MaterialStatePropertyAll<Color>(
                            Color.fromARGB(255, 240, 147, 71))),
                    child: const Text(
                      "업데이트하기",
                      style: TextStyle(color: Colors.black),
                    )),
                ElevatedButton(
                    onPressed: () async {
                      // 앱 종료
                      if (Platform.isAndroid) {
                        SystemNavigator.pop();
                      } else if (Platform.isIOS) {
                        exit(0);
                      }
                    },
                    child: const Text(
                      "앱 종료",
                      style: TextStyle(color: Colors.black),
                    ))
              ],
            );
        });
  }

참고

Firebase 문서 - Remote Config - Firebase 원격 구성

Firebase 문서 - Remote Config - Firebase 원격 구성 시작하기

FlutterFire 문서 - Get started with Firebase Remote Config

flutter pub.dev - package_info_plus

flutter pub.dev - url_launcher

반응형