Skonfiguruj warianty kompilacji

Na tej stronie dowiesz się, jak skonfigurować warianty kompilacji, aby tworzyć różne wersje aplikacji z jednego projektu, oraz jak prawidłowo zarządzać zależnościami i konfiguracjami podpisywania.

Każdy wariant kompilacji reprezentuje inną wersję aplikacji, którą możesz stworzyć. Możesz na przykład utworzyć jedną wersję aplikacji – bezpłatną z ograniczonym zestawem treści, a drugą wersję płatną, która zawiera więcej treści. Możesz też tworzyć różne wersje aplikacji kierowane na różne urządzenia w zależności od poziomu interfejsu API lub innych odmian urządzeń.

Warianty kompilacji to wynik działania narzędzia Gradle korzystającego z określonego zestawu reguł do łączenia ustawień, kodu i zasobów skonfigurowanych w typach kompilacji i rodzajach usług. Chociaż nie konfigurujesz wersji kompilacji bezpośrednio, konfigurujesz typy kompilacji i smaki usług, które je tworzące.

Na przykład rodzaj produktu „demonstracyjny” może określać pewne funkcje i wymagania dotyczące urządzeń, takie jak niestandardowy kod źródłowy, zasoby i minimalne poziomy interfejsu API, a typ kompilacji „debugowanie” stosuje różne ustawienia kompilacji i opakowania, takie jak opcje debugowania i klucze podpisywania. Wariant kompilacji, który łączy te 2 funkcje, to wersja „demoDebug” Twojej aplikacji. Zawiera też kombinację konfiguracji i zasobów zawartych w odmianie produktu „demonstracyjnej”, typu „debugowanie” oraz zbiorze źródeł main/.

Konfigurowanie typów kompilacji

Typy kompilacji możesz tworzyć i konfigurować w bloku android pliku build.gradle.kts na poziomie modułu. Gdy tworzysz nowy moduł, Android Studio automatycznie tworzy typy kompilacji do debugowania i publikowania. Chociaż typu kompilacji do debugowania nie ma w pliku konfiguracji kompilacji, Android Studio konfiguruje go w debuggable true. Dzięki temu możesz debugować aplikację na bezpiecznych urządzeniach z Androidem i skonfigurować podpisywanie aplikacji przy użyciu ogólnego magazynu kluczy debugowania.

Jeśli chcesz dodać lub zmienić określone ustawienia, możesz dodać do konfiguracji typ kompilacji do debugowania. Poniższy przykład określa applicationIdSuffix dla typu kompilacji do debugowania i konfiguruje „etapowy” typ kompilacji zainicjowany za pomocą ustawień z typu kompilacji do debugowania:

Kotlin

android {
    defaultConfig {
        manifestPlaceholders["hostName"] = "www.example.com"
        ...
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
        }

        getByName("debug") {
            applicationIdSuffix = ".debug"
            isDebuggable = true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        create("staging") {
            initWith(getByName("debug"))
            manifestPlaceholders["hostName"] = "internal.example.com"
            applicationIdSuffix = ".debugStaging"
        }
    }
}

Odlotowy

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
        ...
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        staging {
            initWith debug
            manifestPlaceholders = [hostName:"internal.example.com"]
            applicationIdSuffix ".debugStaging"
        }
    }
}

Uwaga: gdy wprowadzasz zmiany w pliku konfiguracji kompilacji, Android Studio wymaga zsynchronizowania projektu z nową konfiguracją. Aby zsynchronizować projekt, kliknij Synchronizuj teraz na pasku powiadomień, który pojawi się po wprowadzeniu zmiany, lub Synchronizuj projekt na pasku narzędzi. Jeśli Android Studio wykryje błędy w konfiguracji, pojawi się okno Wiadomości z opisem problemu.

Więcej informacji o wszystkich właściwościach, które można konfigurować w typach kompilacji, znajdziesz w dokumentacji BuildType.

Skonfiguruj smaki produktów

Tworzenie smaków usług przypomina tworzenie typów kompilacji. Dodaj smaki usług do bloku productFlavors w konfiguracji kompilacji i uwzględnij odpowiednie ustawienia. Smaki produktów obsługują te same właściwości co defaultConfig, ponieważ defaultConfig należy do klasy ProductFlavor. Oznacza to, że możesz podać konfigurację podstawową dla wszystkich rodzajów w bloku defaultConfig, a każdy smak może zmienić dowolną z tych wartości domyślnych, taką jak applicationId. Więcej informacji o identyfikatorze aplikacji znajdziesz w artykule Ustawianie identyfikatora aplikacji.

Uwaga: nadal musisz określić nazwę pakietu za pomocą atrybutu package w pliku manifestu main/. Musisz też używać tej nazwy pakietu w kodzie źródłowym, aby odwołać się do klasy R lub rozwiązać względną aktywność lub rejestrację usługi. Dzięki temu możesz użyć właściwości applicationId, aby nadać każdemu smakowi unikalny identyfikator opakowania i dystrybucji bez konieczności zmiany kodu źródłowego.

Wszystkie smaki muszą należeć do nazwanego wymiaru smaku, który jest grupą smaków produktu. Musisz przypisać wszystkie smaki do wymiaru smaku. W przeciwnym razie wystąpi ten błąd kompilacji.

  Error: All flavors must now belong to a named flavor dimension.
  The flavor 'flavor_name' is not assigned to a flavor dimension.

