Android Developer Console API

Android Developer Console API הוא שירות RESTful שמאפשר למפתחים מאומתים להפוך את תהליכי העבודה של אימות למפתחי Android לאוטומטיים ב-Android Developer Console, כולל אחזור חשבונות פיתוח, בדיקת דרישות הסף של המפתחות, רישום שמות של חבילות Android, רישום מפתחות לחתימת אפליקציות ואימות הבעלות על המפתחות.

סקירה כללית, תרחישים לדוגמה והקשר ההטמעה

תרחישי שימוש ותכונות עיקריים

  • רישום אוטומטי של שמות חבילות ב-CI/CD: רישום של עשרות או מאות שמות של חבילות Android באופן פרוגרמטי (CreateAndroidPackage).
  • בדיקה מקדימה של מדיניות המפתחות ההיסטורית: בדיקה פרוגרמטית אם Google זיהתה בעבר שם חבילה בסביבה העסקית, ואם רישום של אישור חתימה ספציפי מחייב אימות בעלות על המפתח (GetAndroidPackageRegistrationPolicy).
  • רישום אוטומטי של מפתחות לחתימת אפליקציות ואימות בעלות: רישום טביעות אצבע מסוג SHA-256 של אישורי חתימה ציבוריים (CreateAndroidPackageKey), אחזור טוקנים ייחודיים של אתגרי אימות (verificationToken) ואוטומציה של הוכחת החזקה של מפתח פרטי באמצעות העלאות של קובצי APK חתומים בבקשה אחת או בהעלאות שניתן להמשיך (VerifyAndroidPackageKeyOwnership).
  • שליחת הצדקות באופן פרוגרמטי: שליחת הצדקות לבעלות (JustifyAndroidPackageKeyRegistration).
  • מעקב אחרי סטטוס: מעקב אחרי סטטוס הרישום בחשבונות פיתוח, שמות חבילות ומפתחות לחתימת אפליקציות (GetDeveloperAccount, ListDeveloperAccounts, GetAndroidPackage, ListAndroidPackages, GetAndroidPackageKey, ListAndroidPackageKeys).

תהליך עבודה להטמעה מקצה לקצה

  1. אימות זהות המפתח פעם אחת בממשק המשתמש: משלימים את אימות זהות המפתח (INDIVIDUAL או ORGANIZATION) ב-Android Developer Console כדי ש-verificationState יהיה VERIFIED.
  2. מפעילים את ה-API ומאמתים: מפעילים את androiddeveloperconsole.googleapis.com בפרויקט ב-Google Cloud ומקבלים אסימון גישה מסוג Bearer של OAuth 2.0 עם היקף https://www.googleapis.com/auth/androiddeveloperconsole שהוקצה למשתמש.
  3. מאתרים את שם המשאב של חשבון הפיתוח: מפעילים את GET /v1/developerAccounts (ListDeveloperAccounts) כדי לאחזר את developerAccounts/{developer_account} ולוודא שהערך של verificationState הוא VERIFIED.
  4. בודקים את מדיניות הרישום של שם החבילה: מפעילים את GET /v1/developerAccounts/{id}/androidPackages/{pkg}/registrationPolicy (GetAndroidPackageRegistrationPolicy) כדי לבדוק את keySelectionStrategy (SELECT_KEY_FROM_LIST או USE_ANY_KEY) ואת כל מפתחות החתימה ההיסטוריים הידועים (knownKeys).
  5. יוצרים את המשאב של חבילת Android: מפעילים את POST /v1/developerAccounts/{id}/androidPackages?androidPackageId={pkg} (CreateAndroidPackage) עם גוף {"name": ""} (יוצר משאב במצב DRAFT).
  6. רישום טביעת האצבע של מפתח לחתימת אפליקציות: שולחים קריאה ל-POST /v1/developerAccounts/{id}/androidPackages/{pkg}/keys (CreateAndroidPackageKey) עם גוף JSON‏ {"certificateFingerprintSha256": "..."}. בודקים את המצב שהוחזר:
    • ‫DRAFT: נדרשת הוכחה לבעלות על המפתח הפרטי, והתשובה כוללת verificationToken ייחודי לשלב 7.
    • ‫IN_REVIEW: המערכת מדלגת באופן אוטומטי על הוכחת הבעלות וההצדקה (לדוגמה, כשרושמים שם חבילה חדש שלא הופיע אף פעם ב-Android, או כשכבר אימתתם את הבעלות על מפתח החתימה הזה בשביל שם חבילה אחר באותו DeveloperAccount). דלגו על שלב 7 ועל הקריאה להצדקה בשלב 8, והמשיכו ישירות לדגימה של GetAndroidPackage ו-GetAndroidPackageKey.
  7. יוצרים ומעלים את קובץ ה-APK לאימות (אם הסטטוס הוא DRAFT): מטמיעים את המחרוזת verificationToken שהוחזרה ב-assets/adi-registration.properties בתוך קובץ APK מינימלי שתואם ל-packageName, חותמים עליו באמצעות המפתח הפרטי לחתימת אפליקציות ומעלים אותו באמצעות POST /upload/v1/developerAccounts/{id}/androidPackages/{pkg}/keys/{sha256}:verify (VerifyAndroidPackageKeyOwnership).
  8. שליחת הצדקה (אם נדרש) ודגימת סטטוס הרישום: אם המפתח במצב OWNERSHIP_VERIFIED והערך של registrationJustificationRequired הוא true, קוראים ל-POST /v1/developerAccounts/{id}/androidPackages/{pkg}/keys/{sha256}:justifyAndroidPackageKeyRegistration (JustifyAndroidPackageKeyRegistration). דוגמים את GetAndroidPackage ואת GetAndroidPackageKey עד שהערך של state מגיע ל-REGISTERED.

