גרסאות Java בגרסאות build של Android

בין שקוד המקור שלכם נכתב ב-Java, ב-Kotlin או בשתיהן, יש כמה מקומות שבהם עליכם לבחור גרסת JDK או שפת Java ל-build.

סקירה כללית של קשרי JDK ב-build של Gradle
איור 1. יחסי JDK ב-build

מילון מונחים

Java Development Kit‏ (JDK)
ערכת הכלים לפיתוח Java‏ (JDK) כוללת:
  • כלים, כמו קומפיילר, כלי לניתוחי פרופיל ויצירת ארכיונים. אפשר להשתמש בהם מאחורי הקלעים במהלך ה-build כדי ליצור את האפליקציה.
  • ספריות שמכילות ממשקי API שאפשר להפעיל מקוד המקור של Kotlin או Java. חשוב לזכור שלא כל הפונקציות זמינות ב-Android.
  • Java Virtual Machine‏ (JVM), מתורגמן שמריץ אפליקציות Java. משתמשים ב-JVM כדי להריץ את סביבת הפיתוח המשולבת (IDE) של Android Studio ואת הכלי ל-build של Gradle. לא נעשה שימוש ב-JVM במכשירי Android או במהירי Android.
JetBrains Runtime (JBR)
JetBrains Runtime‏ (JBR) הוא JDK משופר שמופץ עם Android Studio. הוא כולל כמה אופטימיזציות לשימוש ב-Studio ובמוצרים קשורים של JetBrains, אבל אפשר להשתמש בו גם להרצת אפליקציות Java אחרות.

איך בוחרים JDK כדי להפעיל את Android Studio?

מומלץ להשתמש ב-JBR כדי להריץ את Android Studio. הוא נפרס עם Android Studio ומשמשים לבדיקת Android Studio, והוא כולל שיפורים לשימוש אופטימלי ב-Android Studio. כדי לוודא זאת, אל תגדירו את משתנה הסביבה STUDIO_JDK.

סקריפטים לטעינה בזמן ההפעלה של Android Studio מחפשים JVM בסדר הבא:

  1. משתנה הסביבה STUDIO_JDK
  2. הספרייה studio.jdk (בהפצה של Android Studio)
  3. ספריית jbr (JetBrains Runtime), בהפצה של Android Studio. מומלץ.
  4. משתנה הסביבה JDK_HOME
  5. משתנה סביבה אחד (JAVA_HOME)
  6. קובץ ההפעלה java במשתנה הסביבה PATH

איך בוחרים את JDK שבו יפעלו ה-builds של Gradle?

אם אתם מריצים את Gradle באמצעות הלחצנים ב-Android Studio, ה-JDK שהוגדר בהגדרות Android Studio ישמש להפעלת Gradle. אם מריצים את Gradle במסוף, בתוך Android Studio או מחוץ אליו, משתנה הסביבה JAVA_HOME (אם הוא מוגדר) קובע איזה JDK ירוץ את הסקריפטים של Gradle. אם JAVA_HOME לא מוגדר, המערכת משתמשת בפקודה java במשתנה הסביבה PATH.

כדי לקבל תוצאות עקביות ביותר, חשוב להגדיר את משתנה הסביבה JAVA_HOME ואת ההגדרות של Gradle JDK ב-Android Studio לאותו JDK.

כשמריצים את ה-build, Gradle יוצר תהליך שנקרא daemon כדי לבצע את ה-build בפועל. אפשר לעשות שימוש חוזר בתהליך הזה, כל עוד ב-builds נעשה שימוש באותה גרסת JDK ו-Gradle. שימוש חוזר בדימון מפחית את הזמן הנדרש להפעלת JVM חדשה ולהפעלת מערכת ה-build.

אם מתחילים גרסאות build עם גרסאות שונות של JDK או Gradle, נוצרים עוד דימונים (daemons) שמנצלים יותר מעבד וזיכרון.

הגדרת Gradle JDK ב-Android Studio

כדי לשנות את ההגדרות האישיות של Gradle JDK בפרויקט קיים, פותחים את ההגדרות של Gradle דרך File (או דרך Android Studio ב-macOS) > Settings > Build, Execution, Deployment > Build Tools > Gradle. בתפריט הנפתח Gradle JDK תוכלו לבחור מבין האפשרויות הבאות:

  • רכיבי מאקרו כמו JAVA_HOME ו-GRADLE_LOCAL_JAVA_HOME
  • רשומות בטבלה של JDK בפורמט vendor-version, כמו jbr-17, שמאוחסנות בקבצי התצורה של Android
  • הורדת JDK
  • הוספת JDK ספציפי
  • גרסאות JDK שזוהו באופן מקומי מהספרייה שמוגדרת כברירת מחדל להתקנת JDK במערכת ההפעלה