Jeśli dany moduł ma określony tylko 1 wymiar typu, wtyczka Androida do obsługi Gradle automatycznie przypisze do niego wszystkie smaki modułu.

Poniższy przykładowy kod tworzy wymiar smaku o nazwie „wersja” i dodaje smaki produktu „wersja demonstracyjna” i „pełna”. Te smaki mają własne właściwości applicationIdSuffix i versionNameSuffix:

Kotlin

android {
    ...
    defaultConfig {...}
    buildTypes {
        getByName("debug"){...}
        getByName("release"){...}
    }
    // Specifies one flavor dimension.
    flavorDimensions += "version"
    productFlavors {
        create("demo") {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension = "version"
            applicationIdSuffix = ".demo"
            versionNameSuffix = "-demo"
        }
        create("full") {
            dimension = "version"
            applicationIdSuffix = ".full"
            versionNameSuffix = "-full"
        }
    }
}

Odlotowy

android {
    ...
    defaultConfig {...}
    buildTypes {
        debug{...}
        release{...}
    }
    // Specifies one flavor dimension.
    flavorDimensions "version"
    productFlavors {
        demo {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension "version"
            applicationIdSuffix ".demo"
            versionNameSuffix "-demo"
        }
        full {
            dimension "version"
            applicationIdSuffix ".full"
            versionNameSuffix "-full"
        }
    }
}

Uwaga: jeśli masz starszą aplikację (utworzoną przed sierpniem 2021 r.), która rozpowszechniasz za pomocą plików APK w Google Play, to aby rozpowszechniać ją w Google Play z wykorzystaniem obsługi wielu plików APK, przypisz tę samą wartość applicationId do wszystkich wariantów, a każdym z nich przypisz inną wartość versionCode. Aby dystrybuować różne wersje aplikacji jako osobne aplikacje w Google Play, do każdego z nich musisz przypisać inną właściwość applicationId.

Gdy utworzysz i skonfigurujesz smaki usług, kliknij Synchronizuj teraz na pasku powiadomień. Po zakończeniu synchronizacji Gradle automatycznie tworzy warianty kompilacji na podstawie typów kompilacji i smaków usług i nadaje im nazwy zgodnie z <product-flavor><Build-Type>. Jeśli na przykład utworzysz „demonstracyjne” i „pełne” wersje usług oraz zachowasz domyślne typy kompilacji „debugowanie” i „wersja”, Gradle utworzy te wersje kompilacji:

  • demoDebug
  • demoRelease
  • fullDebug
  • fullRelease

Aby wybrać wariant kompilacji do skompilowania i uruchomienia, kliknij Kompilacja > Wybierz wariant kompilacji i wybierz z menu wariant kompilacji. Aby zacząć dostosowywać każdy wariant kompilacji za pomocą własnych funkcji i zasobów, musisz utworzyć zbiory źródłowe i nimi zarządzać w sposób opisany na tej stronie.

Zmiana identyfikatora aplikacji dla wariantów kompilacji

Gdy tworzysz pakiet APK lub AAB dla swojej aplikacji, narzędzia do kompilacji oznaczają ją identyfikatorem aplikacji zdefiniowanym w bloku defaultConfig w pliku build.gradle.kts, jak pokazano w poniższym przykładzie. Jeśli jednak chcesz, by różne wersje aplikacji wyświetlały się jako osobne strony w Sklepie Google Play, np. „bezpłatna” i „pro”, musisz utworzyć osobne warianty kompilacji, z których każda będzie mieć inny identyfikator aplikacji.

W takim przypadku zdefiniuj każdą wersję kompilacji jako osobny rodzaj usługi. W przypadku każdego rodzaju wewnątrz bloku productFlavors możesz ponownie zdefiniować właściwość applicationId lub zamiast tego możesz dołączyć segment do domyślnego identyfikatora aplikacji za pomocą metody applicationIdSuffix, jak w tym przykładzie:

Kotlin

android {
    defaultConfig {
        applicationId = "com.example.myapp"
    }
    productFlavors {
        create("free") {
            applicationIdSuffix = ".free"
        }
        create("pro") {
            applicationIdSuffix = ".pro"
        }
    }
}

Odlotowy

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    productFlavors {
        free {
            applicationIdSuffix ".free"
        }
        pro {
            applicationIdSuffix ".pro"
        }
    }
}

Dzięki temu identyfikator aplikacji dla odmiany produktu „bezpłatnego” to „com.example.mojaaplikacja.bezpłatna”.

Możesz też użyć funkcji applicationIdSuffix, aby dołączyć segment na podstawie typu kompilacji, jak pokazano tutaj:

Kotlin

android {
    ...
    buildTypes {
        getByName("debug") {
            applicationIdSuffix = ".debug"
        }
    }
}

Odlotowy

android {
    ...
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
        }
    }
}

Gradle stosuje konfigurację typu kompilacji po rodzaju usługi, więc identyfikator aplikacji dla wariantu kompilacji „bezpłatne debugowanie” to „com.example.mojaaplikacja.bezpłatna.debug”. Jest to przydatne, gdy chcesz mieć zarówno debugowanie, jak i kompilację wersji na tym samym urządzeniu, ponieważ żadna 2 aplikacje nie mogą mieć tego samego identyfikatora.

