Szukaj…


Wprowadzenie

Gradle to oparty na JVM system kompilacji, który umożliwia programistom pisanie skryptów wysokiego poziomu, których można użyć do automatyzacji procesu kompilacji i produkcji aplikacji. Jest to elastyczny system oparty na wtyczkach, który pozwala zautomatyzować różne aspekty procesu kompilacji; w tym kompilowanie i podpisywanie .jar , pobieranie zewnętrznych zależności i zarządzanie nimi, wstrzykiwanie pól do AndroidManifest lub wykorzystanie określonych wersji SDK.

Składnia

  • apply plugin : wtyczki, które powinny być normalnie używane, to po prostu 'com.android.application' lub 'com.android.library' .

  • android : główna konfiguracja Twojej aplikacji

    • compileSdkVersion : wersja kompilowanego compileSdkVersion SDK
    • buildToolsVersion : wersja narzędzi do budowania
    • defaultConfig : Domyślne ustawienia, które można zastąpić smakami i typami kompilacji
      • applicationId : identyfikator aplikacji, którego używasz np. w PlayStore, w większości taki sam jak nazwa pakietu
      • minSdkVersion : minimalna wymagana wersja minSdkVersion SDK
      • targetSdkVersion : Wersja SDK, na której kompilujesz (zawsze powinna być najnowsza)
      • versionCode : wewnętrzny numer wersji, który musi być większy przy każdej aktualizacji
      • versionName : numer wersji, który użytkownik widzi na stronie szczegółów aplikacji
    • buildTypes : Zobacz gdzie indziej (TODO)
  • dependencies : zależność między aplikacją lokalną a lokalną

    • compile pojedynczą zależność
    • testCompile : zależność dla testów jednostkowych lub integracyjnych

Uwagi

Zobacz też

Gradle dla Androida - Dokumentacja rozszerzona:

Jest jeszcze jeden tag, w którym można znaleźć więcej tematów i przykładów na temat używania gradle w Androidzie.
http://www.riptutorial.com/topic/2092

Podstawowy plik build.gradle

To jest przykład domyślnego pliku build.gradle w module.

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion '25.0.3'

    signingConfigs {
        applicationName {
            keyAlias 'applicationName'
            keyPassword 'password'
            storeFile file('../key/applicationName.jks')
            storePassword 'keystorePassword'
        }
    }
    defaultConfig {
        applicationId 'com.company.applicationName'
        minSdkVersion 14
        targetSdkVersion 25
        versionCode 1
        versionName '1.0'
        signingConfig signingConfigs.applicationName
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support:design:25.3.1'

    testCompile 'junit:junit:4.12'
}

DSL (język specyficzny dla domeny)

Każdy blok w powyższym pliku nosi nazwę DSL (język specyficzny dla domeny).


Wtyczki

W pierwszym wierszu apply plugin: 'com.android.application' , zastosuje wtyczkę dla systemu Gradle do kompilacji i udostępni blok android {} celu zadeklarowania opcji kompilacji specyficznych dla Androida.

W przypadku aplikacji na Androida :

apply plugin: 'com.android.application'

W przypadku biblioteki Androida :

apply plugin: 'com.android.library'

Zrozumienie DSL w powyższej próbce

Druga część, blok android {...} Androida, to DSL Androida, który zawiera informacje o twoim projekcie.

Na przykład możesz ustawić compileSdkVersion który określa poziom interfejsu API systemu Android, który powinien być używany przez Gradle do kompilowania Twojej aplikacji.
defaultConfig przechowuje wartości domyślne dla manifestu. Możesz je override pomocą Smaków produktu .

Więcej informacji można znaleźć w tych przykładach:


Zależności

Blok dependencies jest zdefiniowany poza blokiem android {...} : Oznacza to, że nie jest zdefiniowany przez wtyczkę Androida, ale jest to standardowy Gradle.
Blok dependencies określa, jakie biblioteki zewnętrzne (zwykle biblioteki Androida, ale również biblioteki Java są prawidłowe), które chcesz uwzględnić w swojej aplikacji. Gradle automatycznie pobierze te zależności (jeśli nie ma dostępnej kopii lokalnej), wystarczy dodać podobne wiersze compile , aby dodać kolejną bibliotekę.

Spójrzmy na jedną z linii tutaj obecnych:

compile 'com.android.support:design:25.3.1'

Ta linia w zasadzie mówi

dodaj do mojego projektu zależność od biblioteki projektów obsługi systemu Android.

Gradle zapewni, że biblioteka zostanie pobrana i zaprezentowana, dzięki czemu będziesz mógł jej używać w swojej aplikacji, a jej kod będzie również zawarty w Twojej aplikacji.

Jeśli znasz Maven, ta składnia to GroupId , dwukropek, ArtifactId , kolejny dwukropek, a następnie wersja zależności, którą chcesz uwzględnić, dając ci pełną kontrolę nad wersjonowaniem.

Chociaż możliwe jest określenie wersji artefaktu za pomocą znaku plus (+), najlepszą praktyką jest unikanie tego; może to prowadzić do problemów, jeśli biblioteka zostanie zaktualizowana z łamaniem zmian bez Twojej wiedzy, co prawdopodobnie doprowadzi do awarii w Twojej aplikacji.

Możesz dodać różnego rodzaju zależności:

Szczególną uwagę należy zwrócić na płaskie zależności .

