क्रैश रिपोर्टिंग और प्रतीक-युक्त स्टैक ट्रेस
कार्रवाई योग्य क्रैश रिपोर्ट के लिए डीऑब्फ़स्केशन मैपिंग के साथ Crashlytics और Sentry एकीकृत कीजिए।
क्रैश रिपोर्टिंग और प्रतीक-युक्त स्टैक ट्रेस, CoddyKit पर Flutter मोबाइल विकास का एक निःशुल्क पाठ है। यह 4 में से 3वाँ पाठ है। इस अध्ययन पथ के 3 तक कोई भी पाठ पूरा पढ़ना निःशुल्क है — इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ व्यावहारिक अभ्यास भी उपलब्ध कराता है। यह Flutter मोबाइल विकास सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। Flutter मोबाइल विकास पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
कच्चे क्रैश ट्रेस बेकार क्यों हैं
जब आप Flutter ऐप को रिलीज़ मोड में भेजते हैं, तो Dart कंपाइलर अनुकूलित AOT मशीन कोड बनाता है और इंसानों के पढ़ने योग्य प्रतीकों को हटा देता है। उत्पादन में होने वाला क्रैश अब UserRepository.fetchProfile रिपोर्ट नहीं करता — इसके बजाय #00 abs 0000007f9c2a1b40 जैसा हेक्स ऑफ़सेट रिपोर्ट करता है।
- डिबग बिल्ड प्रतीकों को बनाए रखते हैं, इसलिए ट्रेस स्थानीय रूप से पढ़ने योग्य होते हैं।
- रिलीज़ बिल्ड गोपित और प्रतीक-विहीन होते हैं, इसलिए डिवाइस पर मौजूद ट्रेस केवल पते होते हैं।
- इन पतों को फिर से मेथड नामों में बदलने के लिए आपको सिंबॉलिकेशन (मूल iOS/Android प्रतीक) और डिइन्क्रिप्शन (Dart प्रतीक मैपिंग) चाहिए।
यह पाठ Crashlytics और Sentry को जोड़ता है, ताकि उत्पादन का हर क्रैश पूरी तरह सिंबॉलिकेट होकर कार्रवाई योग्य रूप में पहुँचे।
गोपनीकरण और प्रतीक मैप फ़ाइल
Flutter में गोपनीकरण वैकल्पिक है। आप इसे बिल्ड के समय सक्षम करते हैं और Flutter चुनी हुई निर्देशिका में प्रत्येक लक्ष्य आर्किटेक्चर के लिए एक Dart प्रतीक मैप लिखता है।
--obfuscateDart पहचानकर्ताओं के नाम छोटे टोकन में बदलता है।--split-debug-infoमैपिंग फ़ाइलें लिखता है, जैसेapp.android-arm64.symbols, ताकि बाद में गोपनीकरण को उलटा जा सके।
आपको हर रिलीज़ के लिए इन प्रतीक फ़ाइलों को संग्रहित करना चाहिए। भेजे गए बाइनरी से मेल खाने वाली सटीक फ़ाइल के बिना ट्रेस का डिइन्क्रिप्शन कभी नहीं किया जा सकता।
# Build an obfuscated Android release and keep the Dart symbols
flutter build appbundle --release \
--obfuscate \
--split-debug-info=build/symbols/v1.4.0
# iOS equivalent
flutter build ipa --release \
--obfuscate \
--split-debug-info=build/symbols/v1.4.0दो स्तर: मूल और Dart प्रतीक
Flutter क्रैश रिपोर्ट में सिंबॉलिकेशन की दो अलग समस्याएँ होती हैं और इन्हें भ्रमित करना ट्रेस के अपठनीय बने रहने का सबसे बड़ा कारण है।
- मूल स्तर (iOS dSYM, Android NDK
.soप्रतीक): इंजन, प्लगइन और प्लेटफ़ॉर्म कोड के अंदर होने वाले क्रैश का समाधान करता है। इसे Crashlytics का मूल प्रतीक अपलोड संभालता है। - Dart स्तर (
--split-debug-infoफ़ाइलें): गोपनीकरण के बाद आपके Dart व्यावसायिक तर्क के अंदर होने वाले क्रैश का समाधान करता है।
जब आप dSYMs/NDK प्रतीक अपलोड कर देते हैं, तो Crashlytics मूल फ़्रेमों का सिंबॉलिकेशन अपने-आप करता है, लेकिन Dart फ़्रेमों के लिए Flutter प्रतीक फ़ाइल को अभी भी flutter symbolize के माध्यम से चलाना पड़ता है।
Firebase Crashlytics प्रारंभ करना
Crashlytics को runApp से पहले प्रारंभ करना चाहिए और Flutter के त्रुटि हुक्स से जोड़ना चाहिए, ताकि कुछ भी छूट न जाए।
FlutterError.onErrorसमकालिक फ़्रेमवर्क त्रुटियों को पकड़ता है।PlatformDispatcher.instance.onErrorऐसी असमकालिक त्रुटियों को पकड़ता है जो ज़ोन से बाहर निकल जाती हैं।
दोनों को recordFlutterFatalError / recordError में भेजने से यह सुनिश्चित होता है कि हर अनकैप्चर की गई Dart त्रुटि Crashlytics तक पहुँचे।
import 'dart:ui';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
final crashlytics = FirebaseCrashlytics.instance;
FlutterError.onError = crashlytics.recordFlutterFatalError;
PlatformDispatcher.instance.onError = (error, stack) {
crashlytics.recordError(error, stack, fatal: true);
return true;
};
runApp(const MyApp());
}Crashlytics पर मूल प्रतीक अपलोड करना
मूल फ़्रेमों के लिए Crashlytics को बिल्ड की प्रतीक फ़ाइलें Firebase पर अपलोड की हुई चाहिए।
- iOS:
FirebaseCrashlyticsरन स्क्रिप्ट dSYMs अपलोड करती है; बिटकोड या अनुपलब्ध dSYMs के लिएupload-symbolsटूल का उपयोग करें। - Android:
firebase-crashlyticsGradle प्लगइन तब NDK प्रतीक अपलोड करता है, जबnativeSymbolUploadEnabledtrue हो।
ये अपलोड रनटाइम पर नहीं, बल्कि बिल्ड/रिलीज़ के समय होते हैं, इसलिए इन्हें आपकी CI पाइपलाइन का हिस्सा होना चाहिए।
// android/app/build.gradle
plugins {
id 'com.google.firebase.crashlytics'
}
android {
buildTypes {
release {
firebaseCrashlytics {
// Upload Android NDK native symbols
nativeSymbolUploadEnabled true
unstrippedNativeLibsDir 'build/app/intermediates/merged_native_libs'
}
}
}
}flutter symbolize से Dart फ़्रेम का डिइन्क्रिप्शन
Crashlytics आपके Dart --split-debug-info मैप को पढ़ नहीं सकता। जब किसी क्रैश के Dart फ़्रेम गोपित टोकन दिखाते हैं, तो आप कच्चा ट्रेस निर्यात करके उसे Flutter SDK टूल के माध्यम से चलाते हैं।
flutter symbolizeगोपित स्टैक ट्रेस के साथ उस ABI और संस्करण की सटीक प्रतीक फ़ाइल लेता है।- आउटपुट हेक्स ऑफ़सेट और छोटे टोकन को वास्तविक Dart मेथड नामों और पंक्ति संख्याओं से बदल देता है।
इसीलिए हर रिलीज़ की प्रतीक निर्देशिका को संग्रहित करना अनिवार्य है — आपको क्रैश करने वाले बिल्ड से मेल खाने वाली फ़ाइल चाहिए।
# stack.txt holds the obfuscated trace copied from Crashlytics
flutter symbolize \
-i stack.txt \
-d build/symbols/v1.4.0/app.android-arm64.symbols
# Output now shows real frames, e.g.:
# #00 UserRepository.fetchProfile (package:app/data/user_repository.dart:42)Crashlytics के साथ Sentry जोड़ना
Sentry, Crashlytics का लोकप्रिय विकल्प या सहायक है। Flutter SDK आपके ऐप को रैप करता है और बिना संभाली गई त्रुटियों को अपने-आप पकड़ता है, लेकिन इसका वास्तविक मूल्य इसकी डिबग प्रतीक पाइपलाइन में है।
SentryFlutter.initएकीकरण इंस्टॉल करता है और आपको सैंपलिंग, रिलीज़ और वातावरण निर्धारित करने देता है।runAppकोappRunnerमें रैप करने से यह सुनिश्चित होता है कि ज़ोन-स्तरीय त्रुटि हैंडलर सक्रिय है।
release स्ट्रिंग को name+buildNumber पर सेट करें, ताकि Sentry क्रैश का मिलान सही अपलोड किए गए प्रतीकों से कर सके।
import 'package:flutter/material.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
Future<void> main() async {
await SentryFlutter.init(
(options) {
options.dsn = 'https://examplePublicKey@o0.ingest.sentry.io/0';
options.tracesSampleRate = 0.2;
options.environment = 'production';
options.release = 'com.coddykit.app@1.4.0+140';
},
appRunner: () => runApp(const MyApp()),
);
}Sentry पर डिबग प्रतीक अपलोड करना
सही आर्टिफ़ैक्ट को sentry-cli (या बिल्ड के दौरान Sentry Dart प्लगइन) से अपलोड करने के बाद Sentry अपने-आप सर्वर पर डिइन्क्रिप्शन करता है।
debug-files uploadके ज़रिए मूल dSYM / ELF डिबग फ़ाइलें अपलोड करें।- Flutter Dart प्रतीक (
--split-debug-infoका आउटपुट) अपलोड करें, ताकि गोपित Dart फ़्रेम का समाधान हो सके।
Sentry का मिलान डिबग ID और रिलीज़ के आधार पर होता है, इसलिए CI से किए गए अपलोड में वही --split-debug-info निर्देशिका इस्तेमाल होनी चाहिए जिससे भेजा गया बाइनरी बना था।
# Upload native + Dart debug information files for this release
sentry-cli debug-files upload \
--org coddykit --project flutter-app \
build/symbols/v1.4.0
# Associate the release so Sentry can match incoming events
sentry-cli releases new com.coddykit.app@1.4.0+140
sentry-cli releases finalize com.coddykit.app@1.4.0+140संदर्भ और ब्रेडक्रंब से रिपोर्ट को समृद्ध करना
प्रतीक-निर्धारित ट्रेस आपको बताता है कि कहाँ; संदर्भ बताता है कि क्यों। दोनों SDK आपको मेटाडेटा जोड़ने देते हैं, ताकि किसी क्रैश को दोबारा उत्पन्न किया जा सके।
- कस्टम कुंजियाँ: फ़ीचर फ़्लैग, उपयोगकर्ता स्तर, वर्तमान मार्ग।
- ब्रेडक्रंब / लॉग: क्रैश तक पहुँचने वाली हाल की कार्रवाइयों का क्रम।
- उपयोगकर्ता पहचानकर्ता: यह अनुमान लगाने के लिए कि क्रैश कितने उपयोगकर्ताओं को प्रभावित करता है।
PII को कभी भी लॉग न करें। केवल अपारदर्शी आईडी और फ़ीचर से संबंधित फ़्लैग का उपयोग करें।
Future<void> tagCrashContext(FirebaseCrashlytics c) async {
await c.setUserIdentifier('user_8f3a');
await c.setCustomKey('subscription', 'pro');
await c.setCustomKey('active_route', '/checkout');
await c.log('Tapped Pay button with cart total 49.99');
}हैंडल की गई (गैर-घातक) त्रुटियाँ दर्ज करना
हर त्रुटि के कारण ऐप को क्रैश नहीं होना चाहिए। नेटवर्क कॉल का विफल होना या पकड़ी गई पार्सिंग त्रुटि एक गैर-घातक घटना है, फिर भी आप उसकी जानकारी रखना चाहेंगे।
- क्रैशलिटिक्स:
recordError(e, st, fatal: false)। - सेंट्री:
Sentry.captureException(e, stackTrace: st)।
यह स्वतंत्र Dart उदाहरण कैच-और-रिपोर्ट पैटर्न दिखाता है, जिसे आप किसी सेवा स्तर से इनमें से किसी SDK में भेज सकते हैं।
void reportHandled(Object error, StackTrace stack) {
// In production this would call recordError / captureException.
print('NON-FATAL: $error');
print('Top frame: ${stack.toString().split('\n').first}');
}
Map<String, dynamic> parseProfile(String raw) {
if (!raw.startsWith('{')) {
throw const FormatException('Profile payload is not JSON');
}
return {'ok': true};
}
void main() {
try {
parseProfile('not-json');
} catch (e, st) {
reportHandled(e, st);
}
print('App keeps running after handled error');
}प्रतीक अपलोड को CI का हिस्सा बनाना
उत्पादन क्रैश के पढ़े न जा सकने का सबसे बड़ा एकल कारण टूटी हुई रिलीज़ प्रक्रिया है: कोई व्यक्ति बिल्ड भेज देता है, लेकिन उसके प्रतीकों को अपलोड या संग्रहित करना भूल जाता है। इसे स्वचालित करें।
--obfuscate --split-debug-info=build/symbols/$VERSIONके साथ बिल्ड करें।- नेटिव प्रतीक (क्रैशलिटिक्स Gradle प्लगइन / iOS रन स्क्रिप्ट) और Dart प्रतीक (
sentry-cli) को उसी CI जॉब में अपलोड करें। build/symbols/$VERSIONको CI आर्टिफ़ैक्ट के रूप में तब तक सुरक्षित रखें, जब तक उस संस्करण के कारण वास्तविक उपयोगकर्ताओं के यहाँ क्रैश हो सकते हैं।
हर जगह उपयोग की गई संस्करण स्ट्रिंग — Sentry release, क्रैशलिटिक्स setCustomKey, और प्रतीक निर्देशिका के नाम — को एक ही सत्य-स्रोत से जोड़ें, ताकि मिलान में कभी अंतर न आए।
# CI snippet (bash) — one job that builds and ships symbols
VERSION=$(grep '^version:' pubspec.yaml | awk '{print $2}')
flutter build appbundle --release \
--obfuscate --split-debug-info=build/symbols/$VERSION
# Dart + native symbols to Sentry
sentry-cli debug-files upload --org coddykit --project flutter-app \
build/symbols/$VERSION
# Keep the map for later flutter symbolize runs
tar -czf symbols-$VERSION.tgz build/symbols/$VERSIONत्वरित जाँच: Dart फ़्रेम अस्पष्ट क्यों बने रहते हैं
आपने --obfuscate --split-debug-info के साथ बनाया गया Flutter रिलीज़ भेजा है। क्रैशलिटिक्स में नेटिव फ़्रेम पढ़े जा सकते हैं, लेकिन आपके व्यावसायिक तर्क के Dart फ़्रेम अब भी छोटे टोकन और हेक्स ऑफ़सेट दिखा रहे हैं। सही समाधान क्या है?
पुनरावलोकन: क्रियान्वित करने योग्य क्रैश प्रक्रिया-श्रृंखला
अब आपके पास शुरू से अंत तक ऐसी प्रक्रिया-श्रृंखला है, जो रहस्यमय उत्पादन क्रैश को ठीक किए जा सकने वाले बग रिपोर्ट में बदल देती है।
- बिल्ड को
--obfuscate --split-debug-info=build/symbols/$VERSIONके साथ रिलीज़ करें और हर रिलीज़ के लिए उस निर्देशिका को संग्रहित करें। FlutterError.onError+PlatformDispatcher.onError(क्रैशलिटिक्स) और/याSentryFlutter.initकोappRunnerके साथ उपयोग करके कैप्चर करें।- दो स्तरों के प्रतीकों का प्रतीक-निर्धारण करें: नेटिव (dSYM/NDK अपलोड) और Dart (क्रैशलिटिक्स के लिए
flutter symbolize, प्रतीक अपलोड करने के बाद Sentry के लिए सर्वर-पक्ष पर स्वचालित)। - उपयोगकर्ता आईडी, कस्टम कुंजियों और ब्रेडक्रंब से अतिरिक्त संदर्भ दें — PII नहीं।
- CI में प्रतीक अपलोड को स्वचालित करें और एक ही संस्करण स्ट्रिंग को एकमात्र सत्य-स्रोत बनाए रखें।
स्वर्णिम नियम: क्रैश रिपोर्ट उतनी ही अच्छी होती है, जितनी उस सटीक बिल्ड के लिए सुरक्षित रखी गई प्रतीक फ़ाइल।
एआई शिक्षक के साथ Dart सीखें — निःशुल्क
अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।
- पाठ्यक्रम
- 22
- पाठ
- 88
अक्सर पूछे जाने वाले प्रश्न
क्या “क्रैश रिपोर्टिंग और प्रतीक-युक्त स्टैक ट्रेस” पाठ निःशुल्क है?
हाँ — Flutter मोबाइल विकास अध्ययन पथ के 3 तक कोई भी पाठ, जिसमें “क्रैश रिपोर्टिंग और प्रतीक-युक्त स्टैक ट्रेस” भी शामिल है, यहाँ वेब पर पूरा पढ़ना निःशुल्क है। इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ इंटरैक्टिव अभ्यास भी उपलब्ध कराता है। Flutter मोबाइल विकास पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
“क्रैश रिपोर्टिंग और प्रतीक-युक्त स्टैक ट्रेस” में मैं क्या सीखूँगा?
कार्रवाई योग्य क्रैश रिपोर्ट के लिए डीऑब्फ़स्केशन मैपिंग के साथ Crashlytics और Sentry एकीकृत कीजिए। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ Flutter मोबाइल विकास का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।
क्या Flutter मोबाइल विकास शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?
पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर Flutter मोबाइल विकास शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 3वाँ पाठ है।
“क्रैश रिपोर्टिंग और प्रतीक-युक्त स्टैक ट्रेस” पाठ पूरा करने में कितना समय लगता है?
CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।
क्या मैं इस Flutter मोबाइल विकास पाठ में कोड लिख और चला सकता हूँ?
हाँ। हर Flutter मोबाइल विकास पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।
इस पाठ्यक्रम के सभी पाठ
- बिल्ड फ़्लेवर और पर्यावरण कॉन्फ़िगरेशन
- Fastlane और GitHub Actions से स्वचालित पाइपलाइन
- क्रैश रिपोर्टिंग और प्रतीक-युक्त स्टैक ट्रेस
- रिमोट कॉन्फ़िगरेशन, सुविधा फ़्लैग और चरणबद्ध रिलीज़