Sử dụng Build Flavours - Cấu trúc các thư mục nguồn và build.gradle chính xác


166

Xin lưu ý: Trả lời được chỉnh sửa sau Câu trả lời của Xavier

Tôi đang cố gắng sử dụng các Hương vị xây dựng khác nhau cho cùng một dự án Ứng dụng trong Android Studio. Tuy nhiên, tôi dường như đang có một thời gian khủng khiếp để cấu hình nó để hoạt động phù hợp.

Các bước:

  1. Tạo Dự án Android Studio mới, được đặt tên là 'Thử nghiệm'.
  2. Mở build.gradle * và thêm các dòng sau:

    productFlavors {
    flavor1 {
        packageName 'com.android.studio.test.flavor1'
        }
    flavor2 {
        packageName 'com.android.studio.test.flavor2'
        }
    }
  3. Sau khi khởi động lại Android Studio, bây giờ tôi thấy 4 biến thể xây dựng trong phần Build Variants. Có nghĩa là chúng tôi đã thành công trong việc thiết lập các hương vị sản phẩm cho đến nay. **
  4. Tạo một thư mục Nguồn mới cho hương vị1 ; tuy nhiên, tôi không chắc liệu tôi có làm đúng cách không. Đây là cách tôi đã làm:

    • Hãy nhớ rằng tên Gói của tôi cho dự án này là: com.foo.test
    • Nhấp chuột phải vào srcthư mục, đối với hương vị1, tôi thực sự đã tạo các thư mục riêng lẻ trong trình thám hiểm, theo cách cấu trúc src/flavor1/java/com/foo/test/MainActivity.java.
    • Ở trên đã hoạt động tốt, vì thư mục 'java' có màu xanh lam , có nghĩa là IDE biết thư mục nguồn đang hoạt động. Ngoài ra, gói đã được tự động tạo ra. Mặc dù vậy, tôi nhận được một cảnh báo cho lớp trùng lặp được tìm thấy. Xem ảnh chụp màn hình ở đây.
    • Đối với hương vị 2, tôi đã thử tạo gói theo cách thủ công, nhưng thư mục 'src' cho hương vị 2 dường như không có màu xanh lam và do đó các tùy chọn khác nhau khi nhấp chuột phải và 'Gói mới' không có sẵn cho tôi sử dụng. Xem hình ảnh ở đây.
    • Lưu ý rằng đối với hương vị1, tôi cũng đã tạo một thư mục 'res', nó chuyển sang màu xanh lam, nhưng mặc dù vậy, nó không cung cấp khả năng tạo tệp Tài nguyên Android hoặc thư mục tài nguyên Andorid, trong trường hợp tôi muốn sử dụng khác resoruces cho các hương vị khác nhau.

Tôi có làm điều gì sai? Hay tôi đang thiếu một cái gì đó? Hãy cho tôi biết nếu bạn cần thêm thông tin.

* Dự án của tôi dường như có hai tệp build.gradle. Một cái nằm ở thư mục gốc của thư mục dự án (\ GradleTest), cái này trống. Cái thứ hai nằm ở thư mục gốc của thư mục con của \ GradleTest, cũng được gắn nhãn 'GradleTest' (GradleTest-GradleTest), đây là cái đã có mã khi mở; do đó, đó là cái tôi đã chỉnh sửa.

** Tôi đã kiểm tra cài đặt lớp và rõ ràng Sử dụng tự động nhập đã được bật. Mặc dù vậy, việc thay đổi tệp build.gradle không tự động cập nhật các biến thể xây dựng. Lưu ý: Tôi cũng đã thử sử dụng Build - Rebuild Project và / hoặc Build - Make Project, no-go. Tôi vẫn phải đóng dự án và mở lại để các thay đổi có hiệu lực.


Lưu ý rằng applicationIdbây giờ là hỗ trợ thay vì packageName.
Hamzeh Soboh

Câu trả lời:


220

Nếu bạn có các tùy chọn Studio, trong phần Gradle, bạn có thể bật tự động nhập cho dự án của mình (chúng tôi sẽ bật tùy chọn này theo mặc định sau). Điều này sẽ cho phép Studio nhập lại build.gradle của bạn bất cứ khi nào bạn chỉnh sửa nó.

Tạo hương vị không có nghĩa là bạn sẽ sử dụng mã tùy chỉnh cho chúng để chúng tôi không tạo các thư mục. Bạn cần phải tự tạo ra chúng.

Nếu bạn nhìn vào bài nói chuyện IO của tôi, bạn sẽ thấy cách chúng ta trộn lẫn các giá trị từ các hương vị và kiểu xây dựng để tạo ra biến thể.