פקודות CLI מקומיות להכנת טביעות אצבע של מפתחות וקובצי APK לאימות

  • חילוץ טביעת אצבע לאישור SHA-256 ממאגר מפתחות (keytool):

    keytool -list -v -keystore release-key.jks -alias my-key-alias
  • אימות תקציר של אישור חתימה מסוג SHA-256 ב-APK מובנה (apksigner):

    apksigner verify --print-certs app-release.apk
  • לפני ההעלאה, בודקים את שם החבילה של ה-APK ואת קובץ הטוקן המוטמע (aapt2 ו-unzip):

    aapt2 dump badging app-release.apk | head -n 1
    unzip -p app-release.apk assets/adi-registration.properties

יכולות ממשק המשתמש וה-API של Android Developer Console

משימה ממשק המשתמש של Android Developer Console באינטרנט (android.google.com/developerconsole) Android Developer Console API
אימות זהות המפתח (KYC/KYB) ותשלום העמלה נתמך (נדרשת דרישה מוקדמת חד-פעמית) לא נתמך באמצעות ה-API (בדיקת סטטוס לקריאה בלבד באמצעות GetDeveloperAccount ו-ListDeveloperAccounts)
צפייה בחשבונות הפיתוח המקושרים מנגנון למעבר בין חשבונות בכותרת של המסוף GET /v1/developerAccounts (ListDeveloperAccounts)
בדיקת מפתחות חתימה היסטוריים ומדיניות של שם חבילה מוצג במהלך האשף "רישום שם חבילה" GET /v1/.../registrationPolicy (GetAndroidPackageRegistrationPolicy)
רישום שם חבילה חדש ל-Android שמות של חבילות > רישום שם החבילה POST /v1/{parent}/androidPackages?androidPackageId=... (CreateAndroidPackage)
הצגה או רישום של שמות חבילות רשומים וטיוטות של שמות חבילות טבלת מרכז הבקרה שמות של חבילות GET /v1/{name} (GetAndroidPackage), GET /v1/{parent}/androidPackages (ListAndroidPackages)
הוספת מפתח לחתימת אפליקציות ויצירת אסימון אתגר פרטי החבילה > הוספת מפתח חתימה POST /v1/{parent}/keys (CreateAndroidPackageKey)
הוכחת בעלות על מפתח פרטי (adi-registration.properties) העלאת קובץ APK חתום של קטע קוד בממשק המשתמש של המסוף POST /upload/v1/{name}:verify (VerifyAndroidPackageKeyOwnership)
שליחת הצדקה כשנדרשת בדיקה ידנית של המפתח פרומפט טקסטואלי במהלך תהליך העבודה של רישום המפתח POST /v1/{name}:justifyAndroidPackageKeyRegistration (JustifyAndroidPackageKeyRegistration)

