본문 바로가기
Android/기타

하나의 프로젝트에서 여러 다른 버전의 앱을 만들어 보자!(1) - BuildType, productFlavors

by 안스 인민군 2024. 1. 28.

이 글을 앞서 먼저 예시의 상황을 만들어 보자.

먼저 당신은 서비스를 개발하기 전 다양한 형태의 서비스를 제공하기 위해 설계를 해야한다.

여기서 다양한 형태란 무엇일까?

  1. 개발용 debug, 구글 플레이스토어에 올라갈 실제 유저가 사용될 release 두 가지의 빌드 타입
  2. 무료버젼과 유료버젼 등 다양한 버젼
  3. 딥링크를 활용한 서비스 지원
  4. 라이브러리화하여 외부 업체 지원

하나의 프로젝트에서 여러 다른 버전의 앱을 만들어 보자! 시리즈는 위의 다양한 형태에 대해서 작성해보려 한다.

 

2편 : 하나의 프로젝트에서 여러 다른 버전의 앱을 만들어 보자!(2) - DeepLink

3편 : 하나의 프로젝트에서 여러 다른 버젼의 앱을 만들어 보자!(3) - Link

 


이번 글은 빌드 타입과 버젼을 지정할 수 있는 방법에 대해서 알아보자.

BuildTypes

먼저 예시를 생각해보자.

우리는 개발용(debug)과 출시용(release) 환경을 따로 두어 개발해야 한다.

예시로 회사에서는  개발서버와 릴리즈 서버를 구분하여 개발하는데 그때마다 계속해서 바꿔줘야한다면 얼마나 귀찮을까?

이럴때 사용할 수 있는 기능으로 Android Gradle 플러그인에서 제공하는 BuildTypes 가 있다.

Build.gradle 파일에 아래와 같이 작성하면 된다. 아래 예시는 간단하게 debug, stage, release 세 가지만 작성했다.

android {
...
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-android.txt'
            debuggable false
            shrinkResources true
        }

        stage {
            initWith debug
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-android.txt'

            applicationIdSuffix ".stage"
            matchingFallbacks = ['debug']
            debuggable false
            shrinkResources true
        }

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }
}

각각 debug, stage, release 마다 선언되어 있는것이 다른데 각각의 내부 속성들에 대해서 알아보면

    • minifyEnabled: 사용되지 않는 코드와 리소스를 제거하여 APK를 더 작게 만들고 리버스 엔지니어링하기 어렵게 만들어 릴리스 빌드에 대한 코드 축소, 난독화 및 최적화를 가능하게 한다. 대신 true 시 빌드 속도가 늦어진다.
    • proguardFiles: 난독화 및 최적화에 사용할 ProGuard 규칙 파일을 지정합니다. getDefaultProguardFile('proguard-android.txt')에는 Android 프로젝트의 기본 규칙이 포함되어 있으며 'proguard-android.txt'는 사용자 정의 규칙 파일이다. 대신 true 시 서버 등에서 전달 하는 데이터가 난독화가 되어 보기가 어려워진다.
    • debuggable false: 빌드를 디버깅할 없게 만든다. , 디버거에 연결할 없다. 이는 보안과 성능을 보장하는 릴리스에 적합하다.
    • initWith debug: 디버그 빌드 유형의 설정으로 스테이징 빌드 유형을 초기화한 다음 지정된 대로 재정의한다.
    • applicationIdSuffix ".stage": 이 빌드 유형의 애플리케이션 ID(패키지 이름)에 접미사를 추가하여 앱의 준비된 버전을 다른 버전과 함께 설치할 수 있다.
    • matchingFallbacks = ['debug']: 종속성에 스테이징 변형이 포함되지 않은 경우 대체 빌드 유형을 지정합니다. 여기서는 종속성의 디버그 변형을 사용하는 것으로 대체된다.
    • shrinkResources : minifyEnabled 외에도 사용되지 않는 리소스를 제거하여 release stage 빌드의 APK 크기를 더욱 줄인다.

위를 토대로 stage는 최대한 release 의 APK 파일과 비슷하게 제작 하되 서버나 빌드 유형은 debug 환경과 같게 조정하였다.

