העברת תצורת ה-build מ-Groovy ל-Kotlin

בפלאגין Android Gradle מגרסה 4.0 נוספה תמיכה בשימוש ב-Kotlin בהגדרת ה-build של Gradle כתחליף ל-Groovy, שפת התכנות שמשמשת בדרך כלל בקובצי ההגדרה של Gradle.

עדיף להשתמש ב-Kotlin במקום ב-Groovy לכתיבת סקריפטים של Gradle, כי קל יותר לקרוא את Kotlin, והיא מציעה בדיקה טובה יותר בזמן ההידור ותמיכה טובה יותר ב-IDE.

למרות ש-Kotlin מציעה כרגע שילוב טוב יותר בעורך הקוד של Android Studio בהשוואה ל-Groovy, תהליכי build באמצעות Kotlin נוטים להיות איטיים יותר מתהליכי build באמצעות Groovy, לכן כדאי לקחת בחשבון את ביצועי ה-build כשמחליטים אם לבצע העברה.

בדף הזה מוסבר איך להמיר את קובצי ה-build של Gradle באפליקציית Android מ-Groovy ל-Kotlin. למדריך מקיף יותר בנושא העברה, אפשר לעיין במסמכי התיעוד הרשמיים של Gradle.

ציר הזמן

החל מ-Android Studio Giraffe, פרויקטים חדשים משתמשים ב-Kotlin DSL ‏(build.gradle.kts) כברירת מחדל להגדרת ה-build. היא מציעה חוויית עריכה טובה יותר מאשר Groovy DSL‏ (build.gradle) עם הדגשת תחביר, השלמת קוד וניווט להצהרות. מידע נוסף זמין במאמר מבוא ל-Gradle Kotlin DSL.

תקופות ביטוח מקובלות

Kotlin DSL: מתייחס בעיקר ל-Android Gradle plugin Kotlin DSL או, מדי פעם, ל-underlying Gradle Kotlin DSL.

במדריך הזה להעברת נתונים, אנחנו משתמשים במונחים Kotlin ו-Kotlin DSL לסירוגין. באופן דומה, אנחנו משתמשים במונחים Groovy ו-Groovy DSL לסירוגין.

מתן שמות לקובצי סקריפט

שמות הסיומות של קובצי הסקריפט מבוססים על השפה שבה נכתב קובץ ה-build:

  • קובצי build של Gradle שנכתבו ב-Groovy משתמשים בסיומת שם הקובץ .gradle.
  • קובצי build של Gradle שנכתבו ב-Kotlin משתמשים בתוסף שם הקובץ .gradle.kts.

המרת התחביר

יש כמה הבדלים כלליים בתחביר בין Groovy לבין Kotlin, ולכן צריך להחיל את השינויים האלה בכל סקריפטי ה-build.

הוספת סוגריים לקריאות לשיטות

ב-Groovy אפשר להשמיט סוגריים בקריאות ל-method, אבל ב-Kotlin הם נדרשים. כדי להעביר את ההגדרה, מוסיפים סוגריים לקריאות לשיטות מהסוגים האלה. הקוד הבא מראה איך להגדיר הגדרה ב-Groovy:

compileSdkVersion 30

זה אותו קוד שנכתב ב-Kotlin:

compileSdkVersion(30)

הוספת = לשיחות במטלות

ב-Groovy DSL אפשר להשמיט את אופרטור ההשמה = כשמגדירים מאפיינים, אבל ב-Kotlin הוא נדרש. הקוד הבא מראה איך להקצות מאפיינים ב-Groovy:

java {
    sourceCompatibility JavaVersion.VERSION_17
    targetCompatibility JavaVersion.VERSION_17
}

הקוד הזה מראה איך להקצות מאפיינים ב-Kotlin:

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

המרת מחרוזות

