חתימת APK

הכלי apksigner, שזמין בגרסה 24.0.3 ואילך של Android SDK Build Tools, מאפשר לכם לחתום על קובצי APK ולוודא שהחתימה של קובץ APK תאומת בהצלחה בכל הגרסאות של פלטפורמת Android שנתמכות על ידי קובץ ה-APK הזה.

בדף הזה מופיע מדריך קצר לשימוש בכלי, והוא משמש כהפניה לאפשרויות השונות של שורת הפקודה שהכלי תומך בהן. תיאור מלא יותר של השימוש בכלי apksigner לחתימה על קובצי APK זמין במאמר בנושא חתימת האפליקציה.

זהירות: אם חותמים על ה-APK באמצעות apksigner ומבצעים שינויים נוספים ב-APK, החתימה של ה-APK תבוטל. אם אתם משתמשים ב-zipalign כדי ליישר את ה-APK, צריך להשתמש בו לפני שחותמים על ה-APK.

שימוש

חתימה על קובץ APK

התחביר לחתימה על קובץ APK באמצעות הכלי apksigner הוא:

apksigner sign --ks keystore.jks |
  --key key.pk8 --cert cert.x509.pem
  [signer_options] app-name.apk

כשחותמים על APK באמצעות הכלי apksigner, צריך לספק את המפתח הפרטי והאישור של החותם. יש שתי דרכים לכלול את המידע הזה:

  • מציינים קובץ KeyStore באמצעות האפשרות --ks.
  • מציינים את קובץ המפתח הפרטי ואת קובץ האישור בנפרד באמצעות האפשרויות --key ו---cert, בהתאמה. קובץ המפתח הפרטי צריך להיות בפורמט PKCS #8, וקובץ האישור צריך להיות בפורמט X.509.

בדרך כלל, חותמים על קובץ APK באמצעות חותם אחד בלבד. אם אתם צריכים לחתום על קובץ APK באמצעות כמה חותמים, השתמשו באפשרות --next-signer כדי להפריד בין קבוצת האפשרויות הכלליות שחלות על כל חותם:

apksigner sign [signer_1_options] --next-signer [signer_2_options] app-name.apk

אימות החתימה של קובץ APK

התחביר לאישור האימות של חתימת APK בפלטפורמות נתמכות הוא:

apksigner verify [options] app-name.apk

ביצוע רוטציה למפתחות החתימה

התחביר להחלפת שושלת של אישורי חתימה או רצף חדש של חתימות הוא כדלקמן:

$ apksigner rotate --in /path/to/existing/lineage \
  --out /path/to/new/file \
  --old-signer --ks old-signer-jks \
  --new-signer --ks new-signer-jks

אפשרויות

ברשימות הבאות מפורטות האפשרויות לכל פקודה שנתמכת בכלי apksigner.

פקודת חתימה

לפקודה apksigner sign יש את האפשרויות הבאות.

אפשרויות כלליות

האפשרויות הבאות מציינות הגדרות בסיסיות שחלות על החותם:

--out <apk-filename>
המיקום שבו רוצים לשמור את קובץ ה-APK החתום. אם האפשרות הזו לא מצוינת במפורש, חבילת ה-APK נחתמת במקום, וכך קובץ ה-APK של הקלט נדרס.
--min-sdk-version <integer>
רמת ה-API הנמוכה ביותר של מסגרת Android שבה apksigner משתמש כדי לוודא שהחתימה של ה-APK תאומת. ערכים גבוהים יותר מאפשרים לכלי להשתמש בפרמטרים חזקים יותר של אבטחה כשחותמים על האפליקציה, אבל מגבילים את הזמינות של קובץ ה-APK למכשירים שמופעלות בהם גרסאות עדכניות יותר של Android. כברירת מחדל, הפונקציה apksigner משתמשת בערך של המאפיין minSdkVersion מקובץ המניפסט של האפליקציה.
--max-sdk-version <integer>
רמת ה-API הגבוהה ביותר של Android framework שבה apksigner נעשה שימוש כדי לוודא שהחתימה של ה-APK תאומת. כברירת מחדל, הכלי משתמש ברמת ה-API הכי גבוהה שאפשר.
--rotation-min-sdk-version <integer>
רמת ה-API הנמוכה ביותר שצריך להשתמש בה במפתח החתימה שעבר רוטציה של ה-APK כדי ליצור את החתימה של ה-APK. חתימת האפליקציה המקורית (ללא רוטציה) של ה-APK תשמש לכל גרסאות הפלטפורמה הקודמות. כברירת מחדל, נעשה שימוש במפתחות חתימה מסובבים, שנתמכים במכשירים עם Android 13 (רמת API‏ 33) ומעלה, עם בלוק החתימה v3.1.

