Ứng dụng đa hương vị dựa trên thư viện đa hương vị trong Android Gradle


102

Ứng dụng của tôi có một số hương vị cho một số thị trường hệ thống thanh toán trong ứng dụng.

Tôi có một thư viện chia sẻ mã cơ sở cho tất cả các dự án của tôi. Vì vậy, tôi quyết định thêm các hệ thống thanh toán đó vào thư viện này dưới dạng hương vị sản phẩm.

Câu hỏi đặt ra là thư viện android có thể có các hương vị sản phẩm không?

Nếu vậy, làm cách nào tôi có thể đưa các hương vị khác nhau vào hương vị tương ứng của ứng dụng?

Tôi đã tìm kiếm rất nhiều, và tôi không thể tìm thấy bất cứ điều gì về kịch bản này. Điều gần gũi duy nhất tôi tìm thấy là điều này trong http://tools.android.com/tech-docs/new-build-system/user-guide :

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

Tôi đã thay đổi cấu hình thành những thứ khác nhau nhưng nó không hoạt động!

Tôi đang sử dụng android studio 0.8.2.


sau nhiều lần tìm kiếm, tôi không tìm thấy cách nào để đạt được điều này, ngay cả khi tôi nâng cấp plugin android lên 3.4.2phiên bản mới nhất và nâng cấp lên phiên bản mới nhất 5.5.1, nó vẫn không thành công với thời gian biên dịch hoặc liên kết tài nguyên không thành công trong aapt hoặc không thể tìm thấy biểu tượng bên trong thư viện mô-đun
VinceStyling

Câu trả lời:


141

Cuối cùng, tôi đã tìm ra cách làm điều này, tôi sẽ giải thích nó ở đây cho những người khác gặp phải vấn đề tương tự:

Phần quan trọng là đặt PublishingNonDefault thành true trong thư viện build.gradle, Sau đó, bạn phải xác định các phần phụ thuộc theo đề xuất của hướng dẫn sử dụng.

Toàn bộ dự án sẽ như thế này:

Thư viện build.gradle:

apply plugin: 'com.android.library'

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

project build.gradle:

apply plugin: 'com.android.application'

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

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

Bây giờ bạn có thể chọn hương vị ứng dụng và bảng Build Variants và thư viện sẽ được chọn cho phù hợp và tất cả việc xây dựng và chạy sẽ được thực hiện dựa trên hương vị đã chọn.

Nếu bạn có nhiều mô-đun ứng dụng dựa trên thư viện, Android Studio sẽ phàn nàn về xung đột lựa chọn Biến thể, Không sao cả, hãy bỏ qua nó.

nhập mô tả hình ảnh ở đây


Cảm ơn bạn đã chia sẻ, bây giờ tôi có thể loại bỏ cách giải quyết defaultPublishConfig của mình.
Delblanco,

2
Chạy AS 1.1.0, giải pháp trên dường như vẫn hoạt động, tuy nhiên 1) lựa chọn bản dựng gỡ lỗi / phát hành bị mất và tôi dường như tiếp tục gặp sự cố với AIDL được tìm thấy trong thư viện rất thường xuyên không tạo ra mã thích hợp. Bất kỳ suy nghĩ về điều này?
3c71

1
@IgorGanapolsky buildTypes không liên quan gì đến điều này. Mọi hương vị đều có tất cả các kiểu xây dựng (thường là gỡ lỗi và phát hành) và tất cả chúng đều hoạt động với cách tiếp cận này.
Ali

1
@ An-droid nó xác định thư viện được sử dụng cho hương vị market1!
Ali

1
Tại sao nó được đặt thành loại xây dựng "phát hành"? Loại bản dựng "phát hành" có được chọn trong khi bản dựng gỡ lỗi không?
WindRider

35

