Δημοσίευση εκδόσεων APK

Μεταφορτώστε ένα υπογεγραμμένο APK Android απευθείας από τη γραμμή έκδοσής σας και παρακολουθήστε το μέχρι να εμφανιστεί στη βιβλιοθήκη της εταιρείας σας.

Πώς λειτουργεί η δημοσίευση

Δημιουργήστε μια συνεδρία πολυτμηματικής μεταφόρτωσης με το Nomid API, στείλτε τα byte του APK απευθείας στο S3 χρησιμοποιώντας βραχύβιες διευθύνσεις URL για κάθε τμήμα, ολοκληρώστε τη συνεδρία και ελέγχετε περιοδικά το τελικό αποτέλεσμα της επεξεργασίας.

Το LIBRARY_MANAGE καλύπτει πλέον τις μεταφορτώσεις APK και τη διαχείριση εφαρμογών, συμπεριλαμβανομένης της ανάγνωσης, της επεξεργασίας, της απόκρυψης και της επαναφοράς εφαρμογών και εκδόσεων. Τα δημόσια API για αρχεία, επαφές και άλλους πόρους της βιβλιοθήκης εξακολουθούν να μην είναι διαθέσιμα. Δεν παρέχει ανάθεση πολιτικών, εντολές συσκευών, παροχή ή διαχείριση λογαριασμού.

Διαβάστε και διαχειριστείτε τις εφαρμογές της βιβλιοθήκης της εταιρείας και δημοσιεύστε υπογεγραμμένες εκδόσεις APK. Το LIBRARY_MANAGE είναι ευαίσθητη άδεια σε επίπεδο εταιρείας για μεταφορτώσεις APK και διαχείριση εφαρμογών. Δεν παρέχει ανάθεση πολιτικών, εντολές συσκευών, παροχή ή λειτουργίες λογαριασμού.

Μια ολοκληρωμένη δημοσίευση τοποθετεί την έκδοση στη βιβλιοθήκη και μπορεί να ενεργοποιήσει την υπάρχουσα διανομή για πολιτικές που χρησιμοποιούν την εφαρμογή και το κανάλι της. Δεν επιβεβαιώνει ότι κάποια συσκευή έχει εγκαταστήσει την έκδοση.

Πριν ξεκινήσετε

  • Δημιουργήστε ένα ειδικό κλειδί API με LIBRARY_MANAGE. Ένας χρήστης της πύλης που δημιουργεί αυτή την άδεια χρειάζεται API_KEY_MANAGE, απεριόριστο εύρος πολιτικών εταιρείας, LIBRARY_VIEW και LIBRARY_EDIT. Η ευαίσθητη άδεια είναι απενεργοποιημένη από προεπιλογή· τα υπάρχοντα κλειδιά δεν την αποκτούν αυτόματα.
  • Παραχωρήστε το κλειδί μόνο σε αξιόπιστο αυτοματισμό που χρειάζεται αυτές τις λειτουργίες βιβλιοθήκης σε επίπεδο εταιρείας. Το LIBRARY_MANAGE επιτρέπει μεταφορτώσεις APK και διαχείριση εφαρμογών, συμπεριλαμβανομένης της πρόσβασης σε συνεδρίες μεταφόρτωσης που ξεκίνησαν άλλα εξουσιοδοτημένα κλειδιά ή χρήστες της εταιρείας· φυλάξτε το κλειδί στο χώρο αποθήκευσης μυστικών του CI και αλλάξτε το ή ανακαλέστε το όταν αλλάζει η πρόσβαση.
  • Χρησιμοποιήστε Python 3.11 ή νεότερη για το παράδειγμα του εργαλείου μεταφόρτωσης. Δημιουργήστε και υπογράψτε το APK με την προβλεπόμενη ταυτότητα υπογραφής και έναν κατάλληλο κωδικό έκδοσης Android πριν από τη μεταφόρτωση. Το API δεν υπογράφει APK και δεν δημοσιεύει στο Google Play.
  • Στείλτε το X-API-Key στο Nomid API. Το επικυρωμένο κλειδί επιλέγει την εταιρεία· τα αιτήματα δεν έχουν παράμετρο ενοίκου ή εταιρείας. Δεν χρειάζεται άδεια DEVICES_READ ή POLICIES_READ για τη δημοσίευση APK.

Τελικά σημεία

https://api.nomid.tech/emm/api/v1