הערה: אם האפליקציה נחתמה על ידי מפתח חתימה שהוחלף במכשיר עם Android 12L (רמת API‏ 32) או גרסה מוקדמת יותר, צריך להשתמש ב---rotation-min-sdk-version 28 כדי להמשיך לחתום על האפליקציה באמצעות מפתח החתימה שהוחלף ב-Android 9 (רמת API‏ 28).

--v1-signing-enabled <true | false>
ההגדרה קובעת אם apksigner חותם על חבילת ה-APK שצוינה באמצעות סכמת החתימה המסורתית שמבוססת על JAR. כברירת מחדל, הכלי משתמש בערכים של --min-sdk-version ושל --max-sdk-version כדי להחליט מתי להחיל את סכמת החתימה הזו.
--v2-signing-enabled <true | false>
ההגדרה קובעת אם apksigner חותם על חבילת ה-APK שצוינה באמצעות APK Signature Scheme v2. כברירת מחדל, הכלי משתמש בערכים של --min-sdk-version ושל --max-sdk-version כדי להחליט מתי להחיל את שיטת החתימה הזו.
--v3-signing-enabled <true | false>
קובעת אם apksigner חותמת על חבילת ה-APK שצוינה באמצעות APK Signature Scheme v3. כברירת מחדל, הכלי משתמש בערכים של --min-sdk-version ושל --max-sdk-version כדי להחליט מתי להחיל את שיטת החתימה הזו.
--v4-signing-enabled <true | false | only>

הפקודה קובעת אם apksigner יחתום על חבילת ה-APK שצוינה באמצעות APK Signature Scheme v4. הסכמה הזו יוצרת חתימה בקובץ נפרד (apk-name.apk.idsig). אם true וה-APK לא חתום, נוצרת חתימה בגרסה v2 או v3 על סמך הערכים של --min-sdk-version ושל --max-sdk-version. הפקודה יוצרת את הקובץ .idsig על סמך התוכן של קובץ ה-APK החתום.

משתמשים ב-only כדי ליצור רק את חתימת v4 בלי לשנות את ה-APK ואת החתימות שהיו בו לפני ההפעלה. הפעולה only נכשלת אם ל-APK אין כבר חתימה מסוג v2 או v3, או אם החתימה השתמשה במפתח שונה מזה שסופק עבור ההפעלה הנוכחית.

כברירת מחדל, הכלי משתמש בערכים של --min-sdk-version ושל --max-sdk-version כדי להחליט מתי להחיל את שיטת החתימה הזו.

-v, --verbose
שימוש במצב פלט מפורט.

אפשרויות לכל חותם

האפשרויות הבאות מציינות את ההגדרה של חותם מסוים. האפשרויות האלה לא נחוצות אם חותמים על האפליקציה באמצעות חותם אחד בלבד.

--next-signer <signer-options>
התג הזה משמש לציון אפשרויות כלליות שונות לכל חותם.
--v1-signer-name <basename>
שם הבסיס של הקבצים שמרכיבים את החתימה מבוססת ה-JAR של החותם הנוכחי. כברירת מחדל, apksigner משתמש בכינוי המפתח של ה-KeyStore או בשם הבסיסי של קובץ המפתח עבור החותם הזה.

אפשרויות של מפתחות ואישורים

באפשרויות הבאות מציינים את המפתח הפרטי והאישור של החותם:

--ks <filename>
המפתח הפרטי של החותם ושרשרת האישורים נמצאים בקובץ KeyStore מבוסס-Java שצוין. אם שם הקובץ מוגדר כ-"NONE", לא צריך לציין קובץ עבור KeyStore שמכיל את המפתח והאישור. זה המצב בחלק מה-KeyStore מסוג PKCS #11.
--ks-key-alias <alias>
השם של הכינוי שמייצג את המפתח הפרטי של החותם ואת נתוני האישור ב-KeyStore. אם מאגר המפתחות שמשויך לבעל החתימה מכיל כמה מפתחות, צריך לציין את האפשרות הזו.
--ks-pass <input-format>