Więcej informacji można znaleźć w tym temacie.

Uwaga na temat -v7 w appcompat-v7

compile 'com.android.support:appcompat-v7:25.3.1'

Oznacza to po prostu, że ta biblioteka ( appcompat ) jest zgodna z interfejsem API Androida w wersji 7 i appcompat .

Uwaga na temat junit: junit: 4.12

Jest to zależność testowania dla testów jednostkowych.


Określanie zależności specyficznych dla różnych konfiguracji kompilacji

Możesz określić, że zależność powinna być używana tylko dla określonej konfiguracji kompilacji lub możesz zdefiniować różne zależności dla typów kompilacji lub smaków produktu (np. Debugowanie, test lub wydanie) za pomocą debugCompile , testCompile lub releaseCompile zamiast zwykłej compile .

Jest to pomocne w utrzymywaniu zależności związanych z testowaniem i debugowaniem z kompilacji wydania, dzięki czemu APK wersji będzie możliwie jak najmniejszy i zapewni, że żadne informacje debugowania nie będą mogły zostać wykorzystane do uzyskania wewnętrznych informacji o aplikacji.


signingConfig

signingConfig pozwala skonfigurować Gradle tak, aby zawierał informacje o signingConfig keystore i upewnić się, że signingConfig APK zbudowany przy użyciu tych konfiguracji jest podpisany i gotowy do wydania w Play Store.

Tutaj znajdziesz dedykowany temat .

Uwaga : nie zaleca się jednak przechowywania poświadczeń podpisywania w pliku Gradle. Aby usunąć konfiguracje podpisywania, po prostu pomiń część signingConfigs .
Możesz je określić na różne sposoby:

Aby uzyskać więcej informacji, zobacz ten temat: Podpisz APK bez ujawniania hasła do magazynu kluczy .


Więcej informacji na temat Gradle na Androida można znaleźć w dedykowanym temacie Gradle .

Definiowanie smaków produktu

Smaki produktu są zdefiniowane w pliku build.gradle wewnątrz bloku android { ... } jak pokazano poniżej.

...
android {
    ...
    productFlavors {
        free {
            applicationId "com.example.app.free"
            versionName "1.0-free"
        }
        paid {
            applicationId "com.example.app.paid"
            versionName "1.0-paid"
        }
    }
}

Dzięki temu mamy teraz dwa dodatkowe smaki produktu: free i paid . Każdy może mieć swoją własną konfigurację i atrybuty. Na przykład, oba nasze nowe smaki mają osobne applicationId i versionName niż nasz dotychczasowy main smak (dostępny domyślnie, więc nie pokazany tutaj).

Dodanie zależności specyficznych dla smaku produktu

Zależności można dodać dla określonego smaku produktu , podobnie jak można je dodać dla określonych konfiguracji kompilacji.

W tym przykładzie załóżmy, że zdefiniowaliśmy już dwa smaki produktu o nazwie free i paid (więcej o definiowaniu smaków tutaj ).
Następnie możemy dodać zależność AdMob dla free smaku i bibliotekę Picasso dla paid sposób:

android {
    ...

    productFlavors {
        free {
            applicationId "com.example.app.free"
            versionName "1.0-free"
        }
        paid {
            applicationId "com.example.app.paid"
            versionName "1.0-paid"
        }
    }
}

...
dependencies {
    ...
    // Add AdMob only for free flavor
    freeCompile 'com.android.support:appcompat-v7:23.1.1'
    freeCompile 'com.google.android.gms:play-services-ads:8.4.0'
    freeCompile 'com.android.support:support-v4:23.1.1'

    // Add picasso only for paid flavor
    paidCompile 'com.squareup.picasso:picasso:2.5.2'
} 
...

Dodanie zasobów specyficznych dla smaku produktu

Można dodać zasoby dla określonego smaku produktu .

W tym przykładzie załóżmy, że zdefiniowaliśmy już dwa smaki produktu o nazwie free i paid . Aby dodać zasoby specyficzne dla smaku produktu, tworzymy dodatkowe foldery zasobów obok folderu main/res , do których możemy następnie dodawać zasoby jak zwykle. W tym przykładzie zdefiniujemy ciąg, status dla każdego smaku produktu:

/ src / main /res/values/strings.xml

<resources>
    <string name="status">Default</string>
</resources>

/ src / free /res/values/strings.xml

<resources>
    <string name="status">Free</string>
</resources>

/ src / paid /res/values/strings.xml

<resources>
    <string name="status">Paid</string>
</resources>

Ciągi status specyficzne dla smaku produktu zastąpią wartość status dla main smaku.

Zdefiniuj i użyj pól konfiguracji kompilacji

BuildConfigField

Gradle pozwala liniom buildConfigField definiować stałe. Te stałe będą dostępne w czasie wykonywania jako pola statyczne klasy BuildConfig . Można to wykorzystać do tworzenia smaków poprzez zdefiniowanie wszystkich pól w bloku defaultConfig , a następnie zastąpienie ich dla indywidualnych smaków kompilacji w razie potrzeby.

W tym przykładzie zdefiniowano datę kompilacji i oflagowano kompilację dla produkcji zamiast testować:

android {
    ...
    defaultConfig {
        ...
        // defining the build date
        buildConfigField "long", "BUILD_DATE", System.currentTimeMillis() + "L"
        // define whether this build is a production build
        buildConfigField "boolean", "IS_PRODUCTION", "false"
        // note that to define a string you need to escape it
        buildConfigField "String", "API_KEY", "\"my_api_key\""
    }

    productFlavors {
        prod {
            // override the productive flag for the flavor "prod"
            buildConfigField "boolean", "IS_PRODUCTION", "true"
            resValue 'string', 'app_name', 'My App Name'
        }
        dev {
            // inherit default fields
            resValue 'string', 'app_name', 'My App Name - Dev'
        }
    }
}

Automatycznie generowana <nazwa_pakietu>. BuildConfig .java w folderze gen zawiera następujące pola na podstawie powyższej dyrektywy:

public class BuildConfig {
    // ... other generated fields ...
    public static final long BUILD_DATE = 1469504547000L;
    public static final boolean IS_PRODUCTION = false;
    public static final String API_KEY = "my_api_key";
}

Zdefiniowanych pól można teraz używać w aplikacji w czasie wykonywania, uzyskując dostęp do wygenerowanej klasy BuildConfig :

public void example() {
    // format the build date
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
    String buildDate = dateFormat.format(new Date(BuildConfig.BUILD_DATE));
    Log.d("build date", buildDate);
    
    // do something depending whether this is a productive build
    if (BuildConfig.IS_PRODUCTION) {
        connectToProductionApiEndpoint();
    } else {
        connectToStagingApiEndpoint();
    }
}

ResValue

resValue w productFlavors tworzy wartość zasobu. Może to być dowolny rodzaj zasobu ( string , dimen , color itp.). Jest to podobne do definiowania zasobu w odpowiednim pliku: np. Definiowanie łańcucha w pliku strings.xml . Zaletą jest to, że ten zdefiniowany w gradable można modyfikować w zależności od produktu Smak / buildVariant. Aby uzyskać dostęp do wartości, napisz ten sam kod, jakbyś miał dostęp do res z pliku zasobów:

getResources().getString(R.string.app_name)

Ważne jest to, że zasoby zdefiniowane w ten sposób nie mogą modyfikować istniejących zasobów zdefiniowanych w plikach. Mogą tworzyć tylko nowe wartości zasobów.


Niektóre biblioteki (takie jak Google Maps Android API) wymagają klucza API podanego w Manifeście jako meta-data . Jeśli do debugowania i kompilacji produkcyjnych potrzebne są różne klucze, określ manifest zastępczy wypełniony przez Gradle.

W pliku AndroidManifest.xml :

<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="${MAPS_API_KEY}"/>

A następnie odpowiednio ustaw pole w swoim pliku build.gradle :

android {
    defaultConfig {
        ...
        // Your development key
        manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
    }

    productFlavors {
        prod {
            // Your production key
            manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
        }
    }
}

System kompilacji dla Androida automatycznie generuje wiele pól i umieszcza je w BuildConfig.java . Te pola to:

Pole Opis
DEBUG Boolean stwierdzający, czy aplikacja jest w trybie debugowania lub wydania
APPLICATION_ID String zawierający identyfikator aplikacji (np. com.example.app )
BUILD_TYPE String zawierający typ kompilacji aplikacji (zwykle debug lub release )
FLAVOR String zawierający konkretny smak kompilacji
VERSION_CODE int zawierający numer wersji (kompilacji).
Jest to to samo, co versionCode w build.gradle lub versionCode w AndroidManifest.xml
VERSION_NAME String zawierający nazwę wersji (kompilacji).
Jest to to samo, co versionName w build.gradle lub versionName w AndroidManifest.xml

Oprócz powyższego, jeśli zdefiniowałeś wiele wymiarów smaku, to każdy wymiar będzie miał swoją wartość. Na przykład, jeśli masz dwa wymiary smaku color i size , będziesz mieć także następujące zmienne:

Pole Opis
FLAVOR_color String zawierający wartość smaku „kolorowego”.
FLAVOR_size String zawierający wartość smaku „rozmiar”.

Centralizacja zależności za pomocą pliku „dependencies.gradle”

Podczas pracy z projektami wielomodułowymi pomocne jest scentralizowanie zależności w jednym miejscu zamiast rozłożenia ich na wiele plików kompilacji, szczególnie w przypadku popularnych bibliotek, takich jak biblioteki obsługi Androida i biblioteki Firebase .

Jednym z zalecanych sposobów jest oddzielenie plików kompilacji Gradle, z jednym build.gradle na moduł, a także jednym w katalogu głównym projektu i drugim dla zależności, na przykład:

root
  +- gradleScript/
  |     dependencies.gradle
  +- module1/
  |     build.gradle
  +- module2/
  |     build.gradle
  +- build.gradle

Następnie wszystkie twoje zależności mogą być zlokalizowane w gradleScript/dependencies.gradle :