Jeśli masz starszą aplikację (utworzoną przed sierpniem 2021 r.), którą rozpowszechniasz za pomocą plików APK w Google Play i chcesz używać tych samych informacji o aplikacji, aby rozpowszechniać wiele plików APK przeznaczonych na inną konfigurację urządzenia, np. poziom interfejsu API, musisz używać tego samego identyfikatora aplikacji w przypadku każdej kompilacji, ale każdemu plikowi APK nadać inny versionCode. Więcej informacji znajdziesz w artykule Obsługa wielu plików APK. Nie ma to wpływu na publikowanie z użyciem pakietów aplikacji, ponieważ domyślnie używany jest 1 artefakt, który domyślnie używa jednego kodu wersji i identyfikatora aplikacji.

Wskazówka: jeśli w pliku manifestu musisz odwołać się do identyfikatora aplikacji, możesz użyć zmiennej ${applicationId} w dowolnym atrybucie manifestu. Podczas kompilacji Gradle zastępuje ten tag rzeczywistym identyfikatorem aplikacji. Więcej informacji znajdziesz w sekcji Wstawianie zmiennych kompilacji do pliku manifestu.

Łączenie różnych smaków produktów z wymiarami smaku

W niektórych przypadkach możesz chcieć połączyć konfiguracje różnych rodzajów usług. Możesz na przykład utworzyć różne konfiguracje smaków produktu „pełnej” i „demonstracyjnej” na podstawie poziomu interfejsu API. W tym celu wtyczka Androida do obsługi Gradle umożliwia tworzenie wielu grup rodzajów produktów jako wymiarów.

Podczas tworzenia aplikacji Gradle łączy konfigurację smaku produktu z każdego zdefiniowanego przez Ciebie wymiaru smaku oraz konfigurację typu kompilacji, aby utworzyć ostateczny wariant kompilacji. Gradle nie łączy smaków produktów należących do tego samego wymiaru smaku.

W tym przykładowym kodzie użyto właściwości flavorDimensions do utworzenia wymiaru smaku „mode” do grupowania smaków produktu „pełny” i „demonstracyjny” oraz wymiaru smaku „api” do grupowania konfiguracji smaku produktu na podstawie poziomu interfejsu API:

Kotlin