הגדרת שירות ואימות

כל בקשות ה-API חייבות להשתמש ב-HTTPS ולכלול כותרת Authorization: Bearer ACCESS_TOKEN שהתקבלה באמצעות תהליך שרת האינטרנט של OAuth 2.0 לחשבון Google שהשלים את אימות זהות המפתח ב-Android Developer Console.

מאפיין (property) ערך
נקודת קצה בסיסית של REST https://androiddeveloperconsole.googleapis.com
נקודת קצה להעלאת מדיה https://androiddeveloperconsole.googleapis.com/upload
גרסת ה-API v1
היקף ההרשאות הנדרש של OAuth 2.0 https://www.googleapis.com/auth/androiddeveloperconsole
מגבלת ברירת המחדל של המכסה ‫2,000 בקשות ביום לכל פרויקט ב-Google Cloud לכל שיטה

משאבים ונקודות קצה של API

ב-Android Developer Console API, המשאבים מאורגנים בהיררכיה הבאה:

  • DeveloperAccount (developerAccounts/{developer_account})
    • AndroidPackage (developerAccounts/{developer_account}/androidPackages/{android_package})
      • AndroidPackageRegistrationPolicy (developerAccounts/{developer_account}/androidPackages/{android_package}/registrationPolicy)
      • AndroidPackageKey (developerAccounts/{developer_account}/androidPackages/{android_package}/keys/{key})

משאב: DeveloperAccount

מייצג חשבון ב-Android Developer Console שמשויך לזהות מפתח.

שדה סוג תיאור
name string מזהה. שם המשאב בפורמט developerAccounts/{developer_account}.
displayName string פלט בלבד. שם קריא לאנשים שמשויך לחשבון הפיתוח (שם של אדם פרטי או שם של ארגון).
verificationState enum (VerificationState) פלט בלבד. סטטוס אימות הזהות הנוכחי של המפתח בחשבון.

ערכים לדוגמה: DeveloperAccount.VerificationState

ערך תיאור
VERIFIED תהליך אימות הזהות של המפתח הושלם. החשבון יכול לרשום שמות של חבילות ומפתחות לחתימת אפליקציות.
NOT_VERIFIED אימות הזהות של המפתח לא הושלם ב-Android Developer Console.

שיטות: DeveloperAccount