הסיסמה של KeyStore שמכיל את המפתח הפרטי ואת האישור של החותם. כדי לפתוח KeyStore, צריך לספק סיסמה. הכלי apksigner תומך בפורמטים הבאים:

  • pass:<password> – הסיסמה מסופקת בשורה עם שאר הפקודה apksigner sign.
  • env:<name> – הסיסמה מאוחסנת במשתנה הסביבה שצוין.
  • file:<filename> – הסיסמה מאוחסנת כשורה אחת בקובץ הנתון.
  • stdin – הסיסמה מסופקת כשורה אחת בזרם הקלט הרגיל. זוהי התנהגות ברירת המחדל של --ks-pass.

הערה: אם כוללים כמה סיסמאות באותו קובץ, צריך לציין כל אחת מהן בשורה נפרדת. הכלי apksigner משייך סיסמאות לחותמים של APK על סמך הסדר שבו מציינים את החותמים. אם סיפקתם שתי סיסמאות לחותם,‏ apksigner מפרש את הסיסמה הראשונה כסיסמת KeyStore ואת הסיסמה השנייה כסיסמת המפתח.

--pass-encoding <charset>
כולל את קידוד התווים שצוין, כמו ibm437 או utf-8, כשמנסים לטפל בסיסמאות שמכילות תווים שאינם ASCII.

לרוב, Keytool מצפין את מאגרי המפתחות על ידי המרת הסיסמה באמצעות ערכת התווים שמוגדרת כברירת מחדל במסוף. כברירת מחדל, apksigner מנסה לפענח באמצעות כמה צורות של הסיסמה:

  • הטופס של Unicode
  • הטופס מקודד באמצעות ערכת התווים שמוגדרת כברירת מחדל ב-JVM
  • ב-Java 8 ובגרסאות ישנות יותר, הטופס מקודד באמצעות ערכת התווים שמוגדרת כברירת מחדל במסוף
  • ב-Java 9, ‏ apksigner לא יכול לזהות את ערכת התווים של המסוף. יכול להיות שתצטרכו לציין את --pass-encoding אם משתמשים בסיסמה שאינה ASCII. יכול להיות שתצטרכו לציין את האפשרות הזו גם עם KeyStore שנוצר על ידי keytool במערכת הפעלה אחרת או בלוקאל אחר.

    --key-pass <input-format>

    הסיסמה של המפתח הפרטי של החותם, שנדרשת אם המפתח הפרטי מוגן בסיסמה. הכלי apksigner תומך בפורמטים הבאים:

    • pass:<password> – הסיסמה מסופקת בשורה עם שאר הפקודה apksigner sign.
    • env:<name> – הסיסמה מאוחסנת במשתנה הסביבה שצוין.
    • file:<filename> – הסיסמה מאוחסנת כשורה אחת בקובץ הנתון.
    • stdin – הסיסמה מסופקת כשורה אחת בזרם הקלט הרגיל. זוהי התנהגות ברירת המחדל של --key-pass.
    --ks-type <algorithm>
    הסוג או האלגוריתם שמשויכים למאגר המפתחות שמכיל את המפתח הפרטי ואת האישור של החותם. כברירת מחדל, הפקודה apksigner משתמשת בסוג שמוגדר כקבוע keystore.type בקובץ מאפייני האבטחה.
    --ks-provider-name <name>
    השם של ספק ה-JCA שבו יש להשתמש כשמבקשים את ההטמעה של KeyStore של החותם. כברירת מחדל, apksigner משתמש בספק עם העדיפות הכי גבוהה.
    --ks-provider-class <class-name>
    השם המלא של המחלקה של ספק ה-JCA שבו יש להשתמש כשמבקשים את ההטמעה של KeyStore של החותם. האפשרות הזו משמשת כחלופה ל--ks-provider-name. כברירת מחדל, apksigner משתמש בספק שצוין באפשרות --ks-provider-name.
    --ks-provider-arg <value>
    ערך מחרוזת שמועבר כארגומנט לקונסטרוקטור של המחלקה JCA Provider. המחלקה עצמה מוגדרת באמצעות האפשרות --ks-provider-class. כברירת מחדל, apksigner משתמש בבונה ללא ארגומנטים של המחלקה.
    --key <filename>
    השם של הקובץ שמכיל את המפתח הפרטי של החותם. הקובץ הזה חייב להיות בפורמט PKCS #8 DER. אם המפתח מוגן באמצעות סיסמה, apksigner מוצגת בקשה להזנת הסיסמה באמצעות קלט רגיל אלא אם מציינים סוג אחר של פורמט קלט באמצעות האפשרות --key-pass.
    --cert <filename>
    השם של הקובץ שמכיל את שרשרת האישורים של החותם. הקובץ הזה צריך להיות בפורמט X.509 PEM או DER.

    אימות הפקודה

    לפקודה apksigner verify יש את האפשרויות הבאות.

    --print-certs
    הצגת מידע על אישורי החתימה של קובץ ה-APK.
    --print-certs-pem
    הצגת מידע על אישורי החתימה של חבילת ה-APK והדפסת קידוד ה-PEM של כל אישור חתימה ל-stdout.
    --min-sdk-version <integer>
    רמת ה-API הנמוכה ביותר של מסגרת Android שבה apksigner משתמש כדי לוודא שהחתימה של ה-APK תאומת. ערכים גבוהים יותר מאפשרים לכלי להשתמש בפרמטרים חזקים יותר של אבטחה כשחותמים על האפליקציה, אבל מגבילים את הזמינות של קובץ ה-APK למכשירים שמופעלות בהם גרסאות עדכניות יותר של Android. כברירת מחדל, הפונקציה apksigner משתמשת בערך של המאפיין minSdkVersion מקובץ המניפסט של האפליקציה.
    --max-sdk-version <integer>
    רמת ה-API הגבוהה ביותר של Android framework שבה apksigner נעשה שימוש כדי לוודא שהחתימה של ה-APK תאומת. כברירת מחדל, הכלי משתמש ברמת ה-API הכי גבוהה שאפשר.
    -v, --verbose
    שימוש במצב פלט מפורט.
    -Werr
    התייחסות לאזהרות כשגיאות.

    דוגמאות

    הדוגמאות הבאות מציגות שימוש ב-apksigner.

    חתימה על קובץ APK

    חותמים על APK באמצעות release.jks, שהוא המפתח היחיד ב-KeyStore:

    $ apksigner sign --ks release.jks app.apk
    

    חתימה על קובץ APK באמצעות מפתח פרטי ואישור שמאוחסנים כקבצים נפרדים:

    $ apksigner sign --key release.pk8 --cert release.x509.pem app.apk
    

    כדי לחתום על קובץ APK באמצעות שני מפתחות:

    $ apksigner sign --ks first-release-key.jks --next-signer --ks second-release-key.jks app.apk
    

    כדי לחתום על APK באמצעות מפתח חתימה שעבר רוטציה, ולכוון את הרוטציה לגרסת SDK 28 ומעלה:

    $ apksigner sign --ks release.jks --next-signer --ks release2.jks \
      --lineage /path/to/signing/history/lineage app.apk \
      --rotation-min-sdk-version 28
    

    כדי לחתום על APK באמצעות מפתח חתימה שעבר רוטציה, ולכוון את הרוטציה לגרסה 33 ואילך של SDK:

    $ apksigner sign --ks release.jks --next-signer --ks release2.jks \
      --lineage /path/to/signing/history/lineage app.apk
    

    אימות החתימה של קובץ APK

    בודקים אם החתימות של קובץ ה-APK צפויות להיות מאושרות כחוקיות בכל פלטפורמות Android שקובץ ה-APK תומך בהן:

    $ apksigner verify app.apk
    

    בודקים אם החתימות של ה-APK אמורות להיות מאושרות כתקפות ב-Android 4.0.3 (רמת API‏ 15) ואילך:

    $ apksigner verify --min-sdk-version 15 app.apk
    

    ביצוע רוטציה למפתחות החתימה

    הפעלת שושלת של אישורי חתימה שתומכת ברוטציה של מפתחות:

    $ apksigner rotate --out /path/to/new/file --old-signer \
        --ks release.jks --new-signer --ks release2.jks

    מבצעים שוב רוטציה של מפתחות החתימה:

    $ apksigner rotate --in /path/to/existing/lineage \
      --out /path/to/new/file --old-signer --ks release2.jks \
      --new-signer --ks release3.jks