Και οι οκτώ παρακάτω διαδρομές απαιτούν X-API-Key με LIBRARY_MANAGE· μια συνεδρία μεταφόρτωσης ανήκει στην εταιρεία του κλειδιού.

ΜέθοδοςEndpointΠεριγραφή
POST/library/apps/uploads/checkΕλέγξτε την επιλεξιμότητα, το διπλότυπο περιεχόμενο και μια υπάρχουσα συνεδρία που μπορεί να συνεχιστεί. Ένα διπλότυπο είναι ενημερωτικό.
POST/library/apps/uploads/startΞεκινήστε μια μεταφόρτωση και λάβετε sessionId, partSize και expiresAt.
POST/library/apps/uploads/parts/signΛάβετε μια βραχύβια διεύθυνση URL PUT απευθείας στο S3 και τα requiredHeaders για ένα τμήμα.
GET/library/apps/uploads/parts/{sessionId}Εμφανίστε τα τμήματα που έχουν ήδη μεταφορτωθεί και μπορούν να επαναχρησιμοποιηθούν, μαζί με τα ακριβή ETag τους, για την ίδια συνεδρία.
POST/library/apps/uploads/completeΥποβάλετε την ταξινομημένη λίστα τμημάτων και προαιρετικά κανάλια (tracks) για τη σύνθεση και την επεξεργασία του APK.
GET/library/apps/uploads/status/{sessionId}Ελέγχετε περιοδικά τη συνεδρία μέχρι το status να γίνει completed ή failed.
DELETE/library/apps/uploads/abort/{sessionId}Ακυρώστε μια μη ολοκληρωμένη συνεδρία· συνεδρίες σε επεξεργασία ή ολοκληρωμένες δεν μπορούν να ακυρωθούν.
GET/library/apps/{packageName}/versions/{versionCode}/check-reportΔιαβάστε την τελευταία αναφορά ελέγχου μεταφόρτωσης μιας έκδοσης. Χρειάζεται το packageName και το versionCode της έκδοσης, καθώς και το περιβάλλον της όταν αυτό δεν είναι κενό.

Ακολουθία μεταφόρτωσης

  1. POST /check με filename, το πραγματικό θετικό μέγεθος σε byte, τον αποδεκτό τύπο mime και το SHA-256 του APK. Ελέγξτε τα allowed και reason· τα duplicateOf και existingSessionId μπορεί να υπάρχουν.
  2. POST /start με τα ίδια πεδία. Αποθηκεύστε με ασφάλεια τα sessionId και partSize που επιστρέφονται, ώστε αυτή η εκτέλεση να μπορεί να συνεχιστεί αν διακοπεί.
  3. Για κάθε τμήμα που λείπει, κάντε POST /parts/sign με sessionId και partNumber από 1 έως 10000.
  4. Τεμαχίστε το αρχείο σε διαδοχικά κομμάτια partSize byte· μόνο το τελευταίο κομμάτι μπορεί να είναι μικρότερο. Κάντε PUT κάθε κομματιού στην υπογεγραμμένη διεύθυνση URL του, χρησιμοποιώντας τα requiredHeaders, και διατηρήστε την κεφαλίδα απόκρισης ETag ακριβώς όπως επιστράφηκε.
  5. POST /complete με sessionId, κάθε ζεύγος partNumber/etag και προαιρετικά tracks. Η ολοκλήρωση ξεκινά επεξεργασία του APK στο παρασκήνιο· η άμεση απόκρισή της μπορεί και πάλι να δείχνει processing.
  6. Κάντε GET στο τελικό σημείο status με το αναγνωριστικό συνεδρίας μέχρι το status, με πεζά γράμματα, να γίνει completed ή failed. Οι αποκρίσεις completed περιλαμβάνουν app· οι αποκρίσεις failed περιλαμβάνουν errorMessage. Οι άλλες καταστάσεις δεν αποτελούν επιτυχή δημοσίευση.

Το μέγεθος πρέπει να είναι μεγαλύτερο από μηδέν και εντός του ρυθμισμένου ορίου μεταφόρτωσης. Το mime είναι application/vnd.android.package-archive ή application/octet-stream· το sha256 είναι η δεκαεξαδική σύνοψη 64 χαρακτήρων, με πεζά γράμματα, των byte του APK. Ισχύει η λήξη της συνεδρίας και των υπογεγραμμένων διευθύνσεων URL.

Η υπογεγραμμένη διεύθυνση URL προορίζεται για το S3, όχι για το Nomid API: στείλτε με το PUT μόνο τα requiredHeaders, ποτέ το X-API-Key. Μην καταγράφετε την υπογεγραμμένη διεύθυνση URL. Αν λήξει, υπογράψτε ξανά το συγκεκριμένο τμήμα.

Παραδείγματα αιτημάτων και αποκρίσεων

Αυτά τα παραδείγματα δείχνουν ονόματα πεδίων και τιμές status με πεζά γράμματα. Τα αναγνωριστικά, η σύνοψη, η ώρα, το μέγεθος τμήματος, τα ETag και η διεύθυνση URL είναι ενδεικτικά· χρησιμοποιήστε τις τιμές που επιστρέφονται για τη δική σας συνεδρία.

Αίτημα POST /check ή /start

{
  "filename": "app-release.apk",
  "size": 33554432,
  "mime": "application/vnd.android.package-archive",
  "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
}

Απόκριση POST /check για επιλέξιμο APK

{
  "allowed": true,
  "recommendedPartSize": 16777216
}

Απόκριση POST /start

{
  "sessionId": "123e4567-e89b-12d3-a456-426614174000",
  "partSize": 16777216,
  "expiresAt": "2026-10-28T12:00:00Z"
}

Αίτημα POST /parts/sign

{
  "sessionId": "123e4567-e89b-12d3-a456-426614174000",
  "partNumber": 1
}

Απόκριση POST /parts/sign

{
  "url": "https://<presigned-part-url>",
  "requiredHeaders": {}
}

Απόκριση GET για τα μεταφορτωμένα τμήματα

{
  "status": "uploading",
  "partSize": 16777216,
  "parts": [{ "partNumber": 1, "etag": "\"example-etag\"" }]
}

Αίτημα POST /complete

{
  "sessionId": "123e4567-e89b-12d3-a456-426614174000",
  "parts": [
    { "partNumber": 1, "etag": "\"example-etag-1\"" },
    { "partNumber": 2, "etag": "\"example-etag-2\"" }
  ],
  "tracks": ["prod"]
}

Απόκριση POST /complete σε επεξεργασία

{
  "status": "processing",
  "sessionId": "123e4567-e89b-12d3-a456-426614174000"
}

Τα requiredHeaders μπορεί να περιέχουν κεφαλίδες που απαιτεί η υπογραφή του S3. Εφαρμόστε τον επιστρεφόμενο χάρτη ακριβώς, μαζί με τυχόν τιμές, και καταγράψτε την κεφαλίδα απόκρισης ETag από κάθε επιτυχές PUT.

Έλεγχοι μεταφόρτωσης

Κάθε μεταφόρτωση ελέγχεται πριν δημιουργηθεί η έκδοσή της: η υπογραφή και το manifest του APK, οι προηγούμενες εκδόσεις της εταιρείας σας για το ίδιο πακέτο και οι συσκευές της εταιρείας σας (τα επίπεδα API Android που έχουν και οι εφαρμογές που είναι εγκατεστημένες σε αυτές, με τα πιστοποιητικά υπογραφής τους). Το αποτέλεσμα είναι μια αναφορά ελέγχου που μπορείτε να διαβάσετε από το API.

Οι έλεγχοι αναφέρουν ευρήματα. Τα ευρήματα αποθηκεύονται και επιστρέφονται, και η μεταφόρτωση ολοκληρώνεται κανονικά· μόνο το VERSION_CODE_CONFLICT απορρίπτει μια μεταφόρτωση. Ένα εύρημα με σοβαρότητα ERROR περιγράφει ένα APK που οι συσκευές μπορεί να αρνηθούν να εγκαταστήσουν ή να ενημερώσουν· ένα WARNING περιγράφει ένα APK που εγκαθίσταται με κίνδυνο που αξίζει να γνωρίζετε. Κανένα από τα δύο δεν σταματά τη μεταφόρτωση.

Μια ολοκληρωμένη μεταφόρτωση περιλαμβάνει το checkReport στην απόκριση GET /status, και στην απόκριση POST /complete όταν αυτή επιστρέφει μια ολοκληρωμένη συνεδρία (για παράδειγμα σε επαναλαμβανόμενη κλήση). Μια μεταφόρτωση που απορρίφθηκε από έναν έλεγχο έχει status failed και περιλαμβάνει επίσης checkReport. Η αναφορά απουσιάζει όσο η μεταφόρτωση βρίσκεται σε επεξεργασία, καθώς και όταν η μεταφόρτωση απέτυχε για άλλο λόγο. Το errorMessage μιας αποτυχημένης μεταφόρτωσης είναι γενικό, γι' αυτό διαβάστε τα ευρήματα με blocking true στο checkReport για να μάθετε γιατί την απέρριψε ένας έλεγχος.