אלה ההבדלים במחרוזות בין Groovy לבין Kotlin:

  • מירכאות כפולות למחרוזות: ב-Groovy אפשר להגדיר מחרוזות באמצעות גרשיים, אבל ב-Kotlin צריך להשתמש במירכאות כפולות.
  • הצבת מחרוזות בתוך מחרוזות (String interpolation) בביטויים עם נקודות: ב-Groovy, אפשר להשתמש רק בקידומת $ בשביל הצבת מחרוזות בתוך מחרוזות בביטויים עם נקודות, אבל ב-Kotlin צריך להוסיף סוגריים מסולסלים מסביב לביטויים עם נקודות. לדוגמה, ב-Groovy אפשר להשתמש ב-$project.rootDir כמו בקטע הקוד הבא:

        myRootDirectory = "$project.rootDir/tools/proguard-rules-debug.pro"
        

    לעומת זאת, בקוד הקודם ב-Kotlin, הפונקציה toString() נקראת ב-project ולא ב-project.rootDir. כדי לקבל את הערך של ספריית הבסיס, מקיפים את הביטוי ${project.rootDir} בסוגריים מסולסלים:

        myRootDirectory = "${project.rootDir}/tools/proguard-rules-debug.pro"
        

    מידע נוסף זמין במאמר בנושא תבניות מחרוזות במסמכי התיעוד של Kotlin.

שינוי השם של סיומות קבצים

מוסיפים את .kts לכל קובץ build כשמעבירים את התוכן שלו. לדוגמה, בוחרים קובץ build, כמו קובץ settings.gradle. משנים את שם הקובץ ל-settings.gradle.kts וממירים את התוכן של הקובץ ל-Kotlin. חשוב לוודא שהפרויקט עדיין עובר קומפילציה אחרי ההעברה של כל קובץ build.

כדאי להתחיל בהעברת הקבצים הקטנים ביותר כדי לצבור ניסיון, ורק אחר כך להמשיך. אפשר לשלב קובצי build של Kotlin ו-Groovy בפרויקט, לכן כדאי להקדיש זמן למעבר הזה ולבצע אותו בקפידה.

מחליפים את def ב-val או ב-var

מחליפים את def ב-val או ב-var, שזו הדרך להגדיר משתנים ב-Kotlin. זוהי הצהרה על משתנה ב-Groovy:

def building64Bit = false

זה אותו קוד שנכתב ב-Kotlin:

val building64Bit = false

הוספת התחילית is למאפיינים בוליאניים

ב-Groovy נעשה שימוש בלוגיקה של הסקת מאפיינים על סמך שמות המאפיינים. עבור נכס בוליאני foo, השיטות שמוסקות יכולות להיות getFoo, setFoo או isFoo. לכן, אחרי ההמרה ל-Kotlin, צריך לשנות את שמות המאפיינים לשיטות שהוסקו ושלא נתמכות על ידי Kotlin. לדוגמה, כדי להשתמש באלמנטים בוליאניים ב-DSL של buildTypes, צריך להוסיף להם את הקידומת is. בדוגמה הבאה של קוד אפשר לראות איך מגדירים מאפיינים בוליאניים ב-Groovy:

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            ...
        }
        debug {
            debuggable true
            ...
        }
    ...

בהמשך מופיע אותו קוד ב-Kotlin. שימו לב שהמאפיינים מתחילים בקידומת is.

android {
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            isShrinkResources = true
            ...
        }
        getByName("debug") {
            isDebuggable = true
            ...
        }
    ...

המרת רשימות ומפות

התחביר שמשמש להגדרת רשימות ומפות ב-Groovy וב-Kotlin שונה. ב-Groovy משתמשים ב-[], וב-Kotlin קוראים לשיטות ליצירת אוסף באופן מפורש באמצעות listOf או mapOf. במהלך ההעברה, חשוב להקפיד להחליף את [] ב-listOf או ב-mapOf.

כך מגדירים רשימה ב-Groovy לעומת Kotlin:

jvmOptions += ["-Xms4000m", "-Xmx4000m", "-XX:+HeapDumpOnOutOfMemoryError</code>"]

