الفصل العاشر: محرك التطبيق (الطرود البرمجية) Chapter 10: Essential Packages & Engine
التعرف على الأدوات الخارجية التي جعلت MRE CashBook نظاماً قوياً ومتكاملاً.
في MRE Code، مش بنضيف أي حزمة وخلاص. إحنا بنتبع معايير صارمة قبل إضافة أي dependency:
الشعبية (Popularity): لازم تكون الحزمة مدعومة من مجتمع كبير ولها تحديثات مستمرة.
الأداء (Performance): لازم يكون تأثيرها على حجم التطبيق وسرعته بسيط.
التوافق (Compatibility): لازم تدعم أحدث إصدارات Flutter وتشتغل على Android و iOS و Huawei بسلاسة.
اختيار flutter_bloc ماجاش من فراغ. هو المترجم اللي بيحول ضغطات المستخدم لأفعال برمجية منظمة.
flutter_bloc: ^9.1.1
equatable: ^2.0.8
ليه Equatable مع BLoC؟ عشان الباقة دي بتخلينا نقارن الحالات ببعضها بسهولة. لو الحالة الجديدة هي هي القديمة، الـ UI مش هيعمل Rebuild، وكدة بنوفر في استهلاك البطارية والمعالج.
بدون equatable، فلاتر هيفتكر إن الحالة اتغيرت حتى لو القيم هي هي، وده بيعمل استهلاك زيادة في الموارد.
من أصعب التحديات في تطبيقات الحسابات هي سرعة الوصول للداتا وحمايتها. drift (moor سابقاً) حلت المشكلة دي بذكاء.
// Example of an Entry Table in Drift
class Entries extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get amount => text()();
DateTimeColumn get date => dateTime()();
IntColumn get bookId => integer().references(Books, #id)();
}
Pro Tip: التطبيق بيستخدم drift_flutter اللي بتوفر بيئة تشغيل آمنة للـ SQLite على الموبايل وبتهندل الـ Database Path أوتوماتيك.
تخيل لو كل شاشة بتعرف نسخة جديدة من الـ Database؟! ده هيخلي الرام تنفجر. get_it بيضمن إن في نسخة واحدة بس (Singleton) التطبيق كله بيستخدمها.
final sl = GetIt.instance;
Future init() async {
// Database instance
sl.registerLazySingleton(() => AppDatabase());
// Repositories
sl.registerLazySingleton(() => EntryRepositoryImpl(sl()));
// BLoCs
sl.registerFactory(() => EntriesBloc(sl()));
}
الحزم مش جزر منعزلة، هي بتشتغل مع بعض في تناغم مذهل:
المستخدم بيحب يشوف فلوسه رايحة فين في رسم بياني، وبيكره يستنى شاشة بيضاء وهي بتحمل.
بترسم الـ Spline Charts والـ Pie Charts بدقة عالية جداً وبدعم كامل للـ Interaction.
بتقدم الـ Skeleton Loading (تأثير اللمعان) اللي بيخلي المستخدم يشعر إن التطبيق سريع جداً حتى لو في تأخير في الداتا.
بتخلي الأرقام "تعد" لما الشاشة تفتح، وده بيدي لمسة premium للتصميم.
تعالوا نشوف كود حقيقي لاستخدام باقة fl_chart:
LineChart(
LineChartData(
gridData: FlGridData(show: false),
titlesData: FlTitlesData(show: true),
lineBarsData: [
LineChartBarData(
spots: [FlSpot(0, 100), FlSpot(1, 200), FlSpot(2, 150)],
isCurved: true,
barWidth: 4,
color: context.colors.primary,
),
],
),
);
وبالنسبة للتقارير، بنستخدم pdf مع دعم الخطوط العربية:
final fontData = await rootBundle.load("assets/fonts/Cairo-Regular.ttf");
final ttf = pw.Font.ttf(fontData);
pdf.addPage(pw.Page(
theme: pw.ThemeData.withFont(base: ttf),
build: (context) => pw.Directionality(
textDirection: pw.TextDirection.rtl,
child: pw.Text("تقرير المصروفات لشهر مارس"),
),
));
الأبليكيشن متكامل مع خدمات فيربيز لضمان أفضل تجربة:
| Package | Goal (AR) |
|---|---|
firebase_messaging | إرسال عروض وتنبيهات فورية للمستخدمين. |
firebase_crashlytics | رصد الأخطاء وإرسال تقارير مفصلة للمطورين. |
بما إن في أجهزة كتير من هواوي مفيهاش خدمات جوجل، كان لازم ندعمها بشكل خاص:
دي الحزمة المسؤولة عن استقبال الإشعارات على أجهزة هواوي الحديثة لضمان وصول التنبيهات لكل المستخدمين بلا استثناء.
الداتا المالية حساسة جداً، عشان كدة استخدمنا باقات مخصصة للأمان:
- local_auth: بتشغل البصمة (Fingerprint) والـ Face ID.
- encrypt: بتشفر البيانات الحساسة قبل ما تتحفظ في الـ Backup.
- crypto: لإجراء عمليات الـ hashing والمقارنات الآمنة.
إزاي بنحدث الحزم من غير ما المشروع يبوظ؟
التدرج: مابنحدثش كل الحزم مرة واحدة. بنحدث حزمة حزمة ونجرب.
Changelog: لازم نقرأ الـ README والـ Changelog عشان لو في Breaking Changes.
Tests: بنشغل الـ Unit Tests بعد كل تحديث عشان نضمن إن المنطق الأساسي ماتأثرش.
عشان تضمن إن مشروعك يفضل "نظيف" وسهل الصيانة، اتبع القواعد دي:
ماتستخدمش الباقة بشكل مباشر في الـ UI. اعمل كلاس (Wrapper) أو (Interface). ليه؟ عشان لو حبيت تغير الباقة في المستقبل، تغير في مكان واحد بس مش في كل المشروع.
يفضل تستخدم إصدارات محددة (Pinned Versions) في الـ pubspec.yaml للمشاريع الكبيرة، عشان تضمن إن أي تحديث مفاجئ من صاحب الباقة ما يبوظش الكود بتاعك.
| Database | Type | Pros | Cons |
|---|---|---|---|
| Drift (MRE Choice) | Relational (SQL) | Relational, Type-safe | More Boilerplate |
| Hive | NoSQL (Key-Value) | Super Fast | No Relations |
| SharedPrefs | Key-Value | Simple | For Small Settings Only |
الباقات اللي بتتعامل مع الـ hardware (زي البصمة أو الإشعارات) ساعات بتعمل مشاكل في الـ Build:
لو حصل خطأ في الـ iOS Build، جرب الكوماند ده:
cd ios && rm -rf Pods Podfile.lock && pod install && cd ..
باقات فيربيز ساعات بتحتاج إصدارات معينة من google-services في ملف build.gradle.
في الفصل ده عرفنا إن قوة MRE CashBook جاية من الاختيار الذكي للأدوات والتعاون المتناغم بين الباقات المختلفة.
| Layer | Primary Package | Role |
|---|---|---|
| State | flutter_bloc | Managing Logic & UI Updates |
| Data | drift | SQLite Database Management |
| DI | get_it | Global Object Registry |
| UI | fl_chart | Visualization |
| Reporting | pdf | Document Generation |