האפשרות שנבחרה מאוחסנת באפשרות gradleJvm בקובץ .idea/gradle.xml של הפרויקט, והפתרון של נתיב ה-JDK משמש להפעלת Gradle כשמפעילים אותו דרך Android Studio.

איור 2. הגדרות Gradle JDK ב-Android Studio.

המאקרו מאפשר בחירת נתיב JDK דינמי לפרויקט:

  • JAVA_HOME: משתמש במשתנה הסביבה עם אותו שם
  • GRADLE_LOCAL_JAVA_HOME: משתמש במאפיין java.home בקובץ .gradle/config.properties, שמוגדר כברירת מחדל ל-JetBrains Runtime.

JDK שנבחר משמש להרצת ה-build של Gradle ולפתרון הפניות ל-JDK API בזמן העריכה של סקריפטים ל-build וקוד המקור. הערה: הערך שצוין בשדה compileSdk יגדיר אילו סמלי Java יהיו זמינים בזמן העריכה והיצירה של קוד המקור.

חשוב לבחור גרסת JDK שגדולה או שווה לגרסאות ה-JDK שבהן משתמשים הפלאגינים שבהם אתם משתמשים ב-build של Gradle. כדי לבדוק מהי גרסת ה-JDK המינימלית הנדרשת לפלאגין Android Gradle (AGP), אפשר לעיין בטבלת התאימות שמופיעה בהערות המוצר.

לדוגמה, כדי להשתמש ב-Android Gradle Plugin בגרסה 8.x צריך JDK 17. אם תנסו להריץ build של Gradle שמשתמש בו עם גרסה קודמת של JDK, תוצג הודעה כמו:

An exception occurred applying plugin request [id: 'com.android.application']
> Failed to apply plugin 'com.android.internal.application'.
   > Android Gradle plugin requires Java 17 to run. You are currently using Java 11.
      Your current JDK is located in /usr/local/buildtools/java/jdk
      You can try some of the following options:
       - changing the IDE settings.
       - changing the JAVA_HOME environment variable.
       - changing `org.gradle.java.home` in `gradle.properties`.

באילו ממשקי API של Java אפשר להשתמש בקוד המקור של Java או Kotlin?

אפליקציות ל-Android יכולות להשתמש בחלק מממשקי ה-API שמוגדרים ב-JDK, אבל לא בכולם. ב-Android SDK מוגדרים הטמעות של פונקציות רבות בספריית Java כחלק מממשקי ה-API שזמינים לה. המאפיין compileSdk מציין באיזו גרסה של Android SDK יש להשתמש כשמפעילים הידור של קוד המקור ב-Kotlin או ב-Java.

Kotlin

android {
    ...
    compileSdk = 33
}

Groovy

android {
    ...
    compileSdk 33
}

כל גרסה של Android תומכת בגרסה ספציפית של JDK ובקבוצת משנה של ממשקי ה-API הזמינים של Java. אם אתם משתמשים ב-Java API שזמין ב-compileSdk שאינו זמין ב-minSdk שצוין, יכול להיות שתוכלו להשתמש ב-API בגרסה הקודמת של Android באמצעות תהליך שנקרא desugaring. למידע על ממשקי ה-API הנתמכים, ראו ממשקי API של Java 11 ואילך שזמינים באמצעות הסרת סוכרים.

בטבלה הזו תוכלו לראות באיזו גרסה של Java כל ממשק API ל-Android תומך, ואיפה אפשר למצוא פרטים על ממשקי ה-API ל-Java שזמינים.

Android Java תכונות ה-API והשפה הנתמכות
14 (API 34) 17 ספריות ליבה
13 (API 33) 11 ספריות ליבה
12 (API 32) 11 Java API
11 ומטה גרסאות Android

איזה JDK אוסף את קוד המקור שלי ב-Java?

JDK של Java toolchain מכיל את המהדר של Java שמשמש להדרת כל קוד מקור של Java. JDK הזה גם מפעיל javadoc ובדיקות יחידה במהלך ה-build.

ברירת המחדל של כלי הפיתוח היא JDK שמשמש להפעלת Gradle. אם משתמשים בברירת המחדל ומריצים build במכונות שונות (לדוגמה, במכונה המקומית ובשרת אינטגרציה רציפה (CI) נפרד), התוצאות של ה-build עשויות להשתנות אם משתמשים בגרסאות JDK שונות.

כדי ליצור גרסה עקבית יותר של ה-build, אפשר לציין באופן מפורש את הגרסה של כלי הפיתוח של Java. מציינים את הפרטים הבאים:

  • מאתרת JDK תואם במערכת שבה פועל ה-build.
    • אם אין JDK תואם (והוגדר פותר של כלי פיתוח), מתבצע הורדה של JDK.
  • חשיפת ממשקי ה-API של Java בכלי הפיתוח לקריאות מקוד מקור.
  • קומפילציה של קוד מקור Java באמצעות גרסת שפת Java שלו.
  • ברירת המחדל של ציוד ומוצרים עבור sourceCompatibility ו-targetCompatibility.

תמיד מומלץ לציין את ה-toolchain של Java ולוודא שה-JDK שצוין מותקן או להוסיף מקודדtoolchain ל-build.

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

מציינים את גרסת כלי הפיתוח של Java באופן הבא:

Kotlin

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

Groovy

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

אפשרות זו מתאימה אם המקור הוא Kotlin , Java או שילוב של שניהם.

גרסת ה-JDK של כלי הפיתוח יכולה להיות זהה ל-JDK שמשמש להפעלת Gradle, אבל חשוב לזכור שהן משמשות למטרות שונות.

באילו תכונות מקור של שפת Java אפשר להשתמש בקוד המקור של Java?

המאפיין sourceCompatibility קובע אילו תכונות של שפת Java יהיו זמינות במהלך הידור של מקור Java. היא לא משפיעה על המקור של Kotlin.

מציינים את sourceCompatibility בקובץ build.gradle(.kts) של המודול באופן הבא:

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
    }
}

Groovy

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
    }
}

אם לא מציינים זאת, ברירת המחדל של המאפיין הזה היא גרסת Java Toolchain. אם לא משתמשים ב-Java Toolchain, ברירת המחדל תהיה גרסה שנבחרה על ידי הפלאגין Android Gradle (לדוגמה, Java 8 ואילך).

באילו תכונות בינאריות של Java אפשר להשתמש בהדרת מקור Kotlin או Java?

המאפיינים targetCompatibility ו-jvmTarget קובעים את גרסת פורמט הכיתה של Java שבה נעשה שימוש בזמן יצירת קוד באקס (bytecode) למקורות Java ו-Kotlin שהומרו.

חלק מהתכונות של Kotlin היו קיימות לפני שהתכונות המקבילות ב-Java נוספו. בעבר, קומפילרים מוקדמים של Kotlin נאלצו ליצור דרך משלהם לייצוג התכונות האלה של Kotlin. חלק מהתכונות האלה נוספו מאוחר יותר ל-Java. ברמות jvmTarget מאוחרות יותר, יכול להיות שמהדר ה-Kotlin ישתמש ישירות בתכונה של Java, וכתוצאה מכך הביצועים יהיו טובים יותר.

גרסאות שונות של Android תומכות בגרסאות שונות של Java. כדי ליהנות מתכונות נוספות של Java, אפשר להגדיל את הערכים של targetCompatibility ו-jvmTarget, אבל יכול להיות שתצטרכו להגדיל גם את גרסת ה-SDK המינימלית של Android כדי לוודא שהתכונה זמינה.

לתשומת ליבכם, targetCompatibility חייב להיות גדול מ-sourceCompatibility או שווה לו. בפועל, בדרך כלל צריך להשתמש באותו ערך בשדות sourceCompatibility,‏ targetCompatibility ו-jvmTarget. אפשר להגדיר אותם באופן הבא:

Kotlin

android {
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget = "17"
    }
}

Groovy

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget '17'
    }
}

אם לא מציינים את המאפיינים האלה, ברירת המחדל שלהם היא הגרסה של Java toolchain. אם אתם לא משתמשים בכלי פיתוח של Java, ערכי ברירת המחדל עשויים להיות שונים ולגרום לבעיות ב-build. לכן, מומלץ תמיד לציין את הערכים האלה באופן מפורש או להשתמש בערכת כלים של Java.