이유는 stage(내부배포) 에서 proguardFiles 와 같은 잊기 쉬운 부분을 QA 검증 기간 동안 발생 시켜 release 의 안정성을 높이고 debug와 stage 는 회사의 내부 서버를 사용하기 위해서이다.

debug 에서는 shrinkResourcesminifyEnabled 등을 추가하지 않은 이유는 한번 빌드시 많은 시간이 걸리기 때문이다.

productFlavors

다음은 Android Gradle 플러그인의 productFlavors 라는 기능이 있는데 애플리케이션의 다양한 변형을 정의할 있다. 이러한 변형에는 고유한 기능, 리소스 코드가 있을 있다.  기능은 무료 유료 버전, 언어나 콘텐츠가 다른 지역 변형 단일 프로젝트에서 여러 버전의 앱을 생성하려는 경우에 유용 하다.

제품 버전은 애플리케이션 ID, 버전 코드, 버전 이름 등과 같은 다양한 구성을 지정하여 스토어와 Divice에서 구별할 있도록 한다. 또한 종속성, 소스 세트(Java/Kotlin 소스 파일, 리소스, AndroidManifest 파일 포함) Gradle 스크립트가 다르게 지정이 가능하다.

BuildTypes 와 마찬가지로 Build.Gradle 에 아래와 같이 추가하면 된다.

아래와 같이 minSdkversion 이나 versionCode, versionName 등 각 제품마다 변경이 가능하다.

android {
    ...
    signingConfigs {
        debug {
            // Config for debug signing
        }
        release {
            // Config for release signing
        }
    }

    productFlavors {
        free {
            applicationId "com.example.app.free"
            versionCode 1
            versionName "1.0-free"

            signingConfig signingConfigs.debug

            buildConfigField "boolean", "FULL_FEATURES", "false"
            resValue "string", "app_name", "App Free"

            dependencies {
                implementation 'com.google.android.gms:play-services-ads:19.7.0' // Example dependency for the free version
            }
        }

        pro {
            applicationId "com.example.app.pro"
            versionCode 1
            versionName "1.0-pro"

            signingConfig signingConfigs.release

            buildConfigField "boolean", "FULL_FEATURES", "true"
            resValue "string", "app_name", "App Pro"

            dependencies {
                implementation 'com.android.support:design:28.0.0' // Example dependency exclusive to the pro version
            }
        }
    }

    sourceSets {
        free {
            res.srcDirs = ['src/free/res']
        }
        pro {
            res.srcDirs = ['src/pro/res']
        }
    }
    ...
}

dependencies {
    // Common dependencies for all flavors
    implementation 'androidx.appcompat:appcompat:1.2.0'
    ...
}

 

  • 서명 구성: 디버그 및 릴리스 빌드에 대해 별도의 서명 구성이 정의된다. 이렇게 하면 무료 버전은 테스트용 디버그 키로 서명되고, 프로 버전은 배포용 릴리스 키로 서명될 수 있다.
  • 빌드 구성 필드: 사용자 정의 필드(FULL_FEATURES)가 BuildConfig에 추가된다. 이를 통해 앱의 코드는 전체 기능을 활성화해야 하는지 여부를 확인할 수 있다.(프로 버전의 경우 'true', 무료 버전의 경우 'false').
  • Res Values: 리소스 값(app_name)은 각 버전에 대해 정의되어 빌드 변형에 따라 앱이 다른 이름("App Free" 및 "App Pro")을 가질 수 있다.
  • 종속성: 각 버전에 특정 종속성이 추가된다. 예를 들어 무료 버전에는 Google Play 서비스 광고가 포함되어 있고, 프로 버전에는 독점 기능을 위한 Android 지원 디자인 라이브러리가 포함되어 있다.
  • 리소스 디렉터리: 버전별 리소스 디렉터리(src/free/res 및 src/pro/res)가 지정되어 각 버전이 고유한 리소스 세트(예: 레이아웃, 값 및 기본 리소스를 재정의하는 드로어블 자산)

설정은 Android 빌드 변형 기능을 효과적으로 활용하여 단일 프로젝트에서 여러 버전을 관리함으로써 유지 관리성과 확장성을 향상시킨다.