ext {
    // Version
    supportVersion = '24.1.0'

    // Support Libraries dependencies
    supportDependencies = [
            design:            "com.android.support:design:${supportVersion}",
            recyclerView:      "com.android.support:recyclerview-v7:${supportVersion}",
            cardView:          "com.android.support:cardview-v7:${supportVersion}",
            appCompat:         "com.android.support:appcompat-v7:${supportVersion}",
            supportAnnotation: "com.android.support:support-annotations:${supportVersion}",
    ]

    firebaseVersion = '9.2.0';

    firebaseDependencies = [
            core:         "com.google.firebase:firebase-core:${firebaseVersion}",
            database:     "com.google.firebase:firebase-database:${firebaseVersion}",
            storage:      "com.google.firebase:firebase-storage:${firebaseVersion}",
            crash:        "com.google.firebase:firebase-crash:${firebaseVersion}",
            auth:         "com.google.firebase:firebase-auth:${firebaseVersion}",
            messaging:    "com.google.firebase:firebase-messaging:${firebaseVersion}",
            remoteConfig: "com.google.firebase:firebase-config:${firebaseVersion}",
            invites:      "com.google.firebase:firebase-invites:${firebaseVersion}",
            adMod:        "com.google.firebase:firebase-ads:${firebaseVersion}",
            appIndexing:  "com.google.android.gms:play-services-appindexing:${firebaseVersion}",
    ];
}

Które można następnie zastosować z tego pliku w pliku build.gradle najwyższego poziomu, tak jak to:

// Load dependencies
apply from: 'gradleScript/dependencies.gradle'

i w module1/build.gradle tak:

// Module build file
dependencies {
    // ...
    compile supportDependencies.appCompat
    compile supportDependencies.design
    compile firebaseDependencies.crash
}

Inne podejście

Mniej szczegółowe podejście do centralizacji wersji zależności bibliotek można osiągnąć, zadeklarując raz numer wersji jako zmienną i używając go wszędzie.

W głównym katalogu roboczym build.gradle dodaj to:

ext.v = [
    supportVersion:'24.1.1',
]

I w każdym module korzystającym z tej samej biblioteki dodaj potrzebne biblioteki

compile "com.android.support:support-v4:${v.supportVersion}"
compile "com.android.support:recyclerview-v7:${v.supportVersion}"
compile "com.android.support:design:${v.supportVersion}"
compile "com.android.support:support-annotations:${v.supportVersion}"

Struktura katalogów dla zasobów specyficznych dla smaku

Różne wersje kompilacji aplikacji mogą zawierać różne zasoby. Aby utworzyć zasób specyficzny dla smaku, utwórz katalog z małą nazwą Twojego smaku w katalogu src i dodaj swoje zasoby w taki sam sposób, jak normalnie.

Na przykład, jeśli miałeś smak Development i chciałbyś podać dla niego odrębną ikonę uruchamiania, utworzyłbyś katalog src/development/res/drawable-mdpi a wewnątrz tego katalogu ic_launcher.png plik ic_launcher.png z ikoną specyficzną dla rozwoju.

Struktura katalogów będzie wyglądać następująco:

src/
  main/
    res/
      drawable-mdpi/
        ic_launcher.png  <-- the default launcher icon
  development/
    res/
      drawable-mdpi/
        ic_launcher.png  <-- the launcher icon used when the product flavor is 'Development'

(Oczywiście w tym przypadku utworzyłbyś także ikony dla drawable-hdpi, drawable-xhdpi itp .).

Dlaczego w projekcie Android Studio są dwa pliki build.gradle?

<PROJECT_ROOT>\app\build.gradle jest specyficzny dla modułu aplikacji .

<PROJECT_ROOT>\build.gradle to „plik kompilacji najwyższego poziomu”, w którym można dodawać opcje konfiguracji wspólne dla wszystkich podprojektów / modułów.

Jeśli użyjesz innego modułu w swoim projekcie, jako bibliotekę lokalną miałbyś inny plik build.gradle : <PROJECT_ROOT>\module\build.gradle

W pliku najwyższego poziomu możesz określić wspólne właściwości jako blok buildscript lub niektóre wspólne właściwości.

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
       classpath 'com.android.tools.build:gradle:2.2.0'
       classpath 'com.google.gms:google-services:3.0.0'
    }
}

ext {
    compileSdkVersion = 23
    buildToolsVersion = "23.0.1"
}

W app\build.gradle definiujesz tylko właściwości modułu:

apply plugin: 'com.android.application'


android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
}

dependencies {
    //.....
}

Wykonywanie skryptu powłoki z poziomu

Skrypt powłoki to bardzo wszechstronny sposób na rozszerzenie twojej kompilacji do praktycznie wszystkiego, co tylko możesz wymyślić.

Jako przykład, oto prosty skrypt do kompilacji plików protobuf i dodania wynikowych plików Java do katalogu źródłowego w celu dalszej kompilacji:

def compilePb() {
    exec {
        // NOTICE: gradle will fail if there's an error in the protoc file...
        executable "../pbScript.sh"
    }
}

project.afterEvaluate {
    compilePb()
}

Skrypt powłoki „pbScript.sh” dla tego przykładu, znajdujący się w folderze głównym projektu:

#!/usr/bin/env bash
pp=/home/myself/my/proto

/usr/local/bin/protoc -I=$pp \
 --java_out=./src/main/java \
  --proto_path=$pp \
 $pp/my.proto \
 --proto_path=$pp \
 $pp/my_other.proto

Debugowanie błędów Gradle

Poniżej znajduje się fragment Gradle - Co to jest niezerowa wartość wyjściowa i jak to naprawić? zobacz całą dyskusję.

Załóżmy, że tworzysz aplikację i pojawia się błąd Gradle, który na ogół wygląda tak.

:module:someTask FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':module:someTask'.
> some message here...  finished with non-zero exit value X
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: Y.ZZ secs

Przeszukujesz tutaj na StackOverflow swój problem, a ludzie mówią, aby wyczyścić i odbudować projekt lub włączyć MultiDex , a kiedy spróbujesz, to po prostu nie rozwiązuje problemu.

Istnieją sposoby, aby uzyskać więcej informacji , ale samo wyjście Gradle powinno wskazywać na rzeczywisty błąd w kilku wierszach powyżej tego komunikatu między: module:someTask FAILED a ostatnim :module:someOtherTask który przeszedł. Dlatego jeśli zadajesz pytanie na temat błędu, edytuj pytania, aby uwzględnić więcej kontekstu błędu.

Otrzymujesz „niezerową wartość wyjściową”. Ta liczba jest dobrym wskaźnikiem tego, co powinieneś spróbować naprawić. Oto kilka najczęściej występujących.

  • 1 to tylko ogólny kod błędu, a błąd prawdopodobnie występuje na wyjściu Gradle
  • 2 wydaje się mieć związek z nakładającymi się zależnościami lub błędną konfiguracją projektu.
  • Wygląda na to, że 3 zawiera zbyt wiele zależności lub problem z pamięcią.

Ogólne rozwiązania powyższego (po próbie czyszczenia i przebudowy projektu) to:

  • 1 - Rozwiąż wspomniany błąd. Zasadniczo jest to błąd czasu kompilacji, co oznacza, że jakiś fragment kodu w projekcie jest nieprawidłowy. Obejmuje to zarówno XML, jak i Javę dla projektu Android.
  • 2 i 3 - Wiele odpowiedzi tutaj mówi o włączeniu multidex . Chociaż może rozwiązać problem, najprawdopodobniej jest to obejście. Jeśli nie rozumiesz, dlaczego go używasz (patrz link), prawdopodobnie nie potrzebujesz go. Ogólne rozwiązania obejmują ograniczenie nadużywania zależności między bibliotekami (takich jak wszystkie Usługi Google Play, gdy potrzebujesz tylko jednej biblioteki, na przykład Mapy lub Logowanie).

Określanie różnych identyfikatorów aplikacji dla typów kompilacji i smaków produktów

Możesz określić różne identyfikatory aplikacji lub nazwy pakietów dla każdego buildType lub productFlavor za pomocą atrybutu konfiguracji applicationIdSuffix :

Przykład przyrostka applicationId dla każdego buildType :

defaultConfig {
    applicationId "com.package.android"
    minSdkVersion 17
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"
}

buildTypes {
    release {
        debuggable false      
    }

    development {
        debuggable true
        applicationIdSuffix ".dev"
    }

    testing {
        debuggable true
        applicationIdSuffix ".qa"
    }
}

Nasza wynikowa applicationIds będzie teraz:

  • com.package.android do release
  • com.package.android. dev dla development
  • com.package.android. qa do testing

Można to zrobić również dla productFlavors :

productFlavors {
    free {
        applicationIdSuffix ".free"
    }
    paid {
        applicationIdSuffix ".paid"
    }
}

Wynikowymi identyfikatorami applicationIds byłyby:

  • com.package.android. za darmo dla free smaku
  • com.package.android. zapłacono za paid smak

Podpisz APK bez ujawniania hasła do magazynu kluczy

Możesz zdefiniować konfigurację podpisywania, aby podpisać apk w pliku build.gradle , używając następujących właściwości:

  • storeFile : plik kluczy
  • storePassword : hasło do storePassword kluczy
  • keyAlias : nazwa aliasu klucza
  • keyPassword : Hasło aliasu klucza

W wielu przypadkach może być konieczne uniknięcie tego rodzaju informacji w pliku build.gradle .

Metoda A: Skonfiguruj podpisywanie wersji za pomocą pliku keystore.properties

Możliwe jest skonfigurowanie build.gradle aplikacji, aby odczytywała informacje o konfiguracji podpisywania z pliku właściwości, takiego jak keystore.properties .

Konfigurowanie takiego podpisywania jest korzystne, ponieważ:

  • Informacje o konfiguracji podpisywania są niezależne od pliku build.gradle
  • Nie musisz interweniować podczas procesu podpisywania, aby podać hasła do pliku kluczy
  • Możesz łatwo wykluczyć plik keystore.properties z kontroli wersji

Najpierw utwórz plik o nazwie keystore.properties w katalogu głównym projektu z taką treścią (zamieniając wartości na własne):

storeFile=keystore.jks
storePassword=storePassword
keyAlias=keyAlias
keyPassword=keyPassword

Teraz w pliku build.gradle aplikacji skonfiguruj blok signingConfigs w następujący sposób:

android {
...

    signingConfigs {
        release {
            def propsFile = rootProject.file('keystore.properties')
            if (propsFile.exists()) {
                def props = new Properties()
                props.load(new FileInputStream(propsFile))
                storeFile = file(props['storeFile'])
                storePassword = props['storePassword']
                keyAlias = props['keyAlias']
                keyPassword = props['keyPassword']
            }
        }
    }
}

To naprawdę wszystko, ale nie zapomnij wykluczyć zarówno pliku magazynu kluczy, jak i pliku keystore.properties z kontroli wersji .

Kilka rzeczy do zapamiętania:

  • Ścieżka storeFile określona w pliku keystore.properties powinna być względna w stosunku do pliku build.gradle aplikacji. W tym przykładzie założono, że plik kluczy znajduje się w tym samym katalogu, co plik build.gradle aplikacji.
  • W tym przykładzie plik keystore.properties w katalogu głównym projektu. Jeśli umieścisz go w innym miejscu, pamiętaj, aby zmienić wartość w rootProject.file('keystore.properties') na swoją lokalizację względem katalogu głównego projektu.