Οι εκδόσεις που επιστρέφουν οι διαδρομές εκδόσεων της βιβλιοθήκης (η λίστα εκδόσεων και μία μεμονωμένη έκδοση, που τεκμηριώνονται στον οδηγό εφαρμογών της βιβλιοθήκης) περιλαμβάνουν το checkSummary: το status της τελευταίας αναφοράς, το errorCount (ευρήματα ERROR) και το warningCount (ευρήματα WARNING). Είναι null για εκδόσεις που μεταφορτώθηκαν πριν υπάρξουν οι έλεγχοι. Η διαδρομή check-report του παραπάνω πίνακα επιστρέφει την πλήρη αναφορά μιας έκδοσης, στην ίδια μορφή με το checkReport, και απαντά 404 όταν η έκδοση δεν έχει αναφορά. Όπως και οι διαδρομές μεταφόρτωσης, απαιτεί X-API-Key με LIBRARY_MANAGE.

Πεδία αναφοράς

  • status: PASSED (χωρίς ευρήματα), WARNINGS (η έκδοση δημιουργήθηκε και έχει ευρήματα, μεταξύ των οποίων ευρήματα ERROR που δεν απέρριψαν τη μεταφόρτωση) ή BLOCKED (ένα εύρημα σταμάτησε τη μεταφόρτωση και δεν δημιουργήθηκε έκδοση).
  • findings: πρώτα τα ευρήματα ERROR. Κάθε εύρημα έχει code, severity (ERROR ή WARNING), params, blocking, και affectedDeviceCount όταν το εύρημα αφορά συσκευές. Το blocking είναι true μόνο για ένα εύρημα που σταμάτησε τη μεταφόρτωση.
  • params: τιμές που διαβάζονται από το μεταφορτωμένο APK ή από τις δικές σας εκδόσεις της εταιρείας, όπως εκδόσεις, επίπεδα SDK, ονόματα αδειών και ABI, και αποτυπώματα πιστοποιητικών. Τα κλειδιά του εξαρτώνται από τον κωδικό.
  • affectedDeviceCount: σε πόσες από τις συσκευές της εταιρείας σας ισχύει το εύρημα. Για τα MIN_SDK_ABOVE_FLEET και TARGET_SDK_TOO_LOW, το params.scope είναι INSTALLED όταν μετρά τις συσκευές που έχουν εγκατεστημένο το πακέτο, ή COMPANY όταν καμία συσκευή δεν το έχει και μετρά όλες τις συσκευές της εταιρείας.
  • Το checkerVersion προσδιορίζει το σύνολο των ελέγχων που παρήγαγε την αναφορά. Το createdAt είναι η ώρα αποθήκευσης της αναφοράς, σε UTC.

Κωδικοί ελέγχου

Οι κωδικοί είναι σταθεροί: μπορεί να προστεθούν νέοι, αλλά οι υπάρχοντες δεν μετονομάζονται. Διαβάστε τα severity και blocking από κάθε εύρημα και όχι από αυτόν τον πίνακα.

ΚωδικόςΣοβαρότηταΣημασία
SIGNATURE_INVALIDERRORΤο APK δεν είναι υπογεγραμμένο ή η υπογραφή του δεν επαληθεύεται. Το params.issues απαριθμεί τα προβλήματα που βρέθηκαν.
SIGNATURE_SCHEME_V1_ONLYERRORΤο APK στοχεύει Android 11 (API 30) ή νεότερο αλλά έχει μόνο υπογραφή v1 (JAR), την οποία το Android 11 και νεότερα απορρίπτουν. Υπογράψτε το με APK Signature Scheme v2 ή νεότερο. params.targetSdk.
SIGNING_KEY_CHANGEDERRORΤο πιστοποιητικό υπογραφής διαφέρει από αυτό της προηγούμενης έκδοσης και καμία απόδειξη περιστροφής κλειδιού v3 δεν τα συνδέει (params.previousVersionCode, previousCertSha256, newCertSha256), ή διαφέρει από τα πιστοποιητικά που είναι εγκατεστημένα σε affectedDeviceCount συσκευές (params.installedCertSha1, newCertSha1, ως δεκαεξαδικό SHA-1, όπως το αναφέρουν οι συσκευές). Οι συσκευές αρνούνται να ενημερώσουν μια εφαρμογή σε έκδοση υπογεγραμμένη με άλλο κλειδί.
TEST_ONLYWARNINGΤο manifest ορίζει android:testOnly="true", που χαρακτηρίζει μια έκδοση ανάπτυξης. Χωρίς params.
VERSION_CODE_CONFLICTERRORΜια έκδοση με το ίδιο versionCode και περιβάλλον έχει ήδη μεταφορτωθεί με διαφορετικό δυαδικό αρχείο. Αυτό είναι το μόνο εύρημα που απορρίπτει μια μεταφόρτωση. params.versionCode.
VERSION_DOWNGRADEWARNINGΤο versionCode είναι χαμηλότερο από την τελευταία δημοσιευμένη έκδοσή σας (params.latestVersionCode) ή χαμηλότερο από αυτό που έχουν εγκατεστημένο affectedDeviceCount συσκευές (params.installedVersionCode, το υψηλότερο εγκατεστημένο). Οι συσκευές κανονικά δεν ενημερώνονται σε χαμηλότερο κωδικό έκδοσης.
MIN_SDK_ABOVE_FLEETWARNINGΤο minSdk του APK είναι υψηλότερο από το επίπεδο API Android των affectedDeviceCount συσκευών, οι οποίες δεν μπορούν να το εγκαταστήσουν. params.minSdk, scope.
TARGET_SDK_TOO_LOWWARNINGΤο targetSdk του APK είναι κάτω από 23, και το Android 14 και νεότερα αρνούνται να το εγκαταστήσουν. Το affectedDeviceCount μετρά τις συσκευές εντός εύρους που εκτελούν Android 14 ή νεότερο. params.targetSdk, minimumTargetSdk, scope.
MISSING_ARM64WARNINGΤο APK έχει εγγενείς βιβλιοθήκες αλλά καμία για arm64-v8a. Το params.abis απαριθμεί τα ABI που διαθέτει.
DEBUGGABLEWARNINGΤο manifest ορίζει android:debuggable="true". Χωρίς params.
NEW_DANGEROUS_PERMISSIONSWARNINGΤο APK ζητά δικαιώματα εκτέλεσης (επικίνδυνα) που δεν ζητούσε η προηγούμενη έκδοση. params.permissions, previousVersionCode.

Παραδείγματα αναφοράς ελέγχου

Το πρώτο παράδειγμα είναι η απόκριση GET status μιας ολοκληρωμένης μεταφόρτωσης που έχει ευρήματα· άλλα πεδία, όπως το app, παραλείπονται. Το δεύτερο είναι μια αποτυχημένη μεταφόρτωση που απορρίφθηκε από έναν έλεγχο. Τα αναγνωριστικά, οι αριθμοί, τα αποτυπώματα και οι ώρες είναι ενδεικτικά.

Ολοκληρωμένη μεταφόρτωση με ευρήματα

{
  "status": "completed",
  "sessionId": "123e4567-e89b-12d3-a456-426614174000",
  "checkReport": {
    "status": "WARNINGS",
    "findings": [
      {
        "code": "SIGNING_KEY_CHANGED",
        "severity": "ERROR",
        "params": {
          "installedCertSha1": ["0123456789abcdef0123456789abcdef01234567"],
          "newCertSha1": ["89abcdef0123456789abcdef0123456789abcdef"]
        },
        "affectedDeviceCount": 2,
        "blocking": false
      },
      {
        "code": "MIN_SDK_ABOVE_FLEET",
        "severity": "WARNING",
        "params": { "minSdk": 28, "scope": "INSTALLED" },
        "affectedDeviceCount": 3,
        "blocking": false
      },
      {
        "code": "MISSING_ARM64",
        "severity": "WARNING",
        "params": { "abis": ["armeabi-v7a"] },
        "blocking": false
      }
    ],
    "checkerVersion": "2",
    "createdAt": "2026-11-03T09:30:00Z"
  }
}

Μεταφόρτωση που απορρίφθηκε από έναν έλεγχο

{
  "status": "failed",
  "sessionId": "123e4567-e89b-12d3-a456-426614174000",
  "errorMessage": "Upload processing failed",
  "checkReport": {
    "status": "BLOCKED",
    "findings": [
      {
        "code": "VERSION_CODE_CONFLICT",
        "severity": "ERROR",
        "params": { "versionCode": 42 },
        "blocking": true
      }
    ],
    "checkerVersion": "2",
    "createdAt": "2026-11-03T09:30:00Z"
  }
}