זה אותו קוד שנכתב ב-Kotlin:

jvmOptions += listOf("-Xms4000m", "-Xmx4000m", "-XX:+HeapDumpOnOutOfMemoryError")

כך מגדירים מפה ב-Groovy לעומת Kotlin:

def myMap = [key1: 'value1', key2: 'value2']

זה אותו קוד שנכתב ב-Kotlin:

val myMap = mapOf("key1" to "value1", "key2" to "value2")

הגדרת סוגי build

ב-Kotlin DSL, רק סוגי ה-build של debug ו-release זמינים באופן מרומז. צריך ליצור ידנית את כל שאר סוגי הבנייה המותאמת אישית.

ב-Groovy אפשר להשתמש בסוגי build מסוימים כמו debug ו-release בלי ליצור אותם קודם. בקטע הקוד הבא מוצגת הגדרה עם סוגי ה-build‏ debug, release ו-benchmark ב-Groovy.

buildTypes {
 debug {
   ...
 }
 release {
   ...
 }
 benchmark {
   ...
 }
}

כדי ליצור את ההגדרה המקבילה ב-Kotlin, צריך ליצור במפורש את benchmark סוג ה-build.

buildTypes {
 debug {
   ...
 }

 release {
   ...
 }
 register("benchmark") {
    ...
 }
}

העברה מ-buildscript לבלוק plugins

אם אתם משתמשים בבלוק buildscript {} כדי להוסיף פלאגינים לפרויקט, אתם צריכים לשנות את הקוד כך שישתמש בבלוק plugins {}. הבלוק plugins {} מאפשר להחיל פלאגינים בקלות, והוא פועל היטב עם קטלוגים של גרסאות.

בנוסף, כשמשתמשים בבלוק plugins {} בקובצי ה-build,‏ Android Studio מודע להקשר גם אם ה-build נכשל. ההקשר הזה עוזר לבצע תיקונים בקובצי Kotlin DSL, כי הוא מאפשר ל-IDE של Studio להשלים קוד ולספק הצעות מועילות אחרות.

איך מוצאים את מזהי הפלאגינים

בלוק buildscript {} מוסיף את הפלאגינים לנתיב המחלקה של ה-build באמצעות קואורדינטות Maven של הפלאגין, לדוגמה com.android.tools.build:gradle:7.4.0, אבל בלוק plugins {} משתמש במזהי הפלאגינים.

ברוב הפלאגינים, מזהה הפלאגין הוא המחרוזת שמשמשת כשמחילים אותם באמצעות apply plugin. לדוגמה, מזהי הפלאגין הבאים הם חלק מAndroid Gradle Plugin:

  • com.android.application
  • com.android.library
  • com.android.lint
  • com.android.test

רשימת הפלאגינים המלאה זמינה במאגר Maven של Google.

אפשר להפנות לפלאגינים של Kotlin באמצעות כמה מזהי פלאגין. מומלץ להשתמש במזהה התוסף של מרחב השמות, ולשנות את המזהה המקוצר למזהה התוסף של מרחב השמות באמצעות הטבלה הבאה:

מזהי פלאגין מקוצרים מזהי פלאגין עם מרחב שמות
kotlin org.jetbrains.kotlin.jvm
kotlin-android org.jetbrains.kotlin.android
kotlin-kapt org.jetbrains.kotlin.kapt
kotlin-parcelize org.jetbrains.kotlin.plugin.parcelize

אפשר גם לחפש פלאגינים בGradle Plugin Portal, ב-Maven Central Repository וב-Google Maven repository. במאמר פיתוח פלאגינים מותאמים אישית של Gradle מוסבר איך מזהי פלאגינים פועלים.

ביצוע רפקטורינג