android {
  ...
  buildTypes {
    getByName("debug") {...}
    getByName("release") {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions += listOf("api", "mode")

  productFlavors {
    create("demo") {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension = "mode"
      ...
    }

    create("full") {
      dimension = "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    create("minApi24") {
      dimension = "api"
      minSdk = 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.
      versionCode = 30000 + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi24"
      ...
    }

    create("minApi23") {
      dimension = "api"
      minSdk = 23
      versionCode = 20000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi23"
      ...
    }

    create("minApi21") {
      dimension = "api"
      minSdk = 21
      versionCode = 10000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi21"
      ...
    }
  }
}
...

Odlotowy

android {
  ...
  buildTypes {
    debug {...}
    release {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions "api", "mode"

  productFlavors {
    demo {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension "mode"
      ...
    }

    full {
      dimension "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    minApi24 {
      dimension "api"
      minSdkVersion 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.

      versionCode 30000 + android.defaultConfig.versionCode
      versionNameSuffix "-minApi24"
      ...
    }

    minApi23 {
      dimension "api"
      minSdkVersion 23
      versionCode 20000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi23"
      ...
    }

    minApi21 {
      dimension "api"
      minSdkVersion 21
      versionCode 10000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi21"
      ...
    }
  }
}
...

Liczba wariantów kompilacji utworzonych przez Gradle jest równa iloczynowi liczby smaków w każdym wymiarze smaku i liczby skonfigurowanych typów kompilacji. Gdy Gradle nadaje nazwy poszczególnym wariantom kompilacji lub odpowiednim artefaktom, jako pierwsze pojawiają się smaki usług należące do wymiaru rodzaju o wyższym priorytecie, a na końcu te z wymiarów o niższym priorytecie, a na końcu typ kompilacji.

Korzystając z poprzedniej konfiguracji kompilacji, Gradle tworzy łącznie 12 wariantów kompilacji o następującym schemacie nazewnictwa:

  • Wariant kompilacji: [minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
  • Powiązany plik APK: app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
  • Na przykład
    Utwórz wariant: minApi24DemoDebug
    Odpowiedni plik APK: app-minApi24-demo-debug.apk

Oprócz katalogów zbioru źródłowego, które możesz utworzyć dla poszczególnych rodzajów produktu i wariantu kompilacji, możesz też utworzyć katalogi zbioru źródłowego dla każdej kombinacji smaków produktu. Możesz na przykład utworzyć źródła Java i dodać je do katalogu src/demoMinApi24/java/, a Gradle będzie używać tych źródeł tylko podczas tworzenia wariantu łączącego te 2 rodzaje produktów.

Zbiory źródłowe utworzone dla kombinacji smaków produktów mają wyższy priorytet niż zbiory źródłowe należące do poszczególnych smaków produktu. Więcej informacji o zbiorach źródłowych i sposobie scalania zasobów przez Gradle znajdziesz w sekcji poświęconej tworzeniu zbiorów źródłowych.

Filtruj warianty

Gradle tworzy wariant kompilacji dla każdej możliwej kombinacji smaków usługi i skonfigurowanych przez Ciebie typów kompilacji. Mogą jednak być pewne warianty kompilacji, których nie potrzebujesz lub które nie mają sensu w kontekście Twojego projektu. Aby usunąć określone konfiguracje wariantów kompilacji, utwórz filtr wariantów w pliku build.gradle.kts na poziomie modułu.

Używając jako przykładu konfiguracji kompilacji z poprzedniej sekcji, załóżmy, że w wersji demonstracyjnej aplikacji zamierzasz obsługiwać tylko interfejsy API na poziomach 23 i wyższym. Możesz użyć bloku variantFilter, aby odfiltrować wszystkie konfiguracje wariantów kompilacji, które łączą różne smaki usług „minApi21” i „demonstracyjny”:

Kotlin

android {
  ...
  buildTypes {...}

  flavorDimensions += listOf("api", "mode")
  productFlavors {
    create("demo") {...}
    create("full") {...}
    create("minApi24") {...}
    create("minApi23") {...}
    create("minApi21") {...}
  }
}

androidComponents {
    beforeVariants { variantBuilder ->
        // To check for a certain build type, use variantBuilder.buildType == "<buildType>"
        if (variantBuilder.productFlavors.containsAll(listOf("api" to "minApi21", "mode" to "demo"))) {
            // Gradle ignores any variants that satisfy the conditions above.
            variantBuilder.enable = false
        }
    }
}
...

Odlotowy

android {
  ...
  buildTypes {...}

  flavorDimensions "api", "mode"
  productFlavors {
    demo {...}
    full {...}
    minApi24 {...}
    minApi23 {...}
    minApi21 {...}
  }

  variantFilter { variant ->
      def names = variant.flavors*.name
      // To check for a certain build type, use variant.buildType.name == "<buildType>"
      if (names.contains("minApi21") && names.contains("demo")) {
          // Gradle ignores any variants that satisfy the conditions above.
          setIgnore(true)
      }
  }
}
...

Gdy dodasz do konfiguracji kompilacji filtr wariantów i klikniesz Synchronizuj teraz na pasku powiadomień, Gradle zignoruje wszystkie warianty kompilacji spełniające określone przez Ciebie warunki. Warianty kompilacji nie pojawiają się już w menu, gdy na pasku menu klikniesz Kompilacja > Wybierz wariant kompilacji lub na pasku okna narzędzi klikniesz Warianty kompilacji .

Tworzenie zbiorów źródłowych

Domyślnie Android Studio tworzy zbiór źródłowy i katalogi main/ wszystkich elementów, które chcesz udostępnić między wszystkimi wariantami kompilacji. Możesz jednak tworzyć nowe zbiory źródłowe, aby dokładnie kontrolować, które pliki Gradle kompilują i pakiety pod kątem określonych typów kompilacji, smaków produktów, kombinacji smaków produktów (jeśli używasz wymiarów rodzajów) oraz wariantów kompilacji.

Możesz na przykład zdefiniować podstawowe funkcje w zbiorze źródłowym main/ i użyć zestawów źródeł smaków produktu, aby zmienić markę aplikacji u różnych klientów lub uwzględnić specjalne uprawnienia i funkcje logowania tylko w przypadku wersji kompilacji, które korzystają z typu kompilacji do debugowania.

Gradle wymaga, aby pliki i katalogi zestawu źródeł były uporządkowane w określony sposób, podobnie jak w przypadku zbioru źródłowego main/. Na przykład Gradle oczekuje, że pliki klas Kotlin lub Java, które są specyficzne dla Twojego typu kompilacji „debug”, będą znajdować się w katalogu src/debug/kotlin/ lub src/debug/java/.

Wtyczka Androida do obsługi Gradle udostępnia przydatne zadanie Gradle, które pokazuje, jak porządkować pliki pod kątem poszczególnych typów kompilacji, smaków usług i wersji kompilacji. Na przykład ten przykład z danych wyjściowych zadania opisuje, gdzie Gradle spodziewa się znaleźć określone pliki dla typu kompilacji „debuguj”:

------------------------------------------------------------
Project :app
------------------------------------------------------------

...

debug
----
Compile configuration: debugCompile
build.gradle name: android.sourceSets.debug
Java sources: [app/src/debug/java]
Kotlin sources: [app/src/debug/kotlin, app/src/debug/java]
Manifest file: app/src/debug/AndroidManifest.xml
Android resources: [app/src/debug/res]
Assets: [app/src/debug/assets]
AIDL sources: [app/src/debug/aidl]
RenderScript sources: [app/src/debug/rs]
JNI sources: [app/src/debug/jni]
JNI libraries: [app/src/debug/jniLibs]
Java-style resources: [app/src/debug/resources]

Aby wyświetlić te dane, wykonaj te czynności:

  1. Kliknij Gradle na pasku okna narzędzi.
  2. Otwórz MyApplication > Lista zadań > Android i kliknij dwukrotnie sourceSets.

    Aby wyświetlić folder Lista zadań, musisz pozwolić Gradle na skompilowanie listy zadań podczas synchronizacji. Aby to zrobić:

    1. Kliknij Plik > Ustawienia > Eksperymentalne (Android Studio > Ustawienia > Eksperymentalne w systemie macOS).
    2. Odznacz Nie buduj listy zadań Gradle podczas synchronizacji z Gradle.
  3. Gdy Gradle wykona zadanie, otworzy się okno Uruchom z danymi wyjściowymi.

Uwaga: dane wyjściowe zadania pokazują też, jak uporządkować zbiory źródłowe plików, których chcesz użyć do testowania aplikacji, takich jak zestawy źródeł testowych test/ i androidTest/.

Gdy tworzysz nowy wariant kompilacji, Android Studio nie tworzy za Ciebie katalogów zestawu źródłowego, ale udostępnia kilka opcji, które mogą Ci pomóc. Aby np. utworzyć tylko katalog java/ dla typu kompilacji „debuguj”:

  1. Otwórz panel Projekt i w menu u góry panelu wybierz widok Projekt.
  2. Wejdź na MyProject/app/src/.
  3. Kliknij prawym przyciskiem myszy katalog src i wybierz Nowy > Katalog.
  4. W menu w sekcji Gradle Source Sets (Zbiory źródłowe Gradle) wybierz full/java.
  5. Naciśnij Enter.

Android Studio utworzy katalog źródłowy dla typu kompilacji do debugowania, a następnie utworzy w nim katalog java/. Android Studio może też utworzyć dla Ciebie katalogi podczas dodawania do projektu nowego pliku dla określonego wariantu kompilacji.

Aby np. utworzyć plik XML z wartościami dla typu kompilacji „debuguj”:

  1. W panelu Projekt kliknij prawym przyciskiem myszy katalog src i wybierz Nowy > XML > Plik XML wartości.
  2. Wpisz nazwę pliku XML lub zachowaj domyślną nazwę.
  3. W menu obok pozycji Zbiór źródeł docelowych wybierz debugowanie.
  4. Kliknij Zakończ.

Jako docelowy zestaw źródeł określono typ kompilacji „debug”, dlatego Android Studio automatycznie tworzy niezbędne katalogi podczas tworzenia pliku XML. Wynikowa struktura katalogów wygląda jak na ilustracji 1.

Rysunek 1. Nowe katalogi zbioru źródłowego dla typu kompilacji „debug”.

Aktywne zestawy źródeł mają zielony wskaźnik przy ikonie, który wskazuje, że są aktywne. Zbiór źródłowy debug ma sufiks [main], który wskazuje, że zostanie scalony ze zbiorem źródłowym main.

Korzystając z tej samej procedury, możesz też utworzyć katalogi źródeł zbioru dla rodzajów usług, np. src/demo/, i wariantów kompilacji, np. src/demoDebug/. Możesz też tworzyć testowe zbiory źródłowe kierowane na określone warianty kompilacji, np. src/androidTestDemoDebug/. Więcej informacji znajdziesz w artykule o testowaniu zbiorów źródeł.

Zmiana domyślnych konfiguracji zestawu źródeł

Jeśli masz źródła, które nie są uporządkowane według domyślnej struktury plików zestawu źródeł, której oczekuje Gradle, tak jak to opisano w poprzedniej sekcji dotyczącej tworzenia zestawów źródłowych, możesz użyć bloku sourceSets, aby zmienić miejsce, w którym Gradle szuka plików związanych z każdym komponentem zbioru źródłowego.

Blok sourceSets musi być w bloku android. Nie musisz przenosić plików źródłowych. Wystarczy, że podasz do Gradle ścieżki powiązane z plikiem build.gradle.kts na poziomie modułu, gdzie Gradle może znaleźć pliki dla każdego komponentu zestawu źródłowego. Informacje o tym, które komponenty możesz skonfigurować i czy da się je zmapować na wiele plików lub katalogów, znajdziesz w dokumentacji interfejsu API wtyczki Androida do obsługi Gradle.

Następujący przykładowy kod mapuje źródła z katalogu app/other/ na niektóre komponenty zbioru źródłowego main i zmienia katalog główny zbioru źródłowego androidTest:

Kotlin

android {
  ...
  // Encapsulates configurations for the main source set.
  sourceSets.getByName("main") {
    // Changes the directory for Java sources. The default directory is
    // 'src/main/java'.
    java.setSrcDirs(listOf("other/java"))

    // If you list multiple directories, Gradle uses all of them to collect
    // sources. Because Gradle gives these directories equal priority, if
    // you define the same resource in more than one directory, you receive an
    // error when merging resources. The default directory is 'src/main/res'.
    res.setSrcDirs(listOf("other/res1", "other/res2"))

    // Note: Avoid specifying a directory that is a parent to one
    // or more other directories you specify. For example, avoid the following:
    // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
    // Specify either only the root 'other/res1' directory or only the
    // nested 'other/res1/layouts' and 'other/res1/strings' directories.

    // For each source set, you can specify only one Android manifest.
    // By default, Android Studio creates a manifest for your main source
    // set in the src/main/ directory.
    manifest.srcFile("other/AndroidManifest.xml")
    ...
  }

  // Create additional blocks to configure other source sets.
  sourceSets.getByName("androidTest") {
      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot("src/tests")
      ...
  }
}
...

Odlotowy

android {
  ...
  sourceSets {
    // Encapsulates configurations for the main source set.
    main {
      // Changes the directory for Java sources. The default directory is
      // 'src/main/java'.
      java.srcDirs = ['other/java']

      // If you list multiple directories, Gradle uses all of them to collect
      // sources. Because Gradle gives these directories equal priority, if
      // you define the same resource in more than one directory, you receive an
      // error when merging resources. The default directory is 'src/main/res'.
      res.srcDirs = ['other/res1', 'other/res2']

      // Note: Avoid specifying a directory that is a parent to one
      // or more other directories you specify. For example, avoid the following:
      // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
      // Specify either only the root 'other/res1' directory or only the
      // nested 'other/res1/layouts' and 'other/res1/strings' directories.

      // For each source set, you can specify only one Android manifest.
      // By default, Android Studio creates a manifest for your main source
      // set in the src/main/ directory.
      manifest.srcFile 'other/AndroidManifest.xml'
      ...
    }

    // Create additional blocks to configure other source sets.
    androidTest {

      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot 'src/tests'
      ...
    }
  }
}
...

Pamiętaj, że katalog źródłowy może należeć tylko do jednego zbioru źródłowego. Nie możesz na przykład udostępniać tych samych źródeł testowych zarówno zbiorowi źródłowemu test, jak i androidTest. Wynika to z faktu, że Android Studio tworzy osobne moduły IntelliJ dla każdego zbioru źródłowego i nie może obsługiwać zduplikowanych katalogów głównych treści w różnych zbiorach źródłowych.

Utwórz z użyciem zbiorów źródłowych

Możesz użyć katalogów zbioru źródłowego, aby uwzględnić kod i zasoby, które chcesz spakować tylko z określonymi konfiguracjami. Jeśli na przykład tworzysz wariant kompilacji „demoDebug”, który jest usługą wieloprodukcyjną dla typu „demonstracyjnego” i typu kompilacji „debugowania”, Gradle sprawdza te katalogi i nadaje im taki priorytet:

  1. src/demoDebug/ (zestaw źródeł wariantu kompilacji)
  2. src/debug/ (zestaw źródłowy typu kompilacji)
  3. src/demo/ (zestaw źródeł rodzaju produktu)
  4. src/main/ (główny zestaw źródeł)

Zbiory źródłowe utworzone dla kombinacji smaków produktów muszą zawierać wszystkie wymiary smaków. Na przykład zestaw źródeł wariantu kompilacji musi być kombinacją typu kompilacji i wszystkich wymiarów dotyczących smaku. Scalanie kodu i zasobów obejmujących foldery, które obejmują wiele wymiarów rodzajów, ale nie wszystkie, nie jest obsługiwane.

Jeśli łączysz kilka smaków produktów, priorytet między smakami jest określany na podstawie wymiaru smaku, do którego należą. Gdy podajesz wymiary smaku za pomocą właściwości android.flavorDimensions, smaki produktów należące do pierwszego z wymienionych na liście wymiarów smaków mają wyższy priorytet niż te należące do drugiego wymiaru smaku itd. Dodatkowo zestawy źródeł utworzone dla kombinacji smaków produktów mają wyższy priorytet niż zbiory źródłowe, które należą do określonego rodzaju produktu.

Kolejność priorytetów określa, który zbiór źródłowy ma wyższy priorytet, gdy Gradle łączy kod i zasoby. Katalog zestawu źródeł demoDebug/ prawdopodobnie zawiera pliki specyficzne dla tego wariantu kompilacji, dlatego jeśli demoDebug/ zawiera plik zdefiniowany też w obiekcie debug/, Gradle użyje tego pliku ze zbioru źródłowego demoDebug/. Podobnie Gradle nadaje plikom w źródle kompilacji i rodzaju produktu wyższy priorytet niż te same pliki w main/. Gradle uwzględnia tę kolejność priorytetów podczas stosowania tych reguł kompilacji:

  • Cały kod źródłowy w katalogach kotlin/ lub java/ jest skompilowany w celu wygenerowania pojedynczego wyniku.

    Uwaga: w przypadku danego wariantu kompilacji Gradle zgłasza błąd kompilacji, jeśli napotka co najmniej 2 katalogi zbioru źródłowego, które zdefiniowały tę samą klasę Kotlin lub Java. Na przykład podczas tworzenia aplikacji do debugowania nie możesz zdefiniować zarówno src/debug/Utility.kt, jak i src/main/Utility.kt, ponieważ Gradle analizuje oba te katalogi podczas procesu kompilacji i generuje błąd „zduplikowanej klasy”. Jeśli chcesz mieć różne wersje Utility.kt na potrzeby różnych typów kompilacji, każdy typ kompilacji musi definiować własną wersję pliku i nie może jej uwzględniać w zbiorze źródłowym main/.

  • Pliki manifestu są scalane w jeden plik. Priorytety są podawane w takiej samej kolejności jak w przypadku listy w poprzednim przykładzie. Oznacza to, że ustawienia pliku manifestu dotyczące typu kompilacji zastępują ustawienia pliku manifestu w przypadku rodzaju produktu itd. Więcej informacji znajdziesz w artykule o scalaniu plików manifestu.
  • Pliki w katalogach values/ zostaną scalone. Jeśli 2 pliki mają taką samą nazwę, np. 2 pliki strings.xml, priorytet jest podawany w tej samej kolejności co w przypadku listy w poprzednim przykładzie. Oznacza to, że wartości zdefiniowane w pliku w zbiorze źródłowym typu kompilacji zastępują wartości zdefiniowane w tym samym pliku w rodzaju produktu itd.
  • Zasoby w katalogach res/ i asset/ są spakowane razem. Jeśli istnieją zasoby o tej samej nazwie zdefiniowane w co najmniej 2 zbiorach źródłowych, priorytet jest przypisywany w tej samej kolejności co lista w poprzednim przykładzie.
  • Podczas tworzenia aplikacji Gradle nadaje zasobom i plikom manifestu dołączonym do zależności modułu biblioteki najniższy priorytet.

Deklarowanie zależności

Aby skonfigurować zależność dla określonego wariantu kompilacji lub testowego zbioru źródeł, przed słowem kluczowym Implementation dodaj na początku nazwę wariantu kompilacji lub zestawu źródeł testowych przed słowem kluczowym Implementation:

Kotlin

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    "freeImplementation"(project(":mylibrary"))

    // Adds a remote binary dependency only for local tests.
    testImplementation("junit:junit:4.12")

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation("com.android.support.test.espresso:espresso-core:3.5.1")
}

Odlotowy

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    freeImplementation project(":mylibrary")

    // Adds a remote binary dependency only for local tests.
    testImplementation 'junit:junit:4.12'

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.5.1'
}

Więcej informacji o konfigurowaniu zależności znajdziesz w artykule o dodawaniu zależności kompilacji.

Używaj zarządzania zależnościami zależnymi od wariantów

Wtyczka Androida do obsługi Gradle w wersji 3.0.0 lub nowszej zawiera nowy mechanizm zależności, który automatycznie dopasowuje warianty podczas korzystania z biblioteki. Oznacza to, że wariant aplikacji debug automatycznie wykorzystuje wariant debug biblioteki itd. Działa też w przypadku korzystania ze smaków: wariant freeDebug aplikacji będzie korzystać z wariantu freeDebug biblioteki.

Aby wtyczka dokładnie pasowała do wariantów, musisz podać pasujące wartości zastępcze zgodnie z opisem w poniższej sekcji. Pojawia się ono w przypadkach, gdy dopasowanie bezpośrednie jest niemożliwe.

Załóżmy na przykład, że Twoja aplikacja konfiguruje typ kompilacji o nazwie „etap przejściowy”, ale jedna z zależności od biblioteki go nie ma. Gdy wtyczka będzie próbowała utworzyć wersję testową aplikacji, nie będzie wiedzieć, której wersji biblioteki użyć, i zobaczysz komunikat o błędzie podobny do tego:

Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
    project :app

Popraw błędy kompilacji związane z dopasowaniem wariantów

Wtyczka zawiera elementy DSL, które pomagają kontrolować sposób, w jaki Gradle rozpoznaje sytuacje, w których bezpośrednie dopasowanie wariantu aplikacji i zależności nie jest możliwe.

Poniżej znajdziesz listę problemów związanych z dopasowywaniem zależności z uwzględnieniem wariantów oraz sposoby ich rozwiązywania za pomocą właściwości DSL:

  • Aplikacja zawiera typ kompilacji, który nie występuje w zależności od biblioteki.

    Na przykład aplikacja zawiera typ kompilacji „staging”, ale zależność obejmuje tylko typy kompilacji „debug” i „release”.

    Uwaga: jeśli zależność biblioteki obejmuje typ kompilacji, którego nie ma Twoja aplikacja, nie występuje żaden problem. Dzieje się tak, ponieważ wtyczka nigdy nie wysyła z zależności tego typu kompilacji.

    Użyj matchingFallbacks, aby określić alternatywne dopasowania dla danego typu kompilacji:

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        buildTypes {
            getByName("debug") {}
            getByName("release") {}
            create("staging") {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks += listOf("debug", "qa", "release")
            }
        }
    }

    Odlotowy

    // In the app's build.gradle file.
    android {
        buildTypes {
            debug {}
            release {}
            staging {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks = ['debug', 'qa', 'release']
            }
        }
    }
    
  • W przypadku danego wymiaru smaku, który istnieje zarówno w aplikacji, jak i w zależności od jej biblioteki, aplikacja zawiera smaki, których nie ma w bibliotece.

    Na przykład zarówno aplikacja, jak i zależności jej bibliotek zawierają wymiar rodzaju „Poziom”. Jednak wymiar „poziom” w aplikacji obejmuje smaki „bezpłatne” i „płatne”, ale zależność obejmuje tylko smaki „demonstracyjne” i „płatne” dla tego samego wymiaru.

    Pamiętaj, że w przypadku danego wymiaru smaku, który występuje zarówno w aplikacji, jak i w zależności od jej biblioteki, nie wystąpi problem, jeśli biblioteka zawiera rodzaj produktu, którego nie ma Twoja aplikacja. Dzieje się tak, ponieważ wtyczka nigdy nie żąda tego rodzaju z zależności.

    Użyj matchingFallbacks, aby określić alternatywne dopasowania smaku „bezpłatnego” produktu w aplikacji, jak pokazano tutaj:

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions += "tier"
        productFlavors {
            create("paid") {
                dimension = "tier"
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            create("free") {
                dimension = "tier"
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks += listOf("demo", "trial")
            }
        }
    }
    

    Odlotowy

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions 'tier'
        productFlavors {
            paid {
                dimension 'tier'
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            free {
                dimension 'tier'
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks = ['demo', 'trial']
            }
        }
    }
    
  • Zależność z biblioteką obejmuje wymiar smaku, którego nie ma Twoja aplikacja.

    Na przykład zależność biblioteki obejmuje smaki dla wymiaru „minApi”, ale aplikacja zawiera smaki tylko dla wymiaru „poziom”. Gdy chcesz utworzyć wersję „freeDebug” aplikacji, wtyczka nie wie, czy użyć wersji zależności „minApi23Debug” czy „minApi18Debug”.

    Jeśli aplikacja zawiera wymiar smaku, którego nie obejmuje zależność z biblioteką, nie wystąpi żaden problem. Dzieje się tak, ponieważ wtyczka pasuje do smaków tylko w przypadku wymiarów istniejących w zależności. Jeśli na przykład zależność nie zawiera wymiaru dla interfejsów ABI, jej wersja „freeX86Debug” użyje wersji „freeDebug”.

    Użyj w bloku defaultConfig parametru missingDimensionStrategy, aby określić domyślny rodzaj wtyczki, który będzie wybierany dla każdego brakującego wymiaru, jak pokazano w poniższym przykładzie. Możesz też zastąpić swój wybór w bloku productFlavors, aby każdy rodzaj mógł określać inną strategię dopasowania dla brakującego wymiaru.

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy("minApi", "minApi18", "minApi23")
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy("abi", "x86", "arm64")
        }
        flavorDimensions += "tier"
        productFlavors {
            create("free") {
                dimension = "tier"
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the "minApi" dimension.
                missingDimensionStrategy("minApi", "minApi23", "minApi18")
            }
            create("paid") {}
        }
    }
    

    Odlotowy

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy 'minApi', 'minApi18', 'minApi23'
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy 'abi', 'x86', 'arm64'
        }
        flavorDimensions 'tier'
        productFlavors {
            free {
                dimension 'tier'
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the 'minApi' dimension.
                missingDimensionStrategy 'minApi', 'minApi23', 'minApi18'
            }
            paid {}
        }
    }
    