checkSummary σε μια έκδοση μέσα σε λίστα εκδόσεων

{
  "versionCode": 42,
  "environment": "",
  "status": "PUBLISHED",
  "displayName": "Kiosk",
  "displayVersion": "1.4.2",
  "createdAt": "2026-11-03T09:30:00Z",
  "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "fileSizeBytes": 33554432,
  "tracks": ["prod"],
  "checkSummary": { "status": "WARNINGS", "errorCount": 1, "warningCount": 2 }
}

Κανάλια και επαναδοκιμές

Αν παραλείψετε το tracks, χρησιμοποιείται το prod. Η πρώτη έκδοση μιας νέας εφαρμογής περιλαμβάνει πάντα το prod, ακόμη και αν ζητηθεί άλλο κανάλι. Οι επόμενες εκδόσεις μπορούν να στοχεύουν ρητά ονόματα καναλιών έως 10 χαρακτήρων. Σε αυτό το API δεν υπάρχει στάδιο προσχεδίου ή έγκρισης.

Ένα ίδιο checksum μπορεί να προσδιορίσει μια υπάρχουσα εφαρμογή/έκδοση, αλλά δεν αναθέτει αυτή την έκδοση στο κανάλι που ζητά η τρέχουσα εκτέλεση. Μην αντιμετωπίζετε ένα αποτέλεσμα διπλότυπου του /check ως επιτυχή δημοσίευση για ένα νέο κανάλι.

Συνεχίστε μόνο το αναγνωριστικό συνεδρίας που αποθηκεύσατε από αυτή την ίδια εκτέλεση δημοσίευσης, με το ίδιο APK και τα ίδια κανάλια. Κάντε GET στο τελικό σημείο των μεταφορτωμένων τμημάτων με αυτό το αναγνωριστικό συνεδρίας για να επαναχρησιμοποιήσετε τμήματα. Μετά από ένα αβέβαιο αποτέλεσμα του /complete, ελέγξτε τη συνεδρία πριν επαναλάβετε την ολοκλήρωση. Μια ακυρωμένη ή ληγμένη συνεδρία απαιτεί νέα μεταφόρτωση.

Δημοσίευση από CI

Σε έναν εκτελεστή CI Linux με Python 3.11 ή νεότερη και sha256sum, κατεβάστε το εργαλείο μεταφόρτωσης Python που χρησιμοποιεί μόνο την τυπική βιβλιοθήκη και επαληθεύστε το καρφωμένο checksum του πριν το εκτελέσετε. Ελέγξτε και τηρήστε έκδοση (version control) για το επαληθευμένο αντίγραφο στο αποθετήριο της γραμμής σας για τις επόμενες εκτελέσεις. Παρέχετε το NOMID_API_KEY μέσω της έγχυσης μυστικών περιβάλλοντος της πλατφόρμας CI σας. Το εργαλείο μεταφόρτωσης τερματίζει με μη μηδενικό κωδικό σε αποτυχία ή λήξη χρόνου.

Κατεβάστε το εργαλείο μεταφόρτωσης Python

curl --fail --silent --show-error --output publish_apk.py \
  https://www.nomidmdm.com/developers/publish_apk.py &&
printf '%s  %s\n' '8d9ba2a4432e6e6db05ba2411bfb6bfa85c85a79d1ce480d97e0014f965f12d2' publish_apk.py | sha256sum --check --status &&
python3 publish_apk.py app-release.apk --track prod

Για να συνεχίσετε μια διακοπείσα εκτέλεση, δώστε ρητά το αποθηκευμένο αναγνωριστικό συνεδρίας της, με το ίδιο APK και τα ίδια κανάλια:

python3 publish_apk.py app-release.apk --track prod \
  --session-id SESSION_ID_FROM_PREVIOUS_RUN

Μην τοποθετείτε το κλειδί API στην εντολή, στο αποθετήριο ή στα αρχεία καταγραφής· μην ενεργοποιείτε την ανίχνευση εκτέλεσης του κελύφους. Κρατήστε τις προϋπογεγραμμένες διευθύνσεις URL και τις απαιτούμενες κεφαλίδες τους εκτός των αρχείων καταγραφής του CI. Η επιτυχία της δημοσίευσης και η εγκατάσταση σε συσκευές είναι ξεχωριστοί έλεγχοι.

GitHub Actions: δημοσίευση APK όταν δημοσιεύεται μια έκδοση

Αυτή η πλήρης ροή εργασίας κατεβάζει ένα ήδη υπογεγραμμένο APK που είναι συνημμένο στην έκδοση GitHub που την ενεργοποίησε, επαληθεύει το εργαλείο μεταφόρτωσης του Nomid και περιμένει τη δημοσίευση στη βιβλιοθήκη της εταιρείας σας. Χρησιμοποιεί το στοιχείο της έκδοσης (release asset), όχι ένα artifact κατασκευής του Actions, και δεν δημιουργεί ούτε υπογράφει την εφαρμογή σας.

  1. Δημιουργήστε ένα ειδικό κλειδί API Nomid με LIBRARY_MANAGE. Στο αποθετήριό σας στο GitHub, ανοίξτε Settings → Secrets and variables → Actions και προσθέστε ένα μυστικό αποθετηρίου με όνομα NOMID_API_KEY που περιέχει το κλειδί. Δεν χρειάζονται άδειες συσκευών ή πολιτικών.
  2. Αποθηκεύστε το παρακάτω YAML ως .github/workflows/publish-to-nomid.yml στο αποθετήριό σας πριν δημιουργήσετε την ετικέτα έκδοσης, ώστε η υποβολή με την ετικέτα να περιέχει τη ροή εργασίας. Αλλάξτε το APK_ASSET_NAME στο ακριβές όνομα του υπογεγραμμένου APK που επισυνάπτετε σε κάθε έκδοση.
  3. Δημιουργήστε και υπογράψτε το APK στην υπάρχουσα γραμμή σας. Επισυνάψτε το σε μια πρόχειρη έκδοση GitHub ως app-release.apk (ή το όνομα στοιχείου που έχετε ρυθμίσει) και στη συνέχεια δημοσιεύστε την έκδοση. Το παράδειγμα υποστηρίζει επίσης ιδιωτικά αποθετήρια μέσω του ενσωματωμένου διακριτικού GitHub με contents: read. Το APK πρέπει να είναι ήδη συνημμένο όταν δημοσιεύεται η έκδοση· διαφορετικά το βήμα λήψης αποτυγχάνει.
name: Publish APK to Nomid

on:
  release:
    types: [published]

permissions:
  contents: read

concurrency:
  group: nomid-apk-${{ github.event.release.id }}
  cancel-in-progress: false

jobs:
  publish:
    runs-on: ubuntu-24.04
    timeout-minutes: 30
    env:
      APK_ASSET_NAME: app-release.apk
      NOMID_TRACK: ${{ github.event.release.prerelease && 'beta' || 'prod' }}
    steps:
      - name: Set up Python
        uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
        with:
          python-version: '3.12'

      - name: Download the signed APK from this release
        env:
          GH_TOKEN: ${{ github.token }}
          GH_REPO: ${{ github.repository }}
          RELEASE_TAG: ${{ github.event.release.tag_name }}
        shell: bash
        run: |
          set -euo pipefail
          gh release download --repo "$GH_REPO" \
            --pattern "$APK_ASSET_NAME" --output app-release.apk -- "$RELEASE_TAG"
          test -s app-release.apk

      - name: Download and verify the Nomid uploader
        shell: bash
        run: |
          set -euo pipefail
          curl --fail --silent --show-error --output publish_apk.py \
            https://www.nomidmdm.com/developers/publish_apk.py
          printf '%s  %s\n' '8d9ba2a4432e6e6db05ba2411bfb6bfa85c85a79d1ce480d97e0014f965f12d2' publish_apk.py \
            | sha256sum --check --status

      - name: Publish to the Nomid company library
        env:
          NOMID_API_KEY: ${{ secrets.NOMID_API_KEY }}
        shell: bash
        run: |
          set -euo pipefail
          if [[ -z "$NOMID_API_KEY" ]]; then
            echo "Configure the NOMID_API_KEY repository secret before publishing." >&2
            exit 1
          fi
          python3 publish_apk.py app-release.apk --track "$NOMID_TRACK" --timeout 1200

Οι σταθερές εκδόσεις δημοσιεύονται στο prod· οι προεκδόσεις (prereleases) του GitHub δημοσιεύονται στο beta. Για μια νέα εφαρμογή, το Nomid περιλαμβάνει πάντα το prod στην πρώτη δημοσίευση, ακόμη και όταν ζητείται beta. Μια προέκδοση ενός νέου πακέτου επομένως δεν είναι απομονωμένη από το prod. Οι επόμενες εκδόσεις διατηρούν τη ρητή επιλογή καναλιού. Επιλέξτε τον τύπο έκδοσης και το κανάλι πριν δημοσιεύσετε.