אחרי שמזהים את המזהים של הפלאגינים שבהם אתם משתמשים, פועלים לפי השלבים הבאים:

  1. אם עדיין יש לכם מאגרי פלאגינים שהוגדרו בבלוק buildscript {}, צריך להעביר אותם לקובץ settings.gradle.

  2. מוסיפים את התוספים לבלוק plugins {} בקובץ build.gradle ברמה העליונה. כאן צריך לציין את המזהה ואת הגרסה של הפלאגין. אם אין צורך להחיל את הפלאגין על פרויקט הבסיס, משתמשים ב-apply false.

  3. מסירים את הערכים classpath מהקובץ build.gradle.kts ברמה העליונה.

  4. כדי להחיל את הפלאגינים, מוסיפים אותם לבלוק plugins {} בקובץ build.gradle ברמת המודול. כאן צריך לציין רק את המזהה של הפלאגין, כי הגרסה עוברת בירושה מפרויקט הבסיס.

  5. מסירים את הקריאה apply plugin לתוסף מהקובץ build.gradle ברמת המודול.

לדוגמה, בהגדרה הזו נעשה שימוש בבלוק buildscript {}:

// Top-level build.gradle file
buildscript {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
    dependencies {
        classpath("com.android.tools.build:gradle:7.4.0")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0")
        ...
    }
}

// Module-level build.gradle file
apply(plugin: "com.android.application")
apply(plugin: "kotlin-android")

זוהי הגדרה מקבילה באמצעות הבלוק plugins {}:

// Top-level build.gradle file
plugins {
   id 'com.android.application' version '7.4.0' apply false
   id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
   ...
}

// Module-level build.gradle file
plugins {
   id 'com.android.application'
   id 'org.jetbrains.kotlin.android'
   ...
}

// settings.gradle
pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}

המרת בלוק הפלאגינים

השימוש בפלאגינים מהבלוק plugins {} דומה ב-Groovy וב-Kotlin. בדוגמת הקוד הבאה אפשר לראות איך להחיל פלאגינים ב-Groovy כשמשתמשים בקטלוגים של גרסאות:

// Top-level build.gradle file
plugins {
   alias libs.plugins.android.application apply false
   ...
}

// Module-level build.gradle file
plugins {
   alias libs.plugins.android.application
   ...
}

בדוגמה הבאה אפשר לראות איך עושים את אותו הדבר ב-Kotlin:

// Top-level build.gradle.kts file
plugins {
   alias(libs.plugins.android.application) apply false
   ...
}

// Module-level build.gradle.kts file
plugins {
   alias(libs.plugins.android.application)
   ...
}

בדוגמת הקוד הבאה אפשר לראות איך להחיל פלאגינים ב-Groovy כשלא משתמשים בקטלוגים של גרסאות:

// Top-level build.gradle file
plugins {
   id 'com.android.application' version '7.3.0' apply false
   ...
}

// Module-level build.gradle file
plugins {
   id 'com.android.application'
   ...
}

בדוגמה הבאה אפשר לראות איך עושים את אותו הדבר ב-Kotlin:

// Top-level build.gradle.kts file
plugins {
   id("com.android.application") version "7.3.0" apply false
   ...
}

// Module-level build.gradle.kts file
plugins {
   id("com.android.application")
   ...
}

פרטים נוספים על הבלוק plugins {} מופיעים במאמר הוספת פלאגינים במסמכי התיעוד של Gradle.

שונות

דוגמאות קוד ב-Kotlin לפונקציות אחרות מופיעות בדפי התיעוד הבאים:

בעיות מוכרות

נכון לעכשיו, בעיה ידועה היא שמהירות הבנייה עשויה להיות איטית יותר עם Kotlin מאשר עם Groovy.

איך מדווחים על בעיות

הוראות לשליחת המידע שדרוש לנו כדי לתעדף את הבעיה מופיעות במאמר פרטים על באגים בכלי build וב-Gradle. אחר כך, מדווחים על באג באמצעות הכלי הציבורי של Google למעקב אחר בעיות.

משאבים נוספים

דוגמה לקובצי build של Gradle שנכתבו באמצעות Kotlin זמינה באפליקציה לדוגמה Now In Android ב-GitHub.