Crash εφαρμογής — μη φυσιολογικός τερματισμός κατά τον οποίο το πρόγραμμα σταματά να ανταποκρίνεται και κλείνει. Στην ανάπτυξη κινητών, τα crashes είναι η κύρια πηγή αρνητικών κριτικών και μείωσης της βαθμολογίας. Σύμφωνα με τα δεδομένα Firebase (2024), οι χρήστες διαγράφουν την εφαρμογή μετά από ένα-δύο crashes στο 53% των περιπτώσεων. Κάθε κλείσιμο μειώνει τη διατήρηση κατά 3–5%. Συστήματα παρακολούθησης όπως Crashlytics και Sentry βοηθούν να βρεθούν γρήγορα και να διορθωθούν οι αιτίες των crashes πριν επηρεάσουν μαζικά τους χρήστες.
Κύρια Σημεία
Crash — απροσδόκητος τερματισμός του προγράμματος που προκαλείται από μια εξαιρετική κατάσταση που δεν διαχειρίστηκε ο κώδικας. Σε κινητά ΛΣ, το crash οδηγεί σε άμεσο κλείσιμο της εφαρμογής και εμφάνιση της οθόνης “Η εφαρμογή σταμάτησε” ή επιστροφή στην αρχική οθόνη.
Τα crashes χωρίζονται σε δύο μεγάλες κατηγορίες. Διαχειρισμένα σφάλματα — τα μπλοκ try/catch πιάνουν την εξαίρεση, η εφαρμογή συνεχίζει να λειτουργεί, πιθανώς με απώλεια λειτουργικότητας. Μη διαχειρισμένα crashes — η εξαίρεση ανεβαίνει στο επίπεδο του ΛΣ και το σύστημα σκοτώνει τη διεργασία. Ο δεύτερος τύπος είναι ιδιαίτερα επικίνδυνος επειδή ο χρήστης δεν μπορεί να αποθηκεύσει δεδομένα.
Ένα σύστημα με δύο εκατομμύρια χρήστες και ποσοστό crash 0,1% χάνει 2.000 χρήστες σε κάθε έκδοση. Σύμφωνα με το Google Play Console (2024), εφαρμογές με ποσοστό crash άνω του 1,5% αποκλείονται από προτάσεις και χάνουν έως και 30% οργανικής κίνησης.
NullPointerException (NPE) — ο βασιλιάς των crashes σε Java/Kotlin. Προσπάθεια κλήσης μεθόδου σε null αντικείμενο. Στο Kotlin, το NPE εμφανίζεται σπανιότερα χάρη στο null safety, αλλά εξακολουθεί να είναι πιθανό κατά τη χρήση του τελεστή !! ή αλληλεπίδραση με κώδικα Java. Google (2024) εκτιμά: το NPE αποτελεί το 25% όλων των crashes εφαρμογών Android.
IndexOutOfBoundsException — πρόσβαση σε στοιχείο λίστας με ανύπαρκτο δείκτη. Συχνή αιτία: τα δεδομένα έρχονται από τον διακομιστή σε απροσδόκητη μορφή και το UI προσπαθεί να εμφανίσει μια θέση που δεν υπάρχει. Λύση — έλεγχε πάντα το μέγεθος της συλλογής πριν από την πρόσβαση μέσω δείκτη.
ANR (Application Not Responding) — ειδικό πρόβλημα Android. Το νήμα UI αποκλείεται για περισσότερο από 5 δευτερόλεπτα. Κύριες αιτίες: αιτήματα δικτύου στο κύριο νήμα, βαριοί υπολογισμοί, συγχρονισμός με βάση δεδομένων. StrictMode στο Android βοηθά στον εντοπισμό αποκλεισμών του νήματος UI στο στάδιο ανάπτυξης.
OutOfMemoryError (OOM) — η εφαρμογή υπερέβη το όριο μνήμης. Σε κινητές συσκευές με 2–4 GB RAM, το OOM είναι συχνό πρόβλημα κατά την εργασία με μεγάλες εικόνες ή ατελείωτες λίστες χωρίς σελιδοποίηση. Λύση — Glide/Coil για φόρτωση εικόνων, LruCache για προσωρινή αποθήκευση, ViewHolder στο RecyclerView.
Runtime exceptions — σφάλματα που ο μεταγλωττιστής δεν ελέγχει στο στάδιο δημιουργίας. Εμφανίζονται μόνο κατά την εκτέλεση κώδικα σε μια συγκεκριμένη συσκευή με συγκεκριμένα δεδομένα. Στην Java, αυτά είναι RuntimeException και οι υποκλάσεις του: NullPointerException, IllegalArgumentException, ArithmeticException.
Θανατηφόρα σφάλματα (FATAL) — όχι runtime, αλλά συστημικές βλάβες. Signal 11 (SIGSEGV) — παραβίαση τμηματοποίησης μνήμης σε native κώδικα. Signal 6 (SIGABRT) — μη φυσιολογικός τερματισμός που προκαλείται από την ίδια την εφαρμογή μέσω abort(). Τέτοια crashes είναι δύσκολο να διαγνωστούν επειδή το stack trace συχνά δεν δείχνει κατανοητό πλαίσιο.
Στο iOS, οι κύριες αιτίες είναι NSInvalidArgumentException (απροσδόκητο nil σε παράμετρο) και EXC_BAD_ACCESS (πρόσβαση σε απελευθερωμένη μνήμη). Το Swift μείωσε τον αριθμό των crashes σε σύγκριση με το Objective-C, αλλά σφάλματα στο runtime ObjC και βιβλιοθήκες C εξακολουθούν να οδηγούν σε βλάβες.
Firebase Crashlytics — το πρότυπο για εφαρμογές κινητών. Συλλέγει αυτόματα stack trace, προσθέτει logs, ID χρήστη και μεταδεδομένα συσκευής. Ομαδοποιεί crashes κατά υπογραφή (κλάση σφάλματος + γραμμή). Real-time alerts — ειδοποιήσεις όταν το ποσοστό crash υπερβαίνει ένα καθορισμένο όριο (π.χ. >0,1% ανά ώρα).
Sentry — μια εναλλακτική με πιο ευέλικτες δυνατότητες. Επιτρέπει τη δημιουργία custom contexts, προσθήκη breadcrumbs, διαμόρφωση φιλτραρίσματος εντός εφαρμογής για αποκλεισμό μη σημαντικών σφαλμάτων. Source maps για Kotlin και Swift επιτρέπουν την προβολή του πηγαίου κώδικα, όχι συγκεχυμένων ονομάτων.
Best practices για logs: στείλε βασικά μεταδεδομένα πριν από την εκτέλεση μιας επικίνδυνης λειτουργίας. Πρόσθεσε custom keys (αριθμός έκδοσης API, τελευταία οθόνη, μέγεθος δεδομένων εισόδου). Αυτό μετατρέπει ένα άχρηστο stack trace σε αξιοποιήσιμη πληροφορία.
class PaymentViewModel : ViewModel() {
fun processPayment(amount: Double) {
crashlytics.setCustomKey("last_screen", "payment")
crashlytics.setCustomKey("amount", amount)
try {
api.charge(amount)
} catch (e: Exception) {
crashlytics.recordException(e)
}
}
}
Optional binding και null safety — στο Kotlin χρησιμοποίησε `?` για nullable τύπους, `let` και `?:` για ασφαλή διαχείριση null. Στο Swift — optionals και guard let. Modern Kotlin (2024) πρόσθεσε σχολιασμούς Contract: το @ContractsDsl επιτρέπει να δηλωθεί ότι μια συνάρτηση δεν επιστρέφει null, και ο μεταγλωττιστής το ελέγχει.
Error handling στο δίκτυο — κάθε αίτημα δικτύου πρέπει να διαχειρίζεται timeout, σφάλματα ανάλυσης και άρνηση διακομιστή. Retrofit με τύπο Result — μια sealed κλάση που εγγυάται ότι το σφάλμα θα διαχειριστεί. Στυλ No Exception: αντί για try/catch, χρησιμοποίησε sealed Result για ρητή διαχείριση επιτυχίας και σφάλματος.
Feature flags — απενεργοποίησε την προβληματική λειτουργικότητα εξ αποστάσεως χωρίς έκδοση νέας έκδοσης. Firebase Remote Config επιτρέπει την αλλαγή συμπεριφοράς της εφαρμογής χωρίς δημοσίευση στο κατάστημα.
Σταδιακή κυκλοφορία — κυκλοφόρησε τη νέα έκδοση στο 5% του κοινού και παρακολούθησε το ποσοστό crash. Εάν το ποσοστό παραμείνει κάτω από τον στόχο (συνήθως <0,1%), επέκτεινε στο 25%, μετά 50%, μετά 100%. Google Play Console και το App Store Connect υποστηρίζουν σταδιακές κυκλοφορίες για αυτόματη διακοπή κατά την υπέρβαση του ορίου.
1: Ταξινόμηση — προσδιόρισε τη σοβαρότητα: Critical (crash στο >1% των χρηστών), High (0,1–1%), Medium (<0,1%). Για Critical crashes — άμεση απόκριση. Το Google Play Console ταξινομεί αυτόματα τα crashes με βάση τον αριθμό των επηρεαζόμενων χρηστών.
2: Ανάλυση stack trace — άνοιξε το log στο Crashlytics, δες την ακριβή τοποθεσία της βλάβης. Έλεγξε custom keys: ποια οθόνη, ποια δεδομένα, έκδοση ΛΣ. Σύγκρινε με την τελευταία ανάπτυξη — συχνά το crash προκαλείται από μια πρόσφατη αλλαγή στον κώδικα που επηρέασε ένα απροσδόκητο σενάριο χρήσης.
3: Αναπαραγωγή — προσπάθησε να αναπαραγάγεις το crash σε συσκευή ή εξομοιωτή με παρόμοιες παραμέτρους. Εάν δεν τα καταφέρεις, έλεγξε το crash log για μοτίβα: συγκεκριμένα μοντέλα (Samsung A10), εκδόσεις Android (API < 26), locale. Λύση — πρόσθεσε μια προστατευτική συνθήκη που καλύπτει το σενάριο.
4: Διόρθωση και παρακολούθηση — κυκλοφόρησε hotfix με προτεραιότητα. Μετά την κυκλοφορία, βεβαιώσου ότι το ποσοστό crash για αυτόν τον τύπο πέφτει στο μηδέν. Γράψε δοκιμή παλινδρόμησης που καλύπτει το σενάριο crash. Χωρίς δοκιμή, το ίδιο σφάλμα μπορεί να επιστρέψει στην επόμενη αναδιάρθρωση.
Συχνές Ερωτήσεις
Φυσιολογικό ποσοστό crash — λιγότερο από 0,1% για εκδόσεις παραγωγής. Το Google Play συνιστά τη διατήρηση του ποσοστού crash κάτω από 1,5%, αλλά οι κορυφαίες εφαρμογές (YouTube, Instagram) διατηρούν 0,01–0,05%. Για εκδόσεις νέας λειτουργικότητας, επιτρέπεται προσωρινή αύξηση έως 0,5% με επακόλουθη μείωση μετά από hotfix.
Crash — η εφαρμογή τερματίζεται ανώμαλα. ANR (Application Not Responding) — η εφαρμογή παγώνει για περισσότερο από 5 δευτερόλεπτα, αλλά δεν κλείνει βίαια. Ο χρήστης βλέπει το παράθυρο διαλόγου “Η εφαρμογή δεν ανταποκρίνεται” και μπορεί να περιμένει ή να κλείσει. Τα προβλήματα ANR δεν είναι λιγότερο σοβαρά από τα crashes και επηρεάζουν επίσης τη βαθμολογία στο κατάστημα.
Διαφορετικές συσκευές έχουν διαφορετικές εκδόσεις ΛΣ, ποσότητες μνήμης, εκδόσεις βιβλιοθηκών και ακόμη και επεξεργαστές. Παράδειγμα: ένα crash στο Android 6 (API 23) λόγω έλλειψης άδειας χρόνου εκτέλεσης μπορεί να μην αναπαράγεται στο Android 12.
Πρόσθεσε custom breadcrumbs στο Crashlytics: κατέγραψε βασικά συμβάντα πριν από την εκτέλεση της λειτουργίας. Debug symbols (dSYM, ProGuard mapping) — ανέβασέ τα στο Crashlytics για να δεις τα πραγματικά ονόματα συναρτήσεων, όχι συγκεχυμένα.
Στην παραγωγή — ποτέ. Μη διαχειρισμένα crashes χειροτερεύει την εμπειρία χρήστη. Χρησιμοποίησε try/catch με καταγραφή σφάλματος. Σε λειτουργία debug, το crash επιτρέπεται για γρήγορη ανατροφοδότηση στον προγραμματιστή. Assertions — για έλεγχο αμετάβλητων που δεν πρέπει ποτέ να παραβιάζονται, αλλά μόνο σε debug builds.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης