Android Gradle의 다중 플레이버 라이브러리를 기반으로하는 다중 플레이버 앱


102

내 앱에는 여러 시장 인앱 결제 시스템에 대한 여러 가지 특징이 있습니다.

내 모든 프로젝트의 기본 코드를 공유하는 단일 라이브러리가 있습니다. 그래서 저는 이러한 결제 시스템을 제품 맛으로이 라이브러리에 추가하기로 결정했습니다.

문제는 Android 라이브러리에 제품 맛이있을 수 있습니까?

그렇다면 앱의 각 버전에 다른 버전을 어떻게 포함시킬 수 있습니까?

검색을 많이했지만이 시나리오에 대해 아무것도 찾을 수 없었습니다. 내가 찾은 유일한 가까운 점은 http://tools.android.com/tech-docs/new-build-system/user-guide입니다 .

dependencies {
    flavor1Compile project(path: ':lib1', configuration: 'flavor1Release')
    flavor2Compile project(path: ':lib1', configuration: 'flavor2Release')
}

구성을 다른 것으로 변경했지만 작동하지 않았습니다!

Android Studio 0.8.2를 사용하고 있습니다.


많은 검색 후, 나는 이것을 달성하는 방법을 찾지 못했습니다 3.4.2.Android 플러그인을 최신 버전으로 업그레이드하고 최신 버전으로 gradle하더라도 5.5.1컴파일 시간에 여전히 실패했거나 aapt에서 리소스 링크가 실패 했거나 라이브러리 내부의 기호찾을 수 없습니다 모듈
VinceStyling

답변:


141

마지막으로이 작업을 수행하는 방법을 알아 냈으며 동일한 문제에 직면 한 다른 사용자를 위해 여기에서 설명하겠습니다.

핵심 부분은 라이브러리 build.gradle에서 publishNonDefault를 true로 설정하는 것입니다. 그런 다음 사용자 가이드에서 제안한대로 종속성을 정의해야합니다.

전체 프로젝트는 다음과 같습니다.

라이브러리 build.gradle :

apply plugin: 'com.android.library'

android {        
    ....
    publishNonDefault true
    productFlavors {
        market1 {}
        market2 {}
    }
}

프로젝트 build.gradle :

apply plugin: 'com.android.application'

android {
    ....
    productFlavors {
        market1 {}
        market2 {}
    }
}

dependencies {
    ....
    market1Compile project(path: ':lib', configuration: 'market1Release')
    market2Compile project(path: ':lib', configuration: 'market2Release')
}

이제 앱 버전과 빌드 변형 패널을 선택할 수 있으며 그에 따라 라이브러리가 선택되고 선택한 버전에 따라 모든 빌드 및 실행이 수행됩니다.

라이브러리를 기반으로하는 여러 앱 모듈이있는 경우 Android Studio는 변형 선택 충돌에 대해 불평 할 것입니다. 괜찮습니다. 무시하면됩니다.

여기에 이미지 설명 입력


공유해 주셔서 감사합니다. 이제 defaultPublishConfig 해결 방법을 제거 할 수 있습니다.
Delblanco 2014

2
AS 1.1.0을 실행하면 위의 솔루션이 여전히 작동하는 것처럼 보이지만 1) 디버그 / 릴리스 빌드 선택이 손실되고 라이브러리에서 AIDL 문제가 계속 발생하여 적절한 코드를 매우 자주 생성하지 못하는 것 같습니다. 이것에 대한 어떤 생각?
3c71

1
@IgorGanapolsky buildTypes는 이와 관련이 없습니다. 모든 플레이버에는 모든 빌드 유형 (일반적으로 디버그 및 릴리스)이 있으며 모두이 접근 방식으로 작동합니다.
Ali

1
@ An-droid는 market1 플레이버에 사용할 라이브러리를 정의합니다!
알리

1
"release"빌드 유형으로 설정된 이유는 무엇입니까? 디버그 빌드 중에 "release"빌드 유형이 선택됩니까?
WindRider

35

알리 대답 에는 한 가지 문제가 있습니다 . 빌드 변형에서 하나의 매우 중요한 차원을 잃고 있습니다. 모든 옵션 (아래의 예에서는 4 (2 x 2))을 원하면 기본 모듈 build.gradle 파일 에 사용자 지정 구성 을 추가 하기 만하면 . 또한 라이브러리 모듈 build.gradle 에서 publishNonDefault를 true 로 설정 해야합니다 .Build Variants 파일 합니다.

솔루션 예 :

Lib build.gradle

android {

    publishNonDefault true

    buildTypes {
        release {
        }
        debug {
        }
    }
    productFlavors {
        free {
        }
        paid {
        }
    }
}

앱 build.gradle

android {

    buildTypes {
        debug {
        }
        release {
        }
    }
    productFlavors {
        free {
        }
        paid {
        }
    }
}