Το κλειδί Nomid παρέχεται μόνο στο βήμα δημοσίευσης μέσω του περιβάλλοντός του. Ένα κλειδί που λείπει, ένα APK που λείπει, μια ασυμφωνία checksum, μια αποτυχημένη δημοσίευση ή μια λήξη χρόνου δημοσίευσης αποτυγχάνει την εργασία. Μια επιτυχημένη εργασία επιβεβαιώνει τη δημοσίευση στο κατάστημα, όχι την εγκατάσταση σε συσκευές. Αν διακοπεί, χρησιμοποιήστε το αποθηκευμένο sessionId με το ίδιο APK και κανάλι, όπως περιγράφεται παραπάνω· η επανεκτέλεση ολόκληρης της ροής εργασίας ξεκινά νέα μεταφόρτωση.

Αν μια άλλη ροή εργασίας δημοσιεύει την έκδοση GitHub χρησιμοποιώντας το ενσωματωμένο GITHUB_TOKEN της, το GitHub δεν ενεργοποιεί αυτή τη ροή εργασίας έκδοσης. Σε αυτή την περίπτωση, εκτελέστε απευθείας το επαληθευμένο εργαλείο μεταφόρτωσης στην υπάρχουσα εργασία έκδοσης αφού επισυνάψετε το APK, ή δημοσιεύστε την έκδοση χρησιμοποιώντας ένα διακριτικό GitHub App ή προσωπικό διακριτικό πρόσβασης με κατάλληλο εύρος. Κρατήστε το GH_TOKEN του βήματος λήψης ξεχωριστό από το κλειδί API του Nomid.

Τεκμηρίωση GitHub: ενεργοποίηση ροής εργασίας από άλλη ροή εργασίας

Σφάλματα και αποκατάσταση

  • 401: το κλειδί λείπει, δεν είναι έγκυρο, έχει λήξει ή έχει ανακληθεί. Ελέγξτε την έγχυση μυστικών του CI χωρίς να εκτυπώσετε την τιμή.
  • 403: το κλειδί δεν έχει LIBRARY_MANAGE. Δημιουργήστε ένα κατάλληλα εξουσιοδοτημένο κλειδί· άσχετες άδειες ανάγνωσης ή εγγραφής δεν αρκούν.
  • 404 για αναγνωριστικό συνεδρίας που είναι άγνωστο στην εταιρεία του κλειδιού. Επιβεβαιώστε το αναγνωριστικό και το κλειδί που είναι δεσμευμένο στην εταιρεία· μην αλλάξετε σε άλλη εταιρεία για να το αναζητήσετε.
  • 400 για μη έγκυρα πεδία αιτήματος, συμπεριλαμβανομένου του μεγέθους σε byte ή του MIME. Διορθώστε το αίτημα· μην επαναλάβετε αμετάβλητη μη έγκυρη είσοδο.
  • 410: η συνεδρία μεταφόρτωσης έχει λήξει. Ξεκινήστε νέα μεταφόρτωση· οι υπογεγραμμένες διευθύνσεις URL τμημάτων που δόθηκαν πριν δεν μπορούν να επαναχρησιμοποιηθούν.
  • 409 από το /abort σημαίνει ότι η μεταφόρτωση βρίσκεται ήδη σε επεξεργασία ή έχει ολοκληρωθεί. Ελέγξτε την κατάστασή της αντί να προσπαθήσετε να την ακυρώσετε.
  • 422 από το /complete σημαίνει ότι τα τμήματα που δόθηκαν δεν μπορούν να σχηματίσουν το αρχείο. Συγκρίνετε την πλήρη λίστα τμημάτων και τα ακριβή ETag με το τελικό σημείο των μεταφορτωμένων τμημάτων.
  • Για παροδικό σφάλμα δικτύου ή S3, υπογράψτε ξανά τη λήξασα διεύθυνση URL του τμήματος και επαναχρησιμοποιήστε τα επιτυχή τμήματα. Για αβέβαιο αποτέλεσμα του /complete, ελέγξτε πρώτα την ίδια συνεδρία. Μια αποτυχημένη οριστικοποιημένη μεταφόρτωση μπορεί να επαναδοκιμαστεί μέσω της ίδιας διαδρομής ολοκλήρωσης όσο η συνεδρία της είναι έγκυρη.

Επιλέξτε την ώρα σας

Φόρτωση...
Άνοιγμα ημερολογίου κρατήσεων