Więcej informacji znajdziesz w sekcjach matchingFallbacks i missingDimensionStrategy w dokumentacji DSL wtyczki Androida do obsługi Gradle.

Skonfiguruj ustawienia podpisywania

Gradle nie podpisuje pliku APK ani pakietu AAB kompilacji wersji, chyba że wyraźnie zdefiniujesz konfigurację podpisywania dla tej kompilacji. Jeśli nie masz jeszcze klucza podpisywania, wygeneruj klucz przesyłania i magazyn kluczy za pomocą Androida Studio.

Aby ręcznie skonfigurować konfiguracje podpisywania na potrzeby typu kompilacji wersji za pomocą konfiguracji kompilacji Gradle:

  1. utworzyć magazyn kluczy, Magazyn kluczy to plik binarny zawierający zestaw kluczy prywatnych. Magazyn kluczy musisz przechowywać w bezpiecznym miejscu.
  2. utworzyć klucz prywatny, Klucz prywatny służy do podpisywania aplikacji na potrzeby jej rozpowszechniania. Nigdy nie jest dołączany do aplikacji ani nie jest ujawniany nieupoważnionym osobom.
  3. Dodaj konfigurację podpisywania do pliku build.gradle.kts na poziomie modułu:

    Kotlin

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

    Odlotowy

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