Đối với nguồn Java:

src/main/java
src/flavor1/java
src/debug/java

là cả 3 được sử dụng để tạo ra một đầu ra duy nhất. Điều này có nghĩa là họ không thể định nghĩa cùng một lớp.

Nếu bạn muốn có một phiên bản khác của cùng một loại trong hai hương vị, bạn sẽ cần tạo nó theo cả hai hương vị.

src/flavor1/java/com/foo/A.java
src/flavor2/java/com/foo/A.java

Và sau đó mã của bạn trong src / main / java có thể làm được

import com.foo.A

tùy thuộc vào hương vị được chọn, phiên bản phù hợp của com.foo.A được sử dụng.

Điều này cũng có nghĩa là cả hai phiên bản A phải có cùng một API (ít nhất là khi nói đến API được sử dụng bởi các lớp trong src / main / java / ...

Chỉnh sửa để phù hợp với câu hỏi sửa đổi

Ngoài ra, điều quan trọng là chỉ đặt cùng một lớp A trong các thư mục nguồn loại trừ lẫn nhau. Trong trường hợp này, src / Hương1 / java và src / Hương2 / java không bao giờ được chọn cùng nhau, nhưng chính và hương1 là.

Nếu bạn muốn cung cấp một phiên bản khác của một hoạt động với hương vị khác nhau, đừng đặt nó trong src / main / java.

Xin lưu ý rằng nếu bạn có 3 hương vị và chỉ muốn một hương vị tùy chỉnh cho hương vị1, trong khi hương vị 2 và hương vị 3 chia sẻ cùng một hoạt động, bạn có thể tạo một thư mục nguồn chung cho hai hoạt động khác đó. Bạn hoàn toàn linh hoạt trong việc tạo các thư mục nguồn mới và định cấu hình bộ nguồn để sử dụng chúng.

Về những điểm khác của bạn:

Điều bình thường là thư mục nguồn hương vị thứ 2 không có màu xanh. Bạn cần chuyển sang hương vị thứ 2 để kích hoạt nó, và sau đó bạn sẽ có thể tạo các gói và các lớp bên trong. Cho đến lúc đó, Studio không coi đó là một thư mục nguồn. Chúng tôi sẽ hy vọng cải thiện điều này trong tương lai để làm cho IDE biết những unactive thư mục nguồn.

Tôi nghĩ cũng bình thường khi bạn không thể tạo các tệp tài nguyên trong thư mục res. Hệ thống menu chưa được cập nhật để xử lý tất cả các thư mục tài nguyên bổ sung này. Điều này sẽ đến sau.


1
Tôi đã thêm một số yếu tố mới vào cuối câu trả lời của tôi, nhưng trùng lặp có ý nghĩa. Bạn không thể có cùng một lớp trong cả src / main / java và src / Hương1 / java vì cả hai đều được sử dụng khi chọn hương vị1. Trong câu trả lời của tôi, hãy chú ý cách tôi đặt cùng một lớp chỉ trong hương vị1 / java và Hương2 / java vì đây là độc quyền và không bao giờ được kích hoạt cùng nhau.
Xavier Ducrohet

Này Xavier, bạn có thể cho tôi một mô tả chi tiết hơn về cách tôi có thể sử dụng một phiên bản khác của một hoạt động theo sở thích của mình không? Tôi có một dự án thử nghiệm nơi tôi muốn sử dụng các phiên bản MainActivity khác nhau của mình, nhưng trong cả hai apks (Hương1 và Hương2) chỉ có phiên bản chính / java. Khi tôi không đặt MainActivity bên trong main / java, ứng dụng sẽ gặp sự cố khi tôi khởi động nó.
JensJensen

@XavierDucrohet làm thế nào về việc có các tài nguyên khác nhau cũng như mã khác nhau dựa trên các hương vị, nhưng có chúng trong các mô-đun khác nhau để chúng tôi có thể bao gồm một mô-đun hoặc mô-đun khác dựa trên hương vị, mà không phải trộn mã và tài nguyên trong cùng một dự án gốc? Được hỗ trợ?
Valerio Santinelli

3
@ValerioSantinelli Bạn có thể làm phụ thuộc theo hương vị. Sử dụngflavorCompile ...
Xavier Ducrohet

@XavierDucrohet Tôi đã thử những gì bạn đề xuất nhưng nó không hoạt động như tôi mong đợi. Bạn có thể thấy dự án của tôi được cấu trúc ở đó như thế nào: stackoverflow.com/q/24410995/443136
Valerio Santinelli

19

"Hương vị sản phẩm" trên Android

Đôi khi tôi đã được hỏi về cách làm việc với các máy chủ, biểu tượng hoặc thậm chí tên gói khác nhau, tùy thuộc vào các phiên bản khác nhau của cùng một ứng dụng.

Có rất nhiều lý do để làm điều này và một cách dễ dàng để đi: Hương vị sản phẩm.

Bạn có thể định nghĩa trên tập lệnh build.gradle của mình những loại điều tôi đã mô tả trước đây.

Hương vị sản phẩm Một phần của bài viết này là suy nghĩ bằng văn bản về hương vị sản phẩm, vậy, chúng là gì? Liên quan đến tài liệu Android:

Một hương vị sản phẩm xác định một phiên bản tùy chỉnh của việc xây dựng ứng dụng theo dự án. Một dự án có thể có các hương vị khác nhau làm thay đổi ứng dụng được tạo.

Làm thế nào bạn có thể định nghĩa chúng? Bạn phải viết trên build.gradle của bạn những hương vị bạn muốn xác định:

productFlavors {  
        ...
        devel {
            ...
        }

        prod {
            ...
        }
    }

Bây giờ, chúng tôi sẽ có hai hương vị khác nhau của ứng dụng của chúng tôi. Bạn cũng có thể kiểm tra nó trên Android Studio bên trong tab Build Variants

Xây dựng các biến thể

Nhiều tên gói

Điều gì sẽ xảy ra nếu bạn muốn cài đặt trên điện thoại của mình một ứng dụng có trạng thái phát triển và một cho trạng thái sản xuất. Như bạn có thể biết, bạn chỉ có thể cài đặt một ứng dụng có cùng tên gói (nếu bạn cố cài đặt một số APK mới với cùng một ứng dụng được cài đặt trên điện thoại của bạn, nó sẽ cố gắng cập nhật nó).

Điều duy nhất bạn phải làm là xác định nó trên từng hương vị sản phẩm của bạn:

android {  
    productFlavors {
        devel {
            applicationId "zuul.com.android.devel"
        }
        prod {
            applicationId "zuul.com.android"
        }
    }
}

Gửi yêu cầu đến nhiều máy chủ tùy thuộc vào hương vị Như trước đây, bạn phải bao gồm một số thông số trên trường cấu hình hương vị sản phẩm của bạn.

android {  
    productFlavors {
        devel {
            applicationId "zuul.com.android.devel"
            buildConfigField 'String', 'HOST', '"http://192.168.1.34:3000"'

        }

        prod {
            applicationId "zuul.com.android"
               buildConfigField 'String', 'HOST', '"http://api.zuul.com"'

        }
    }
}

Ví dụ, chúng tôi sẽ cố gắng chỉ cho bạn cách bạn có thể tích hợp điều này với Retrofit để gửi yêu cầu đến máy chủ chiếm dụng mà không xử lý máy chủ nào bạn đang trỏ và dựa trên hương vị. Trong trường hợp này, đây là một đoạn trích của ứng dụng Zuul android:

public class RetrofitModule {

    public ZuulService getRestAdapter() {
        RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint(BuildConfig.HOST)
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .build();
        return restAdapter.create(ZuulService.class);
    }

}

Như bạn có thể thấy bạn chỉ cần sử dụng BuildConfig class để truy cập vào biến bạn vừa xác định.

Bất kỳ biến nào có sẵn thông qua mã của bạn Biến HOST không phải là biến duy nhất bạn có thể hiển thị trong mã của mình. Bạn có thể làm điều đó với bất cứ điều gì bạn muốn:

prod {  
    applicationId "zuul.com.android"
    buildConfigField 'String', 'HOST', '"http://api.zuul.com"'
    buildConfigField 'String', 'FLAVOR', '"prod"'
    buildConfigField "boolean", "REPORT_CRASHES", "true"
}

Bạn có thể truy cập chúng như sau:

BuildConfig.HOST  
BuildConfig.FLAVOR  
BuildConfig.REPORT_CRASHES  

Các biểu tượng khác nhau cho mỗi hương vị Nếu bạn muốn có các biểu tượng khác nhau cho mỗi hương vị, vì vậy bạn có thể phát hiện trực quan cái nào bạn đang mở (bạn cũng có thể làm điều đó bằng tên ... Nhưng nó không thể phù hợp với không gian!), Bạn chỉ cần có để xác định cấu trúc thư mục mới cho mỗi hương vị.

Trong ví dụ tôi vừa sử dụng có hai hương vị: devel và prod. Sau đó, chúng tôi có thể xác định hai cấu trúc thư mục mới để có thể xác định tài nguyên chúng tôi muốn:

kết cấu

Điều này hoạt động với các loại tài nguyên khác như strings.xml, integers.xml, arrays.xml, vv

Cấu hình cài đặt ký

Để cấu hình thủ công các cấu hình ký cho loại bản dựng phát hành của bạn bằng cách sử dụng cấu hình bản dựng Gradle:

1. Tạo một kho khóa. Kho khóa là một tệp nhị phân chứa một tập hợp các khóa riêng. Bạn phải giữ kho khóa của bạn ở một nơi an toàn và an toàn. 2. Tạo một khóa riêng. Khóa riêng đại diện cho thực thể được xác định với ứng dụng, chẳng hạn như một người hoặc một công ty. 3.Thêm cấu hình ký vào tệp build.gradle cấp mô-đun:

android {
...
defaultConfig {...}
signingConfigs {
    release {
        storeFile file("myreleasekey.keystore")
        storePassword "password"
        keyAlias "MyReleaseKey"
        keyPassword "password"
    }
}
buildTypes {
    release {
        ...
        signingConfig signingConfigs.release
    }
}

}

Tạo APK đã ký:

Để tạo APK đã ký, chọn Build> Tạo APK đã ký từ menu chính. Gói trong app / build / apk / app-release.apk hiện được ký với khóa phát hành của bạn.

ref: https://developer.android.com/studio/build/build-variants.html#signing,http://blog.brainattica.com/how-to-work-with-flavours-on-android/



7

Có vẻ như bạn cần tải lại dự án của mình sau khi thêm các hương vị mới vào build.gradle. Sau đó, bạn sẽ thấy 4 Biến thể xây dựng trong chế độ xem Biến thể xây dựng (bạn truy cập nó từ cạnh trái của cửa sổ).

Về các thư mục nguồn bổ sung, có vẻ như bạn cần tạo chúng bằng tay: src/flavor1/javasrc/flavor2/java. Bạn sẽ thấy việc thay đổi hương vị trong chế độ xem "Biến thể xây dựng" sẽ thay đổi các thư mục nguồn hiện đang hoạt động (thư mục có màu xanh khi nó là thư mục nguồn hoạt động )

Cuối cùng, "gradle sẽ tạo sourceSets mới cho hương vị mới của mình" có nghĩa rằng gradle sẽ tạo ra các đối tượng android.sourceSets.flavor1android.sourceSets.flavor2và bạn có thể sử dụng chúng trong kịch bản build.gradle của bạn. Nhưng những đối tượng đó được tạo ra một cách linh hoạt, đó là lý do tại sao bạn không nhìn thấy chúng trong build.gradle(Tôi khuyên bạn nên đọc điều này: http://www.gradle.org/docs/civerse/userguide/tutorial_USE_t Nhiệm.html Đặc biệt là 6.6: nó giải thích tạo tác vụ động. Tập lệnh gradle là tập lệnh Groovy, vì vậy tôi khuyên bạn cũng nên làm quen với Groovy)


2
Tôi nghĩ rằng ghi chú nhập khẩu là Build VariantsChế độ xem, tôi đã không nhận thấy điều đó.
Chris.Jenkins

2

Tôi gặp vấn đề tương tự khi tôi chuyển dự án của mình sang Gradle. Vấn đề là bản dựng không tìm thấy thư mục tài nguyên phù hợp. Tôi đã sửa nó bằng cách thêm phần tử này vào phần tử android trong build.gradle:

sourceSets {
        main {
            res.srcDirs = ['myProject/res']
        }
    }

0

Một điều quan trọng và cản trở tôi khá lâu là tên hương vị cần khớp với gói trái ngược với gói được định nghĩa bên trong định nghĩa hương vị trong lớp. Ví dụ:

src/flavor1/java/com/foo/A.java

sẽ phù hợp

productFlavors {
  flavor1 {
    packageName 'com.android.studio.test.foobar'
  }
}

nhưng

src/foobar/java/com/foo/A.java sẽ không được sử dụng để xây dựng hương vị1.


0

Trong lớp:

Đối với các kiểu xây dựng, bạn chỉ cần:

buildTypes {
   release{
    //proguard, signing etc.
   }
   debug {
    //development
   }
  }
}

Và sau đó cho hương vị bạn thêm những thứ bạn cần

productFlavors {
    pro {
        applicationIdSuffix '.paid'
        buildConfigField 'boolean', 'PRO', 'true'
    }
    free {
        applicationIdSuffix '.free'
        buildConfigField 'boolean', 'PRO', 'false'
    }
}
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.