Có một vấn đề với câu trả lời của Ali . Chúng tôi đang đánh mất một khía cạnh rất quan trọng trong các biến thể xây dựng của mình. Nếu chúng ta muốn có tất cả các tùy chọn (trong ví dụ dưới đây của tôi là 4 (2 x 2)), chúng ta chỉ cần thêm các cấu hình tùy chỉnh trong tệp build.gradle của mô-đun chính để có thể sử dụng tất cả các loại đa buildType trong Build Variants. Chúng tôi cũng phải đặt PublishingNonDefault true trong tệp build.gradle của mô-đun thư viện .

Giải pháp ví dụ:

Lib build.gradle

android {

    publishNonDefault true

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

App 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')

}

Sau khi làm những việc tương tự trong ứng dụng của tôi Error:java.lang.RuntimeException: Error: more than one library with package name,, đã xảy ra
Chetan Joshi,

21

Cập nhật cho Android Plugin 3.0.0 trở lên

Theo Tài liệu Android chính thức - Di chuyển cấu hình phụ thuộc cho các mô-đun cục bộ ,

Với độ phân giải phụ thuộc nhận biết biến thể, bạn không còn cần sử dụng các cấu hình dành riêng cho biến thể, chẳng hạn như freeDebugImplementation, cho các phụ thuộc mô-đun cục bộ — plugin sẽ giải quyết việc này cho bạn

Thay vào đó, bạn nên định cấu hình các phần phụ thuộc của mình như sau:

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'
}

Vì vậy, trong câu trả lời của Ali, hãy thay đổi

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

đến

implementation project(':lib')

Và plugin sẽ tự động xử lý các cấu hình cụ thể của biến thể. Hy vọng nó sẽ giúp những người khác nâng cấp Android Studio Plugin lên 3.0.0 và cao hơn.


7

Plugin Android của tôi là 3.4.0 và tôi thấy rằng nó không cần cấu hình ngay bây giờ. Tất cả những gì bạn cần là đảm bảo hương vị và sản phẩmFlavors trong ứng dụng có chứa một sản phẩm

Trong mylibrary's build.gradle

apply plugin: 'com.android.library'

android {        
    ....
    flavorDimensions "mylibFlavor"

    productFlavors {
        market1
        market2
    }
}

build.gradle của ứng dụng:

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')
}

Sau khi đồng bộ hóa, bạn có thể chuyển đổi tất cả các tùy chọn trong Cửa sổ Xây dựng Biến thể: nhập mô tả hình ảnh ở đây


Nhưng nếu tôi không muốn có cùng hương vị trong mô-đun ứng dụng chính của mình thì sao? Giả sử tôi có nhiều mô-đun ứng dụng có hương vị riêng và một mô-đun chung có hương vị riêng và tôi muốn sử dụng trong ứng dụng của mình lib của tôi với hương vị cụ thể. Bạn làm điều đó như thế nào? Không có ý nghĩa gì khi sao chép hương vị lib của tôi vào tất cả các ứng dụng.
Billda

@Billda Bạn không cần sao chép tất cả, chỉ cần giữ một productFlavor giống nhau trong ứng dụng, đối với mẫu của tôi, tôi có thể giữ market1 hoặc market2 trong build.gradle của ứng dụng.
JiajiaGu

2

Để có được các hương vị hoạt động trên thư viện AAR, bạn cần xác định defaultPublishConfig trong tệp build.gradle của mô-đun Thư viện Android của bạn.

Để biết thêm thông tin, hãy xem: Xuất bản Thư viện .

Xuất bản Thư viện

Theo mặc định, một thư viện chỉ xuất bản biến thể phát hành của nó. Biến thể này sẽ được sử dụng bởi tất cả các dự án tham chiếu đến thư viện, bất kể biến thể nào họ tự xây dựng. Đây là hạn chế tạm thời do các giới hạn của Gradle mà chúng tôi đang nỗ lực loại bỏ. Bạn có thể kiểm soát biến thể nào được xuất bản:

android {defaultPublishConfig "debug"}

Lưu ý rằng tên cấu hình xuất bản này tham chiếu đến tên biến thể đầy đủ. Việc phát hành và gỡ lỗi chỉ được áp dụng khi không có phiên bản nào. Nếu bạn muốn thay đổi biến thể đã xuất bản mặc định trong khi sử dụng phiên bản hương vị, bạn sẽ viết:

android {defaultPublishConfig "flavour1Debug"}


1

Hiện tại thì không thể, mặc dù nếu tôi nhớ chính xác thì đó là một tính năng mà họ muốn thêm vào. (Chỉnh sửa 2: liên kết , liên kết2 )

Chỉnh sửa: Hiện tại, tôi đang sử dụng defaultPublishConfigtùy chọn để khai báo biến thể thư viện nào được xuất bản:

android {
    defaultPublishConfig fullRelease
    defaultPublishConfig demoRelease 
}

1
Vì vậy, mỗi khi tôi định biên dịch ứng dụng, tôi phải thay đổi điều này trong build.gradle của thư viện?
Ali,

Vâng, vâng ... mỗi lần bạn muốn biên dịch ứng dụng với một hương vị khác nhau.
Delblanco

Trên thực tế, khi tôi xác định hương vị cho mô-đun thư viện, gói R kế thừa không được tìm thấy mô-đun ứng dụng.
Ali,

Bạn đã đồng bộ hóa các tệp gradle trong AS?
Delblanco

@Delblanco Điều này có vẻ giống như lao động thủ công và rất dễ hỏng (các nhà phát triển lười biếng và quên sửa đổi các tệp build.gradle của họ).
IgorGanapolsky

1

Tôi biết môn học này đã bị đóng, nhưng chỉ là bản cập nhật với gradle 3.0, hãy xem phần này: https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#variant_aware and grep matchingFallbacksmissingDimensionStrategy. Bây giờ, cách đơn giản hơn để khai báo sự phụ thuộc giữa các hương vị mô-đun.

... và trong trường hợp chính xác này với gradle3.0, vì các hương vị có cùng tên, gradle sẽ ánh xạ chúng một cách kỳ diệu, không cần cấu hình.


Đối với tôi, có vẻ như nội dung được tạo trong thời gian chạy đó bị bỏ qua. Ví dụ như simonvt-> thế hệ sơ đồ không hoạt động nữa với cách mới đối với tôi. : - /
Stefan Sprenger

1

Tôi cũng gặp sự cố khi biên dịch các mô-đun cho các tùy chọn khác nhau.

Những gì tôi đã tìm thấy:

Có vẻ như chúng tôi không cần thêm publishNonDefault truevào build.gradletệp của lib , kể từ Gradle 3.0.1 .

Sau khi dịch ngược một lớp BaseExtensiontìm thấy điều này:

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

Và thay vì:

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

Chúng ta nên sử dụng:

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

Chỉ có điều quan trọng, là thêm một configurations {...}phần vào build.gradle.

Vì vậy, biến thể cuối cùng của build.gradletệp ứng dụng là:

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')
   ...
}

Ngoài ra, bạn có thể sử dụng các biến thể Bộ lọc để hạn chế các biến thể bản dựng.

Ps đừng quên bao gồm các mô-đun trong settings.gradletệp, như:

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

bạn có thể giải thích cách script sẽ xác định thời tiết để đưa thư viện vào một cấu hình nhất định hay không? tôi có nghĩa là tôi có một trường hợp khi tôi cần phải sử dụng một số lib cho một hương vị nào đó, nhưng tôi không cần phải sử dụng nó cho các hương vị khác
Jenya Kirmiza

Không gặp phải tình huống như vậy. Nhưng một hướng dẫn của google developer.android.com/studio/build/dependencies khuyên bạn nên thêm tiền tố trước lệnh "implement" trong khối "dependencies {...}". Tức là các phụ thuộc {payImplementation project (': lib')} hoặc các phụ thuộc {debugImplementation project (': lib')}, hoặc bất kỳ các phụ thuộc kết hợp nhiều biến thể nào {payProdDebugImplementation project (': lib')}. Kiểm tra nó ra và cung cấp cho chúng tôi một phản hồi :)
Sergio
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.