Uwaga: umieszczanie haseł klucza wersji i magazynu kluczy w pliku kompilacji nie jest dobrą metodą zachowania bezpieczeństwa. Zamiast tego skonfiguruj plik kompilacji, aby uzyskiwał te hasła ze zmiennych środowiskowych lub aby proces kompilacji wyświetlał prośbę o ich podanie.

Aby uzyskać te hasła ze zmiennych środowiskowych:

Kotlin

storePassword = System.getenv("KSTOREPWD")
keyPassword = System.getenv("KEYPWD")

Odlotowy

storePassword System.getenv("KSTOREPWD")
keyPassword System.getenv("KEYPWD")

Magazyn kluczy możesz też wczytać z pliku właściwości lokalnych. Ze względów bezpieczeństwa nie dodawaj tego pliku do kontroli źródła. Zamiast tego skonfiguruj ją lokalnie dla każdego dewelopera. Więcej informacji znajdziesz w artykule Usuwanie informacji o podpisywaniu z plików kompilacji.

Po zakończeniu tego procesu możesz rozpowszechniać swoją aplikację i publikować ją w Google Play.

Ostrzeżenie: przechowuj swój magazyn kluczy i klucz prywatny w bezpiecznym miejscu i upewnij się, że masz ich bezpieczne kopie zapasowe. Jeśli korzystasz z podpisywania aplikacji przez Google Play i utracisz swój klucz przesyłania, możesz poprosić o zresetowanie danych w Konsoli Play. Jeśli publikujesz aplikację bez podpisywania aplikacji przez Google Play (w przypadku aplikacji utworzonych przed sierpniem 2021 r.) i utracisz swój klucz podpisywania aplikacji, nie będziesz mieć możliwości publikowania żadnych aktualizacji aplikacji, ponieważ wszystkie wersje aplikacji musisz zawsze podpisywać tym samym kluczem.

Podpisywanie aplikacji na Wear OS

Podczas publikowania aplikacji na Wear OS zarówno plik APK na zegarek, jak i opcjonalny plik APK na telefon muszą być podpisane za pomocą tego samego klucza. Więcej informacji o pakowaniu i podpisywaniu aplikacji na Wear OS znajdziesz w artykule Pakowanie i rozpowszechnianie aplikacji na Wear.