שיטה בקשת HTTP תיאור
GetDeveloperAccount GET /v1/{name=developerAccounts/*} אחזור מטא-נתונים ומצב אימות של DeveloperAccount יחיד.
ListDeveloperAccounts GET /v1/developerAccounts מציגה את כל האובייקטים של DeveloperAccount שחשבון Google המאומת יכול לגשת אליהם (ללא חלוקה לדפים).

משאב: AndroidPackage

מייצג שם של חבילת Android שרשומה או נמצאת בתהליך רישום ב-DeveloperAccount.

שדה סוג תיאור
name string מזהה. שם המשאב בפורמט developerAccounts/{developer_account}/androidPackages/{android_package}, כאשר {android_package} הוא שם החבילה ל-Android (לדוגמה, com.example.myapp).
packageName string פלט בלבד. שם החבילה ל-Android (לדוגמה, com.example.myapp).
state enum (AndroidPackage.State) פלט בלבד. מצב מחזור החיים הנוכחי של רישום שם החבילה.
registeredAppStore boolean פלט בלבד. מציין אם שם החבילה הזה פעיל כרגע כחנות אפליקציות רשומה.

Enum: AndroidPackage.State

ערך תיאור
DRAFT משאב שם החבילה נוצר, והרישום של מפתח לחתימת אפליקציות או אימות הבעלות עדיין בתהליך.
IN_REVIEW הרישום של שם החבילה וההצדקה הנדרשת לשימוש במפתח נשלחו ונמצאים בבדיקה של Google. חבילה עוברת מסטטוס DRAFT לסטטוס IN_REVIEW מיד אחרי CreateAndroidPackageKey (אם דילגתם על אימות הבעלות על המפתח, כולל אם המפתח כבר אומת לשם חבילה אחר באותו DeveloperAccount) או אחרי השלמת VerifyAndroidPackageKeyOwnership ואם נדרש, גם JustifyAndroidPackageKeyRegistration.
REGISTERED שם החבילה רשום באופן פעיל בחשבון הפיתוח הזה לצורך אימות למפתחי Android.
PENDING_TRANSFER שם החבילה ממתין להשלמת העברת הבעלות לחשבון פיתוח אחר.

משאב: AndroidPackageRegistrationPolicy

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

שדה סוג תיאור
name string מזהה. שם המשאב בפורמט developerAccounts/{developer_account}/androidPackages/{android_package}/registrationPolicy.
knownKeys[] object (KnownKey) רשימה של מפתחות היסטוריים לחתימת אפליקציות ששימשו בעבר להפצת אפליקציות עם שם החבילה הזה, ממוינת לפי סדר לקסיקוגרפי לפי certificateFingerprintSha256.
knownKeys[].certificateFingerprintSha256 string פלט בלבד. טביעת אצבע מנורמלת של SHA-256 בבסיס הקסדצימלי עם 64 תווים באותיות קטנות של אישור החתימה ההיסטורי (ללא נקודתיים).
knownKeys[].justificationRequirement enum (JustificationRequirement) פלט בלבד. מציין אם רישום המפתח הזה מחייב קריאה ל-JustifyAndroidPackageKeyRegistration (REQUIRED או NOT_REQUIRED). אם מפתח החתימה אומת בעבר בשם חבילה אחר באותו DeveloperAccount, המערכת מדלגת על VerifyAndroidPackageKeyOwnership ועל JustifyAndroidPackageKeyRegistration גם אם הערך של justificationRequirement הוא REQUIRED.
keySelectionStrategy enum (KeySelectionStrategy) פלט בלבד. מדיניות בחירת המפתחות לרישום שם החבילה הזה: SELECT_KEY_FROM_LIST (צריך לרשום מפתח מ-knownKeys) או USE_ANY_KEY (אפשר לרשום כל מפתח חוקי לחתימת אפליקציות שנמצא בבעלות המפתח).

ערך נספר (enum):‏ KnownKey.JustificationRequirement

ערך תיאור
REQUIRED כדי לרשום את המפתח המוכר הזה, צריך לשלוח הצדקה בכתב באמצעות JustifyAndroidPackageKeyRegistration אחרי שמשלימים את VerifyAndroidPackageKeyOwnership (אלא אם המפתח אומת בעבר בשם חבילה אחר באותו DeveloperAccount, ובמקרה כזה המערכת מדלגת על VerifyAndroidPackageKeyOwnership ועל JustifyAndroidPackageKeyRegistration).
NOT_REQUIRED כדי לרשום את המפתח המוכר הזה, לא צריך לספק הצדקה. המפתח עובר ישירות למצב IN_REVIEW אחרי VerifyAndroidPackageKeyOwnership (או מיד אחרי CreateAndroidPackageKey אם המפתח אומת בעבר בשם חבילה אחר באותו DeveloperAccount).

טיפוסים בני מנייה (enum): AndroidPackageRegistrationPolicy.KeySelectionStrategy

ערך תיאור
SELECT_KEY_FROM_LIST מבצע הקריאה החוזרת צריך לרשום את אחד מהמפתחות ההיסטוריים שרשומים ב-knownKeys.
USE_ANY_KEY בנוסף למפתחות ב-knownKeys, הגורם המבקש יכול לרשום כל מפתח חוקי לחתימת אפליקציות שלא נצפה בעבר בסביבה העסקית של Android.

Methods: AndroidPackage

שיטה בקשת HTTP תיאור
GetAndroidPackageRegistrationPolicy GET /v1/{name=developerAccounts/*/androidPackages/*/registrationPolicy} אחזור של אסטרטגיית בחירת המפתחות ומפתחות החתימה ההיסטוריים הידועים של שם חבילה.
CreateAndroidPackage POST /v1/{parent=developerAccounts/*}/androidPackages?androidPackageId={package_name} יוצר משאב AndroidPackage חדש במצב DRAFT כדי להתחיל לרשום שם חבילה.
GetAndroidPackage GET /v1/{name=developerAccounts/*/androidPackages/*} אחזור פרטים ומצב הרישום הנוכחי של AndroidPackage קיים.
ListAndroidPackages GET /v1/{parent=developerAccounts/*}/androidPackages הצגת רשימה של אובייקטים מסוג AndroidPackage ב-DeveloperAccount (pageSize מקסימום 1000, pageToken).

משאב: AndroidPackageKey

מייצג טביעת אצבע לאישור חתימת אפליקציה ציבורי שמשויך ל-AndroidPackage, ועוקב אחרי מצב אימות הבעלות ובדיקת הרישום.

שדה סוג תיאור
name string מזהה. שם המשאב שהוקצה על ידי השרת בפורמט developerAccounts/{developer_account}/androidPackages/{android_package}/keys/{key}, כאשר {key} היא טביעת אצבע מנורמלת של SHA-256 הקסדצימלי באותיות קטנות באורך 64 תווים ללא נקודתיים. צריך להשמיט את השדה או להשאיר אותו ריק כשמפעילים את CreateAndroidPackageKey.
certificateFingerprintSha256 string חובה. לא ניתן לשינוי. גיבוב SHA-256 של אישור חתימת האפליקציה. בקלט ב-CreateAndroidPackageKey, מקבל ערך הקסדצימלי פשוט של 64 תווים (60e860e8...) או ערך הקסדצימלי מופרד בנקודתיים (60:E8:60:E8:...). בפלט, תמיד מנורמל לערך הקסדצימלי של 64 תווים באותיות קטנות ללא נקודתיים.
state enum (AndroidPackageKey.State) פלט בלבד. מצב האימות והרישום הנוכחי של המפתח במחזור החיים.
verificationToken string פלט בלבד. טוקן אתגר ייחודי שנוצר על ידי Google. משמש רק כשהמצב הוא DRAFT (אפשר להתעלם כשהמצב CreateAndroidPackageKey מעביר את המפתח ישירות למצב IN_REVIEW). כשהמצב הוא DRAFT, צריך להטמיע את המחרוזת הזו בתוך assets/adi-registration.properties ב-APK חתום כדי להשלים את VerifyAndroidPackageKeyOwnership.
registrationJustificationRequired boolean פלט בלבד. אם true והמפתח במצב OWNERSHIP_VERIFIED, צריך לשלוח הצדקה בכתב באמצעות JustifyAndroidPackageKeyRegistration לפני שהרישום ימשיך אל IN_REVIEW. אם CreateAndroidPackageKey מעביר את המפתח ישירות אל IN_REVIEW (כי המפתח אומת בעבר בשם חבילה אחר באותו DeveloperAccount), המערכת מדלגת על ההצדקה.

Enum: AndroidPackageKey.State

ערך תיאור
DRAFT משאב המפתח נוצר, ועדיין נדרשת הוכחה להחזקה במפתח הפרטי באמצעות העלאת קובץ APK חתום (VerifyAndroidPackageKeyOwnership) כי הבעלות על המפתח הזה עדיין לא אומתה באף שם חבילה ב-DeveloperAccount הזה.
OWNERSHIP_VERIFIED הבעלות על המפתח הפרטי אומתה באמצעות העלאת APK חתום. אם הערך של registrationJustificationRequired הוא true, עדיין צריך לספק הצדקה לפני שמתחילים בבדיקה.
IN_REVIEW ‫Google בודקת את רישום המפתח. מפתח עובר לכאן מיד אחרי CreateAndroidPackageKey כשלא נדרשת הוכחת בעלות (לדוגמה, בשם חבילה חדש שלא הופיע אף פעם ב-Android, או כשהמפתח אומת בעבר בשם חבילה אחר באותו DeveloperAccount, שגם מדלג על JustifyAndroidPackageKeyRegistration), מיד אחרי VerifyAndroidPackageKeyOwnership (אם registrationJustificationRequired הוא false), או אחרי JustifyAndroidPackageKeyRegistration (אם registrationJustificationRequired הוא true).
REGISTERED המפתח לחתימת האפליקציות רשום באופן פעיל לשם החבילה הזה לצורך אימות למפתחי Android.
PENDING_TRANSFER רישום המפתח לחתימת האפליקציה ממתין להשלמת ההעברה.

Methods: AndroidPackageKey

שיטה בקשת HTTP תיאור
CreateAndroidPackageKey POST /v1/{parent=developerAccounts/*/androidPackages/*}/keys רושמת טביעת אצבע חדשה לאישור חתימת אפליקציה מסוג SHA-256 ב-AndroidPackage. הפונקציה מחזירה את המפתח במצב DRAFT (כשנדרשת הוכחת בעלות באמצעות VerifyAndroidPackageKeyOwnership) או ישירות במצב IN_REVIEW (כשמדלגים על אימות הבעלות, למשל עבור שם חבילה חדש שמעולם לא הופיע ב-Android או מפתח שכבר אומת בשם חבילה אחר באותו DeveloperAccount).
GetAndroidPackageKey GET /v1/{name=developerAccounts/*/androidPackages/*/keys/*} אחזור של סטטוס, טביעת אצבע ומטא-נתונים של אימות של AndroidPackageKey ספציפי.
ListAndroidPackageKeys GET /v1/{parent=developerAccounts/*/androidPackages/*}/keys הצגת רשימה של כל האובייקטים מסוג AndroidPackageKey שרשומים ב-AndroidPackage (pageSize מקסימום 1000, pageToken).
VerifyAndroidPackageKeyOwnership POST /upload/v1/{name=developerAccounts/*/androidPackages/*/keys/*}:verify הסוכן מעלה קובץ APK מינימלי חתום שמכיל את verificationToken ב-assets/adi-registration.properties כדי לאמת את הבעלות על המפתח הפרטי, ושולח מפתחות מוכנים לבדיקה.
JustifyAndroidPackageKeyRegistration POST /v1/{name=developerAccounts/*/androidPackages/*/keys/*}:justifyAndroidPackageKeyRegistration שליחת הקשר נוסף להצדקה כש-registrationJustificationRequired הוא true ושליחת מפתחות מאומתים לבדיקה.

טיפול בשגיאות

אם בקשת API נכשלת, Android Developer Console API מחזיר קוד סטטוס HTTP‏ 4xx או 5xx וגוף שגיאה סטנדרטי בפורמט JSON של google.rpc.Status:

{
  "error": {
    "code": 400,
    "message": "Invalid certificate fingerprint SHA256 format.",
    "status": "INVALID_ARGUMENT",
    "details": []
  }
}

קודי סטטוס של HTTP ופתרונות נפוצים

קוד HTTP סטטוס gRPC גורמים נפוצים רזולוציה
400 Bad Request INVALID_ARGUMENT חסר androidPackageId בסגנון Java או שהוא לא תקין; פורמט certificateFingerprintSha256 לא תקין; שדה name לא ריק ב-CreateAndroidPackage או ב-CreateAndroidPackageKey; ה-APK שהועלה לא חתום, פגום, חסר בו assets/adi-registration.properties, חסר בו verificationToken תואם או שהוא חתום באמצעות אישור לא תואם. לפני ההעלאה, צריך לאמת את הפורמטים של הבקשות מול הסכימות של המשאבים, להשמיט או לרוקן את name בקריאות ליצירה, ולאמת את החתימה של ה-APK ואת הטוקן המוטמע באמצעות apksigner verify --print-certs ו-unzip -p app-release.apk assets/adi-registration.properties.
400 Bad Request FAILED_PRECONDITION ל-DeveloperAccount יש verificationState: NOT_VERIFIED; בחירת המפתח מפרה את AndroidPackageRegistrationPolicy (SELECT_KEY_FROM_LIST); קריאה ל-VerifyAndroidPackageKeyOwnership או ל-JustifyAndroidPackageKeyRegistration במצב לא כשיר. צריך להשלים את תהליך אימות הזהות של המפתח ב-Android Developer Console, לבדוק קודם את GetAndroidPackageRegistrationPolicy ולבדוק את state הנוכחי של המשאב.
401 Unauthorized UNAUTHENTICATED טוקן הגישה מסוג OAuth 2.0 Bearer חסר, לא תקין או שפג תוקפו, או שבוצע ניסיון לאימות באמצעות מפתח API או חשבון שירות. מקבלים אסימון גישה חדש מסוג OAuth 2.0 Bearer עם היקף ההרשאות https://www.googleapis.com/auth/androiddeveloperconsole, שהוקצה למשתמש.
403 Forbidden PERMISSION_DENIED למשתמש המאומת אין הרשאה ב-DeveloperAccount או ב-AndroidPackage, או ש-Android Developer Console API לא מופעל בפרויקט בענן ב-Google Cloud. צריך לאמת את החברות בחשבון באמצעות ListDeveloperAccounts ולוודא ש-androiddeveloperconsole.googleapis.com מופעל במסוף Google Cloud.
404 Not Found NOT_FOUND נתיב המשאב שצוין ב-DeveloperAccount, ב-AndroidPackage או ב-AndroidPackageKey לא קיים. מאשרים את נתיבי המשאבים באמצעות ListDeveloperAccounts, ListAndroidPackages או ListAndroidPackageKeys. צריך לוודא שהמזהים של {key} משתמשים בערכים הקסדצימליים באותיות קטנות בלי נקודתיים.
409 Conflict ALREADY_EXISTS שם החבילה או טביעת האצבע לאישור SHA-256 כבר רשומים בחשבון הפיתוח הזה או בחשבון פיתוח אחר. אפשר לבדוק רישומים קיימים באמצעות GetAndroidPackage או GetAndroidPackageKey, או לבדוק בעלות היסטורית באמצעות GetAndroidPackageRegistrationPolicy.
429 Too Many Requests RESOURCE_EXHAUSTED חרגת מהמכסה של 2,000 בקשות ביום לכל שיטה בכל פרויקט בענן של Google. הטמיעו השהיה מעריכית לפני ניסיון חוזר (exponential backoff) עם ריצוד (jitter) והימנעו מלולאות דגימה בתדירות גבוהה.
500 / 503 INTERNAL / UNAVAILABLE שגיאה זמנית בקצה העורפי או חוסר זמינות זמני של השירות. נסו שוב לשלוח בקשות אידמפוטנטיות עם השהיה מעריכית קטועה לפני ניסיון חוזר (truncated exponential backoff).

דוגמאות לבקשות ולתגובות HTTP

מחליפים את הערכים הזמניים לשמירת מקום (פלייסהולדרים) כמו ACCESS_TOKEN,‏ 1234567890,‏ com.example.myapp ו-60e860e8... בערכים משלכם.

1. GetDeveloperAccount

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890"

תשובה:

{
  "name": "developerAccounts/1234567890",
  "displayName": "Example Developer",
  "verificationState": "VERIFIED"
}

2. ListDeveloperAccounts

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts"

תשובה:

{
  "developerAccounts": [
    {
      "name": "developerAccounts/1234567890",
      "displayName": "Example Developer",
      "verificationState": "VERIFIED"
    }
  ]
}

3. GetAndroidPackageRegistrationPolicy

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/registrationPolicy"

תשובה:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/registrationPolicy",
  "knownKeys": [
    {
      "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "justificationRequirement": "NOT_REQUIRED"
    }
  ],
  "keySelectionStrategy": "SELECT_KEY_FROM_LIST"
}

4. CreateAndroidPackage

curl -X POST \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d '{"name": ""}' \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages?androidPackageId=com.example.myapp"

תשובה:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp",
  "packageName": "com.example.myapp",
  "state": "DRAFT",
  "registeredAppStore": false
}

5. GetAndroidPackage

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp"

תשובה:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp",
  "packageName": "com.example.myapp",
  "state": "REGISTERED",
  "registeredAppStore": false
}

6. ListAndroidPackages

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages?pageSize=100"

תשובה:

{
  "androidPackages": [
    {
      "name": "developerAccounts/1234567890/androidPackages/com.example.myapp",
      "packageName": "com.example.myapp",
      "state": "REGISTERED",
      "registeredAppStore": false
    }
  ],
  "nextPageToken": ""
}

7. CreateAndroidPackageKey

curl -X POST \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d '{
    "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123"
  }' \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys"

תשובה:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "state": "DRAFT",
  "verificationToken": "token_xyz987654321"
}

8. GetAndroidPackageKey

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123"

תשובה:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "state": "REGISTERED"
}

9. ListAndroidPackageKeys

curl -X GET \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys?pageSize=100"

תשובה:

{
  "androidPackageKeys": [
    {
      "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
      "state": "REGISTERED"
    }
  ],
  "nextPageToken": ""
}

10. VerifyAndroidPackageKeyOwnership

אפשרות א': העלאת מדיה בבקשה יחידה

curl -X POST \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @app-release.apk \
  "https://androiddeveloperconsole.googleapis.com/upload/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123:verify?uploadType=media"

אפשרות ב': פרוטוקול העלאה שניתן להמשיך (מומלץ לקובצי APK גדולים או ל-CI/CD)

שלב 1: מתחילים את סשן ההעלאה שניתן להמשיך ומחלצים את הכותרת X-Goog-Upload-URL שהוחזרה:

curl -i -X POST \
  "https://androiddeveloperconsole.googleapis.com/upload/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123:verify" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "X-Goog-Upload-Protocol: resumable" \
  -H "X-Goog-Upload-Command: start" \
  -H "X-Goog-Upload-Header-Content-Length: FILE_SIZE_IN_BYTES" \
  -H "X-Goog-Upload-Header-Content-Type: application/vnd.android.package-archive" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123"
  }'

שלב 2: מעלים את הקובץ הבינארי של ה-APK החתום אל UPLOAD_SESSION_URI ומסיימים את הסשן:

curl -X PUT \
  "UPLOAD_SESSION_URI" \
  -H "Content-Length: FILE_SIZE_IN_BYTES" \
  -H "X-Goog-Upload-Offset: 0" \
  -H "X-Goog-Upload-Command: upload, finalize" \
  --data-binary "@app-release.apk"

תשובה:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "state": "IN_REVIEW"
}

11. JustifyAndroidPackageKeyRegistration

curl -X POST \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json; charset=utf-8" \
  -d '{
    "justification": "We previously distributed com.example.myapp directly from https://downloads.example.com and are migrating to our rotated production key."
  }' \
  "https://androiddeveloperconsole.googleapis.com/v1/developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123:justifyAndroidPackageKeyRegistration"

תשובה:

{
  "name": "developerAccounts/1234567890/androidPackages/com.example.myapp/keys/60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "certificateFingerprintSha256": "60e860e8d77251234567890abcdef1234567890abcdef1234567890abcdef123",
  "state": "IN_REVIEW",
  "registrationJustificationRequired": true
}

מקורות מידע נוספים