configurations {
    freeDebugCompile
    paidDebugCompile
    freeReleaseCompile
    paidReleaseCompile
}

dependencies {

    freeDebugCompile project(path: ':lib', configuration: 'freeDebug')
    paidDebugCompile project(path: ':lib', configuration: 'paidDebug')
    freeReleaseCompile project(path: ':lib', configuration: 'freeRelease')
    paidReleaseCompile project(path: ':lib', configuration: 'paidRelease')

}

내 응용 프로그램에서 동일한 작업을 수행 한 후 Error:java.lang.RuntimeException: Error: more than one library with package name, occoured
Chetan Joshi

21

Android 플러그인 3.0.0 이상 업데이트

공식 Android 문서- 로컬 모듈에 대한 종속성 구성 마이그레이션 에 따르면 ,

변형 인식 종속성 해결을 사용하면 더 이상 로컬 모듈 종속성에 대해 freeDebugImplementation과 같은 변형 별 구성을 사용할 필요가 없습니다. 플러그인이이를 처리합니다.

대신 다음과 같이 종속성을 구성해야합니다.

dependencies {
    // This is the old method and no longer works for local
    // library modules:
    // debugImplementation project(path: ':library', configuration: 'debug')
    // releaseImplementation project(path: ':library', configuration: 'release')

    // Instead, simply use the following to take advantage of
    // variant-aware dependency resolution. You can learn more about
    // the 'implementation' configuration in the section about
    // new dependency configurations.
    implementation project(':library')

    // You can, however, keep using variant-specific configurations when
    // targeting external dependencies. The following line adds 'app-magic'
    // as a dependency to only the "debug" version of your module.

    debugImplementation 'com.example.android:app-magic:12.3'
}

그래서 Ali의 대답에서

dependencies {
    ....
    market1Compile project(path: ':lib', configuration: 'market1Release')
    market2Compile project(path: ':lib', configuration: 'market2Release')
}

implementation project(':lib')

플러그인은 변형 별 구성을 자동으로 처리합니다. Android Studio 플러그인을 3.0.0 이상으로 업그레이드하는 다른 사용자에게 도움이되기를 바랍니다.


7

내 Android 플러그인은 3.4.0이며 지금 구성이 필요하지 않습니다. 애플리케이션의 flavorDimensions 및 productFlavors가 라이브러리에 동일한 flavorDimensions 및 productFlavor의 productFlavor 하나를 포함하는지 확인하기 만하면됩니다.

mylibrary의 build.gradle에서

apply plugin: 'com.android.library'

android {        
    ....
    flavorDimensions "mylibFlavor"

    productFlavors {
        market1
        market2
    }
}

응용 프로그램의 build.gradle :

apply plugin: 'com.android.application'

android {
    ....
    flavorDimensions "mylibFlavor", "appFlavor"
    productFlavors {
        market1 {
            dimension "mylibFlavor"
        }
        market2 {
            dimension "mylibFlavor"
        }
        common1 {
            dimension "appFlavor"
        }
        common2 {
            dimension "appFlavor"
        }
    }
}

dependencies {
    ....
    implementation project(path: ':mylibrary')
}

동기화 후 Build Variants 창에서 모든 옵션을 전환 할 수 있습니다. 여기에 이미지 설명 입력


하지만 메인 앱 모듈에서 동일한 맛을 갖고 싶지 않으면 어떻게해야합니까? 고유 한 풍미가있는 여러 앱 모듈과 고유 한 풍미가있는 하나의 공통 모듈이 있고 내 앱에서 특정 풍미로 내 lib를 사용하고 싶다고 가정 해 보겠습니다. 어떻게 하시겠습니까? 내 lib 맛을 모든 앱에 복사하는 것은 의미가 없습니다.
Billda

@Billda 모두 복사 할 필요는 없습니다. 동일한 productFlavor를 앱에 하나만 유지하면됩니다. 내 샘플을 위해 애플리케이션의 build.gradle에 market1 또는 market2를 유지할 수 있습니다.
JiajiaGu

2

AAR 라이브러리에서 작동하는 플레이버를 얻으려면 Android 라이브러리 모듈의 build.gradle 파일에 defaultPublishConfig를 정의해야합니다.

자세한 내용은 도서관 출판물을 참조하십시오 .

도서관 출판

기본적으로 라이브러리는 릴리스 변형 만 게시합니다. 이 변형은 자체적으로 빌드하는 변형에 관계없이 라이브러리를 참조하는 모든 프로젝트에서 사용됩니다. 이것은 제거를 위해 노력하고있는 Gradle 제한으로 인한 일시적인 제한입니다. 게시 할 변형을 제어 할 수 있습니다.

android {defaultPublishConfig "debug"}

이 게시 구성 이름은 전체 변형 이름을 참조합니다. 릴리스 및 디버그는 플레이버가없는 경우에만 적용 가능합니다. 특징을 사용하는 동안 게시 된 기본 변형을 변경하려면 다음과 같이 작성합니다.

android {defaultPublishConfig "flavor1Debug"}


1

현재로서는 가능하지 않지만 올바르게 기억하면 추가하려는 기능입니다. (편집 2 : link , link2 )

편집 : 현재 defaultPublishConfig어떤 라이브러리 변형이 게시되는지 선언하는 옵션을 사용하고 있습니다.

android {
    defaultPublishConfig fullRelease
    defaultPublishConfig demoRelease 
}

1
따라서 앱을 컴파일 할 때마다 라이브러리의 build.gradle에서이를 변경해야합니까?
알리

글쎄, 네 ... 매번 다른 맛으로 앱을 컴파일하고 싶을 때.
Delblanco

실제로 라이브러리 모듈에 대한 플레이버를 정의 할 때 상속 된 R 패키지가 앱 모듈에서 발견되지 않습니다.
알리

AS에서 gradle 파일을 동기화 했습니까?
Delblanco

@Delblanco 이것은 수작업과 매우 부서지기 쉬운 것처럼 보입니다 (개발자는 게으르고 build.gradle 파일을 수정하는 것을 잊었습니다).
IgorGanapolsky 2015

1

이 주제가 닫혔다는 것을 알고 있지만 gradle 3.0의 업데이트 일뿐입니다. https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#variant_aware 및 grep을 참조하십시오. matchingFallbacksmissingDimensionStrategy . 이제 모듈 버전 간의 종속성을 선언하는 것이 훨씬 더 간단 해졌습니다.

... 그리고 gradle3.0의 정확한 경우에는 플레이버가 동일한 이름을 공유하기 때문에 gradle은 마법처럼 매핑 할 것이며 구성이 필요하지 않습니다.


나를 위해 런타임 생성 항목을 건너 뛰는 것 같습니다. 예를 들어 simonvt-> 회로도 생성은 더 이상 새로운 방식으로 작동하지 않습니다. :-/
Stefan Sprenger 2017-11-05

1

또한 다양한 옵션을 위해 모듈을 컴파일하는 데 문제가 발생했습니다.

내가 찾은 것 :

Gradle 3.0.1 이후 publishNonDefault truelib build.gradle파일에 추가 할 필요가없는 것 같습니다 .

클래스를 디 컴파일 한 후 다음을 BaseExtension발견했습니다.

public void setPublishNonDefault(boolean publishNonDefault) {
   this.logger.warn("publishNonDefault is deprecated and has no effect anymore. All variants are now published.");
}

그리고 대신 :

dependencies {
...
   Compile project(path: ':lib', configuration: 'config1Debug')
}

다음을 사용해야합니다.

dependencies {
...
   implementation project(':lib')
}

중요한 점 configurations {...}build.gradle.

따라서 앱 build.gradle파일 의 최종 변형 은 다음과 같습니다.

buildTypes {
   debug {
      ...
   }

   release {
      ...
   }
}

flavorDimensions "productType", "serverType"
productFlavors {
   Free {
      dimension "productType"
      ...
   }
   Paid {
      dimension "productType"
      ...
   }
   Test {
      dimension "serverType"
      ...
   }
   Prod {
      dimension "serverType"
      ...
   }
}

configurations {
   FreeTestDebug
   FreeTestRelease
   FreeProdDebug
   FreeProdRelease
   PaidTestDebug
   PaidTestRelease
   PaidProdDebug
   PaidProdRelease
}

dependencies {
   implementation fileTree(dir: 'libs', include: ['*.jar'])
   implementation project(':lib')
   ...
}

또한 필터 변형 을 사용 하여 빌드 변형을 제한 할 수 있습니다 .

추신은 다음 settings.gradle과 같이 파일에 모듈을 포함하는 것을 잊지 마십시오 .

include ':app'
include ':lib'
project(':lib').projectDir = new File('app/libs/lib')

선생님, 스크립트가 특정 구성에 라이브러리를 포함 할 날씨를 결정하는 방법을 설명해 주시겠습니까? 나는 어떤 맛에 대한 몇 가지 lib 디렉토리를 사용할 필요가있을 때 난 경우를 의미,하지만 난 다른 맛을 위해 그것을 사용할 필요가 없습니다
태그 Jenya Kirmiza

그런 상황에 빠지지 않았습니다. 그러나 Google 자습서 developer.android.com/studio/build/dependencies 는 "dependencies {...}"블록에서 "implementation"명령 앞에 접두사를 추가 할 것을 권장합니다. 즉, 종속성 {paidImplementation 프로젝트 ( ': lib')} 또는 종속성 {debugImplementation 프로젝트 ( ': lib')} 또는 여러 변형 조합 종속성 {paidProdDebugImplementation 프로젝트 ( ': lib')}. 그것을 확인하고 우리에게 피드백을주십시오 :)
Sergio
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.