Metoda B: przy użyciu zmiennej środowiskowej

To samo można osiągnąć również bez pliku właściwości, co utrudnia znalezienie hasła:

android {

  signingConfigs {
    release {
        storeFile file('/your/keystore/location/key')
        keyAlias 'your_alias'
        String ps = System.getenv("ps")
        if (ps == null) {
             throw new GradleException('missing ps env variable')
        }
        keyPassword ps
        storePassword ps
    }
}

Zmienna środowiskowa "ps" może być globalna, ale bezpieczniejszym podejściem może być dodanie jej tylko do powłoki Android Studio.
W systemie Linux można to zrobić, edytując Desktop Entry Android Studio

Exec=sh -c "export ps=myPassword123 ; /path/to/studio.sh"

Więcej informacji można znaleźć w tym temacie .

Wersjonowanie swoich kompilacji za pomocą pliku „version.properties”

Możesz użyć narzędzia Gradle do automatycznego zwiększania wersji pakietu za każdym razem, gdy ją budujesz. W tym celu należy utworzyć plik version.properties w tym samym katalogu, co plik build.gradle o następującej treści:

VERSION_MAJOR=0
VERSION_MINOR=1
VERSION_BUILD=1

(Zmiana wartości dla dur i minor według własnego uznania). Następnie w swoim build.gradle dodaj następujący kod do sekcji android :

// Read version information from local file and increment as appropriate
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
  def Properties versionProps = new Properties()

  versionProps.load(new FileInputStream(versionPropsFile))

  def versionMajor = versionProps['VERSION_MAJOR'].toInteger()
  def versionMinor = versionProps['VERSION_MINOR'].toInteger()
  def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1

  // Update the build number in the local file
  versionProps['VERSION_BUILD'] = versionBuild.toString()
  versionProps.store(versionPropsFile.newWriter(), null)

  defaultConfig {
    versionCode versionBuild
    versionName "${versionMajor}.${versionMinor}." + String.format("%05d", versionBuild)
  }
}

Informacje można uzyskać w Javie jako ciąg BuildConfig.VERSION_NAME dla kompletnego BuildConfig.VERSION_NAME {major}. { BuildConfig.VERSION_NAME }. {Build} oraz jako liczbę całkowitą BuildConfig.VERSION_CODE tylko dla numeru kompilacji.

Zmiana wyjściowej nazwy apk i dodanie nazwy wersji:

Jest to kod do zmiany nazwy pliku aplikacji wyjściowej (.apk). Nazwę można skonfigurować, przypisując inną wartość do newName

android {

    applicationVariants.all { variant ->
        def newName = "ApkName";
        variant.outputs.each { output ->
            def apk = output.outputFile;

            newName += "-v" + defaultConfig.versionName;
            if (variant.buildType.name == "release") {
                newName += "-release.apk";
            } else {
                newName += ".apk";
            }
            if (!output.zipAlign) {
                newName = newName.replace(".apk", "-unaligned.apk");
            }

            output.outputFile = new File(apk.parentFile, newName);
            logger.info("INFO: Set outputFile to " 
                        + output.outputFile 
                        + " for [" + output.name + "]");
        }
    }
}

Wyłącz kompresję obrazu dla mniejszego pliku APK

Jeśli ręcznie optymalizujesz wszystkie obrazy, wyłącz APT Cruncher dla mniejszego rozmiaru pliku APK.

android {
    
    aaptOptions {
        cruncherEnabled = false
    }
}

Włącz Proguard za pomocą gradla

Aby włączyć konfiguracje Proguard dla aplikacji, musisz włączyć ją w pliku ocen na poziomie modułu. Musisz ustawić wartość minifyEnabled na true .

buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

Powyższy kod zastosuje konfiguracje Proguard zawarte w domyślnym zestawie SDK systemu Android w połączeniu z plikiem „proguard-rules.pro” w module do wydanej aplikacji.

Włącz eksperymentalną obsługę wtyczek NDK dla Gradle i AndroidStudio

Włącz i skonfiguruj eksperymentalną wtyczkę Gradle, aby poprawić obsługę NDK w AndroidStudio. Sprawdź, czy spełniasz następujące wymagania:

  • Stopień 2.10 (dla tego przykładu)
  • Android NDK r10 lub nowszy
  • Android SDK z narzędziami do kompilacji w wersji 19.0.0 lub nowszej

Skonfiguruj plik MyApp / build.gradle

Edytuj wiersz dependencies.classpath w build.gradle np

classpath 'com.android.tools.build:gradle:2.1.2'

do

classpath 'com.android.tools.build:gradle-experimental:0.7.2'

(v0.7.2 była najnowszą wersją w momencie pisania. Sprawdź najnowszą wersję i odpowiednio dostosuj swoją linię)

Plik build.gradle powinien wyglądać podobnie do tego:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle-experimental:0.7.2'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Skonfiguruj plik MyApp / app / build.gradle

Edytuj plik build.gradle, aby wyglądał podobnie do poniższego przykładu. Twoje numery wersji mogą wyglądać inaczej.

apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion 19
        buildToolsVersion "24.0.1"

        defaultConfig {
            applicationId "com.example.mydomain.myapp"
            minSdkVersion.apiLevel 19
            targetSdkVersion.apiLevel 19
            versionCode 1
            versionName "1.0"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles.add(file('proguard-android.txt'))
            }
        }
        ndk {
            moduleName "myLib"
            
            /* The following lines are examples of a some optional flags that 
               you may set to configure your build environment
            */ 
            cppFlags.add("-I${file("path/to/my/includes/dir")}".toString())
            cppFlags.add("-std=c++11")
            ldLibs.addAll(['log', 'm'])
            stl = "c++_static"
            abiFilters.add("armeabi-v7a")
        }
    }
}

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

Przed kontynuowaniem zsynchronizuj i sprawdź, czy w plikach Gradle nie ma błędów.

Sprawdź, czy wtyczka jest włączona

Najpierw upewnij się, że pobrałeś moduł Android NDK. Następnie utwórz nową aplikację w AndroidStudio i dodaj następujące elementy do pliku ActivityMain:

public class MainActivity implements Activity {
    onCreate() {
        // Pregenerated code. Not important here
    }
    static {
        System.loadLibrary("myLib");
    }
    public static native String getString();
}

Część getString() powinna być podświetlona na czerwono, mówiąc, że nie można znaleźć odpowiedniej funkcji JNI. Najedź kursorem myszy na wywołanie funkcji, aż pojawi się czerwona żarówka. Kliknij żarówkę i wybierz opcję Utwórz create function JNI_... Powinno to wygenerować plik myLib.c w katalogu myApp / app / src / main / jni z poprawnym wywołaniem funkcji JNI. Powinno to wyglądać podobnie do tego:

#include <jni.h>

JNIEXPORT jstring JNICALL 
Java_com_example_mydomain_myapp_MainActivity_getString(JNIEnv *env, jobject instance)     
{
    // TODO

    return (*env)->NewStringUTF(env, returnValue);
}

Jeśli tak nie wygląda, to wtyczka nie została poprawnie skonfigurowana lub NDK nie został pobrany

Pokaż wszystkie zadania projektowe

gradlew tasks -- show all tasks

 

Android tasks
-------------
androidDependencies - Displays the Android dependencies of the project.
signingReport - Displays the signing info for each variant.
sourceSets - Prints out all the source sets defined in this project.

Build tasks
-----------
assemble - Assembles all variants of all applications and secondary packages.
assembleAndroidTest - Assembles all the Test applications.
assembleDebug - Assembles all Debug builds.
assembleRelease - Assembles all Release builds.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
compileDebugAndroidTestSources
compileDebugSources
compileDebugUnitTestSources
compileReleaseSources
compileReleaseUnitTestSources
extractDebugAnnotations - Extracts Android annotations for the debug variant into the archive file
extractReleaseAnnotations - Extracts Android annotations for the release variant into the archive file
jar - Assembles a jar archive containing the main classes.
mockableAndroidJar - Creates a version of android.jar that's suitable for unit tests.
testClasses - Assembles test classes.

Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
wrapper - Generates Gradle wrapper files. [incubating]

Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.

Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'LeitnerBoxPro'.
components - Displays the components produced by root project 'LeitnerBoxPro'. [incubating]
dependencies - Displays all dependencies declared in root project 'LeitnerBoxPro'.
dependencyInsight - Displays the insight into a specific dependency in root project 'LeitnerBoxPro'.
help - Displays a help message.
model - Displays the configuration model of root project 'LeitnerBoxPro'. [incubating]
projects - Displays the sub-projects of root project 'LeitnerBoxPro'.
properties - Displays the properties of root project 'LeitnerBoxPro'.
tasks - Displays the tasks runnable from root project 'LeitnerBoxPro' (some of the displayed tasks may belong to subprojects)
.

Install tasks
-------------
installDebug - Installs the Debug build.
installDebugAndroidTest - Installs the android (on device) tests for the Debug build.
uninstallAll - Uninstall all applications.
uninstallDebug - Uninstalls the Debug build.
uninstallDebugAndroidTest - Uninstalls the android (on device) tests for the Debug build.
uninstallRelease - Uninstalls the Release build.

Verification tasks
------------------
check - Runs all checks.
connectedAndroidTest - Installs and runs instrumentation tests for all flavors on connected devices.
connectedCheck - Runs all device checks on currently connected devices.
connectedDebugAndroidTest - Installs and runs the tests for debug on connected devices.
deviceAndroidTest - Installs and runs instrumentation tests using all Device Providers.
deviceCheck - Runs all device checks using Device Providers and Test Servers.
lint - Runs lint on all variants.
lintDebug - Runs lint on the Debug build.
lintRelease - Runs lint on the Release build.
test - Run unit tests for all variants.
testDebugUnitTest - Run unit tests for the debug build.
testReleaseUnitTest - Run unit tests for the release build.

Other tasks
-----------
assembleDefault
clean
jarDebugClasses
jarReleaseClasses
transformResourcesWithMergeJavaResForDebugUnitTest
transformResourcesWithMergeJavaResForReleaseUnitTest

Automatycznie usuń „nieprzystosowany” apk

Jeśli nie potrzebujesz automatycznie generowanych plików APK z unaligned przyrostkiem (czego prawdopodobnie nie potrzebujesz), możesz dodać następujący kod do pliku build.gradle :

// delete unaligned files
android.applicationVariants.all { variant ->
  variant.assemble.doLast {
    variant.outputs.each { output ->
        println "aligned " + output.outputFile
        println "unaligned " + output.packageApplication.outputFile

        File unaligned = output.packageApplication.outputFile;
        File aligned = output.outputFile
        if (!unaligned.getName().equalsIgnoreCase(aligned.getName())) {
            println "deleting " + unaligned.getName()
            unaligned.delete()
        }
    }
  }
}

Stąd

Ignorowanie wariantu kompilacji

Z niektórych powodów możesz zignorować warianty kompilacji. Na przykład: masz „próbny” smak produktu i używasz go tylko do celów debugowania, takich jak testy jednostkowe / instrumentacyjne.

Zignorujmy wariant mockRelease z naszego projektu. Otwórz plik build.gradle i napisz:

    // Remove mockRelease as it's not needed.
    android.variantFilter { variant ->
        if (variant.buildType.name.equals('release') && variant.getFlavors().get(0).name.equals('mock')) {
            variant.setIgnore(true);
        }
    }

Wyświetlanie drzewa zależności

Użyj zależności zadań. W zależności od konfiguracji modułów mogą to być ./gradlew dependencies lub zobaczyć zależności użycia aplikacji modułu ./gradlew :app:dependencies

Przykład następujący po pliku build.gradle

dependencies {
    compile 'com.android.support:design:23.2.1'
    compile 'com.android.support:cardview-v7:23.1.1'

    compile 'com.google.android.gms:play-services:6.5.87'
}

wyświetli następujący wykres:

Parallel execution is an incubating feature.
:app:dependencies

------------------------------------------------------------
Project :app
------------------------------------------------------------
. . .
_releaseApk - ## Internal use, do not manually configure ##
+--- com.android.support:design:23.2.1
|    +--- com.android.support:support-v4:23.2.1
|    |    \--- com.android.support:support-annotations:23.2.1
|    +--- com.android.support:appcompat-v7:23.2.1
|    |    +--- com.android.support:support-v4:23.2.1 (*)
|    |    +--- com.android.support:animated-vector-drawable:23.2.1
|    |    |    \--- com.android.support:support-vector-drawable:23.2.1
|    |    |         \--- com.android.support:support-v4:23.2.1 (*)
|    |    \--- com.android.support:support-vector-drawable:23.2.1 (*)
|    \--- com.android.support:recyclerview-v7:23.2.1
|         +--- com.android.support:support-v4:23.2.1 (*)
|         \--- com.android.support:support-annotations:23.2.1
+--- com.android.support:cardview-v7:23.1.1
\--- com.google.android.gms:play-services:6.5.87
     \--- com.android.support:support-v4:21.0.0 -> 23.2.1 (*)

. . .

Tutaj możesz zobaczyć, że projekt bezpośrednio obejmuje com.android.support:design wersji 23.2.1, który sam przynosi com.android.support:support-v4 z wersją 23.2.1. Jednak com.google.android.gms:play-services są zależne od tego samego support-v4 ale ze starszą wersją 21.0.0, co jest konfliktem wykrywanym przez gradle.

(*) są używane, gdy grad pomija poddrzewo, ponieważ te zależności były już wymienione wcześniej.

Użyj gradle.properties do centralnych numerów wersji / konfiguracji kompilacji

Możesz zdefiniować informacje o konfiguracji centralnej w

lub zrób to z gradle.properties root gradle.properties

struktura projektu

root
  +- module1/
  |     build.gradle
  +- module2/
  |     build.gradle
  +- build.gradle
  +- gradle.properties

ustawienie globalne dla wszystkich submodułów w gradle.properties

# used for manifest
# todo increment for every release
appVersionCode=19
appVersionName=0.5.2.160726

# android tools settings
appCompileSdkVersion=23
appBuildToolsVersion=23.0.2

użycie w submodule

apply plugin: 'com.android.application'
android {
    // appXXX are defined in gradle.properties
    compileSdkVersion = Integer.valueOf(appCompileSdkVersion)
    buildToolsVersion = appBuildToolsVersion

    defaultConfig {
        // appXXX are defined in gradle.properties
        versionCode = Long.valueOf(appVersionCode)
        versionName = appVersionName
    }
}

dependencies {
    ...
}

Uwaga: jeśli chcesz opublikować aplikację w sklepie z aplikacjami F-Droid, musisz użyć magicznych liczb w pliku stopni, ponieważ w przeciwnym razie robot f-droid nie będzie mógł odczytać aktualnego numeru wersji, aby wykryć / zweryfikować zmiany wersji.

Wyświetl informacje o podpisywaniu

W niektórych okolicznościach (na przykład uzyskanie klucza Google API) musisz znaleźć swój odcisk palca w magazynie kluczy. Gradle ma wygodne zadanie, które wyświetla wszystkie informacje o podpisywaniu, w tym odciski palców magazynu kluczy:

./gradlew signingReport

To jest przykładowy wynik:

:app:signingReport
Variant: release
Config: none
----------
Variant: debug
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: debugAndroidTest
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: debugUnitTest
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: releaseUnitTest
Config: none
----------

Definiowanie typów kompilacji

Możesz tworzyć i konfigurować typy kompilacji w pliku build.gradle poziomie modułu w bloku android {} .

    android {
        ...
        defaultConfig {...}
    
        buildTypes {
            release {
                minifyEnabled true
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
    
            debug {
                applicationIdSuffix ".debug"
            }
        }
    }


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow