نظرة عامة على معمارية Flutter
لماذا Flutter مختلف
يتخذ Flutter نهجاً مختلفاً جذرياً في التطوير متعدد المنصات مقارنة بالأطر الأخرى. بدلاً من استخدام مكونات واجهة المستخدم الأصلية للمنصة أو عرض الويب، يرسم Flutter كل بكسل على الشاشة باستخدام محرك العرض عالي الأداء الخاص به. هذا يمنح Flutter تحكماً كاملاً في كل بكسل، مما ينتج عنه واجهة مستخدم متسقة عبر جميع المنصات ورسوم متحركة سلسة بمعدل 60 إطار في الثانية (أو 120 إطار في الثانية).
Flutter مقابل الأطر الأخرى
لتقدير معمارية Flutter، دعنا نقارنها مع أساليب التطوير متعدد المنصات الشائعة الأخرى.
التطوير الأصلي
التطوير الأصلي (Swift/Kotlin) يمنحك وصولاً مباشراً لواجهات برمجة المنصة ومكونات واجهة المستخدم الأصلية. الجانب السلبي هو الحفاظ على قاعدتي كود منفصلتين لـ iOS و Android، مما يضاعف جهد ووقت التطوير.
نهج React Native
يستخدم React Native جسر JavaScript للتواصل بين كود JavaScript ومكونات المنصة الأصلية. يصف كود JavaScript واجهة المستخدم، ويترجم React Native ذلك إلى عروض أصلية. بينما يستخدم هذا مكونات أصلية حقيقية، يمكن أن يصبح الجسر عنق زجاجة في الأداء، خاصة أثناء الرسوم المتحركة أو معالجة البيانات الكثيفة.
مقارنة المعمارية
// التطوير الأصلي:
// كود التطبيق (Swift/Kotlin) > مكونات UI أصلية > اللوحة
// المزايا: أفضل أداء، وصول كامل للمنصة
// العيوب: قاعدتا كود، لا مشاركة كود
// React Native:
// كود التطبيق (JavaScript) > الجسر > مكونات UI أصلية > اللوحة
// المزايا: قاعدة كود واحدة، مكونات أصلية
// العيوب: تكلفة الجسر، تناقضات المنصات
// Flutter:
// كود التطبيق (Dart) > محرك Flutter (Skia) > اللوحة
// المزايا: قاعدة كود واحدة، تحكم دقيق بالبكسل، لا جسر
// العيوب: حجم تطبيق أكبر، عرض مخصص (ليس مظهر أصلي)
نهج Flutter
يجمع Flutter كود Dart مباشرة إلى كود آلة ARM أصلي ويستخدم محرك الرسومات Skia لعرض واجهة المستخدم. لا يوجد جسر ولا عرض ويب ولا اعتماد على مكونات واجهة المستخدم الخاصة بالمنصة. يمتلك Flutter خط أنابيب العرض بالكامل من ودجاتك وصولاً إلى البكسلات الفردية على الشاشة.
تجميع Dart: AOT و JIT
يستخدم Flutter لغة Dart كلغة برمجة، ويدعم Dart وضعي تجميع يخدمان أغراضاً مختلفة أثناء التطوير والإنتاج.
تجميع JIT (في الوقت المناسب)
أثناء التطوير، يستخدم Dart تجميع JIT. يتم تجميع الكود أثناء التشغيل، مما يمكّن ميزة Flutter الأكثر شعبية: إعادة التحميل السريع. مع إعادة التحميل السريع، يمكنك إجراء تغييرات على كودك ورؤية النتائج في أقل من ثانية دون فقدان حالة التطبيق الحالية.
تجميع JIT في التطوير
// أثناء التطوير (وضع التصحيح):
// 1. تكتب كود Dart
// 2. يجمعه Dart VM في الوقت المناسب
// 3. يتم حقن التغييرات في التطبيق الجاري
// 4. تُعاد بناء شجرة الودجات بالكود الجديد
// 5. تُحفظ حالة التطبيق!
// سير عمل إعادة التحميل السريع:
// 1. عدّل كودك (مثل تغيير لون)
// 2. احفظ الملف (Ctrl+S / Cmd+S)
// 3. يحقن Flutter التغييرات (~300 مللي ثانية)
// 4. تتحدث واجهة المستخدم فوراً بدون إعادة تشغيل
// إعادة التشغيل السريع (تفقد الحالة):
// اضغط Shift+R في الطرفية أو انقر زر إعادة التشغيل
// يعيد بناء التطبيق بالكامل من الصفر
تجميع AOT (المسبق)
للإصدارات الإنتاجية، يستخدم Dart تجميع AOT. يتم تجميع كود Dart مباشرة إلى كود آلة ARM أو x86 أصلي قبل تشغيل التطبيق. هذا يلغي تكلفة التجميع في وقت التشغيل وينتج ثنائيات سريعة وفعالة.
تجميع AOT للإنتاج
// بناء الإنتاج (وضع الإصدار):
// 1. يحلل مترجم Dart كل الكود
// 2. يزيل هز الشجرة الكود غير المستخدم
// 3. يُجمع الكود إلى كود آلة أصلي
// 4. لا حاجة لـ Dart VM في وقت التشغيل
// 5. النتيجة: بدء تشغيل سريع، أداء سلس
// أوامر البناء:
// flutter build apk --release (Android APK)
// flutter build appbundle --release (Android App Bundle)
// flutter build ios --release (iOS)
// flutter build web --release (الويب)
// flutter build windows --release (سطح مكتب Windows)
// flutter build macos --release (سطح مكتب macOS)
محرك Flutter (Skia)
في قلب Flutter يوجد محرك العرض الخاص به، المبني على Skia، مكتبة رسومات ثنائية الأبعاد تُستخدم أيضاً في Google Chrome و Android ومنتجات رئيسية أخرى. محرك Flutter مكتوب بلغة C++ ويوفر عرض منخفض المستوى، تخطيط النص، عمليات إدخال/إخراج الملفات والشبكة، دعم إمكانية الوصول، بنية الإضافات، وسلسلة أدوات تشغيل وتجميع Dart.
مكونات محرك Flutter
// يتضمن محرك Flutter:
// 1. محرك رسومات Skia
// - مكتبة عرض ثنائية الأبعاد (مكتوبة بـ C++)
// - يتعامل مع جميع عمليات الرسم
// - عرض معجّل بواسطة GPU
// - يُستخدم في Chrome و Android و Firefox وغيرها
// 2. بيئة تشغيل Dart
// - ينفذ كود Dart المُجمع
// - يدير الذاكرة (جمع القمامة)
// - يتعامل مع العوازل (التزامن)
// 3. عرض النص
// - يستخدم libtxt و HarfBuzz لتخطيط النص
// - يدعم النصوص المعقدة (العربية، CJK، إلخ)
// - يتعامل مع النص ثنائي الاتجاه (LTR/RTL)
// 4. قنوات المنصة
// - جسر تواصل مع المنصة الأصلية
// - تمرير رسائل مسلسلة
// - يُستخدم للوصول لواجهات API الأصلية
الأشجار الثلاث
نظام العرض في Flutter مبني حول ثلاث هياكل شجرية متوازية تعمل معاً لبناء وتحديث واجهة المستخدم بكفاءة. فهم هذه الأشجار ضروري لكتابة تطبيقات Flutter عالية الأداء.
1. شجرة الودجات
شجرة الودجات هي شجرة كائنات الودجات التي تحددها في كودك. الودجات خفيفة الوزن ووصفية غير قابلة للتغيير لجزء من واجهة المستخدم. هي مثل المخططات التي تصف كيف يجب أن تبدو واجهة المستخدم.
مثال على شجرة الودجات
// ينشئ كودك شجرة ودجات:
MaterialApp // الودجة الجذر
+-- Scaffold // هيكل الصفحة
+-- AppBar // الشريط العلوي
| +-- Text('My App') // نص العنوان
+-- Center // تخطيط توسيط
+-- Column // تخطيط عمودي
+-- Icon(...) // أيقونة
+-- Text(...) // نص
+-- ElevatedButton // زر
+-- Text('Click Me')
2. شجرة العناصر
شجرة العناصر هي إنشاء نسخ من شجرة الودجات. كل ودجة تنشئ عنصراً مقابلاً. العناصر قابلة للتغيير وتحتفظ بالموقع الفعلي في الشجرة. تعمل كجسر بين أوصاف الودجات غير القابلة للتغيير وكائنات العرض القابلة للتغيير.
مفهوم شجرة العناصر
// شجرة الودجات (مخططات غير قابلة للتغيير):
// Container(color: red) > Container(color: blue)
//
// شجرة العناصر (نسخ قابلة للتغيير):
// ContainerElement -------- يدير دورة الحياة
// - يحتفظ بمرجع للودجة الحالية
// - يحتفظ بمرجع لكائن العرض
// - يدير العناصر الفرعية
//
// عندما تتغير الودجة (أحمر > أزرق):
// 1. يتم إنشاء ودجة جديدة (Container(color: blue))
// 2. يقارن العنصر الودجة القديمة والجديدة
// 3. إذا نفس النوع: يحدّث العنصر كائن العرض
// 4. إذا نوع مختلف: يُدمر العنصر ويُنشأ جديد
//
// لهذا أنواع الودجات مهمة للأداء!
3. شجرة العرض
شجرة العرض تحتوي على كائنات العرض الفعلية التي تتعامل مع التخطيط والرسم. كل كائن عرض يعرف حجمه وموقعه وكيفية رسم نفسه على الشاشة. شجرة العرض هي ما ينتج البكسلات التي تراها في النهاية.
خط أنابيب شجرة العرض
// خط أنابيب العرض:
//
// شجرة الودجات شجرة العناصر شجرة العرض
// (المخطط) (المدير) (الرسام)
//
// Text('Hi') > TextElement > RenderParagraph
// |
// +-- يحسب حجم النص
// +-- يحدد الموقع
// +-- يرسم الحروف على اللوحة
//
// Container() > ContainerElement > RenderDecoratedBox
// |
// +-- يحسب حجم الصندوق
// +-- يطبق القيود
// +-- يرسم الزخرفة
setState()، يتم إعادة بناء شجرة الودجات (يتم إعادة إنشاء الودجات)، لكن يتم تحديث شجرتي العناصر والعرض بذكاء. فقط الأجزاء التي تغيرت فعلاً يتم إعادة عرضها. هذا ما يجعل Flutter فعالاً.كل شيء ودجة
في Flutter، كل شيء ودجة. هذه فلسفة أساسية تبسط النموذج الذهني. سواء كان عنصراً هيكلياً مثل صف أو عمود، أو عنصراً مرئياً مثل زر أو صورة، أو عنصر تنسيق مثل حشو أو سمة، أو حتى إيماءات ورسوم متحركة، كلها ودجات.
كل شيء ودجة
// ودجات التخطيط:
Row(), Column(), Stack(), Wrap(), ListView()
// ودجات مرئية:
Text(), Image(), Icon(), Card(), Chip()
// ودجات تفاعلية:
ElevatedButton(), TextField(), Checkbox(), Slider()
// ودجات هيكلية:
Scaffold(), AppBar(), Drawer(), BottomNavigationBar()
// التنسيق والزخرفة:
Padding(), Center(), Align(), Container(), DecoratedBox()
// غير مرئية لكن وظيفية:
GestureDetector(), InkWell(), MediaQuery(), Theme()
// حتى التطبيق بالكامل هو ودجة!
MaterialApp(), CupertinoApp(), WidgetsApp()
Padding. هذا النهج التركيبي قوي ومرن.قنوات المنصة
بينما يتعامل Flutter مع عرض واجهة المستخدم بشكل مستقل، أحياناً تحتاج للوصول إلى ميزات خاصة بالمنصة مثل الكاميرا أو GPS أو البلوتوث أو واجهات API الأصلية. يستخدم Flutter قنوات المنصة لهذا التواصل.
معمارية قنوات المنصة
// تواصل قنوات المنصة:
//
// Flutter (Dart) المنصة (أصلي)
// +-----------+ +-------------+
// | تطبيقك | | كود أصلي |
// | | رسالة | (Kotlin/ |
// | MethodCh. | ------> | Swift/C++) |
// | | <------ | |
// +-----------+ نتيجة +-------------+
//
// أنواع الرسائل:
// 1. MethodChannel - استدعاءات مع نتائج
// 2. EventChannel - تدفقات بيانات
// 3. BasicMessageChannel - رسائل بسيطة
// مثال: الحصول على مستوى البطارية
// جانب Dart:
const platform = MethodChannel('com.example/battery');
final int batteryLevel = await platform.invokeMethod('getBatteryLevel');
// الجانب الأصلي (Kotlin/Swift) يتعامل مع
// استدعاء API المنصة الفعلي ويعيد النتيجة
camera و geolocator و shared_preferences تتعامل مع تواصل المنصة نيابةً عنك.كيف يعرض Flutter واجهة المستخدم
دعنا نتتبع خط أنابيب العرض الكامل من كود Dart إلى البكسلات على الشاشة.
خط أنابيب العرض الكامل
// الخطوة 1: مرحلة البناء
// تنشئ دوال build() الخاصة بك شجرة الودجات
// الودجات كائنات تكوين خفيفة وغير قابلة للتغيير
Widget build(BuildContext context) {
return Container(
color: Colors.blue,
child: Text('Hello Flutter'),
);
}
// الخطوة 2: تحديث شجرة العناصر
// ينشئ/يحدّث إطار Flutter العناصر
// تقارن العناصر الودجات القديمة مع الجديدة
// تقرر ما يحتاج للتغيير (خوارزمية المقارنة)
// الخطوة 3: مرحلة التخطيط
// تحسب كائنات العرض الأحجام والمواقع
// تتدفق القيود للأسفل في الشجرة (أب إلى ابن)
// تتدفق الأحجام للأعلى في الشجرة (ابن إلى أب)
// يحصل كل كائن عرض على حجمه وموقعه النهائي
// الخطوة 4: مرحلة الرسم
// ترسم كائنات العرض نفسها على الطبقات
// تُركب الطبقات معاً
// يترجم Skia عمليات الطبقات إلى أوامر GPU
// الخطوة 5: التركيب
// تُرسل الطبقات إلى GPU
// يعرض GPU الإطار النهائي
// النتيجة: بكسلات على الشاشة!
// خط الأنابيب بالكامل يعمل بمعدل 60 إطار/ثانية (16.67 مللي ثانية لكل إطار)
// أو 120 إطار/ثانية على الأجهزة المدعومة (8.33 مللي ثانية لكل إطار)
طبقات الإطار
إطار عمل Flutter منظم في طبقات، من العرض منخفض المستوى إلى الودجات عالية المستوى. كل طبقة تبني على التي تحتها.
طبقات إطار عمل Flutter
// من الأعلى (ما تستخدمه) إلى الأسفل (المحرك):
//
// +------------------------------------------+
// | Material / Cupertino | <-- ودجات لغة التصميم
// | (أزرار، بطاقات، تنقل، سمات) |
// +------------------------------------------+
// | Widgets | <-- طبقة التركيب
// | (StatelessWidget, StatefulWidget, |
// | InheritedWidget, إدارة الحالة) |
// +------------------------------------------+
// | Rendering | <-- التخطيط والرسم
// | (RenderObject, القيود, اختبار اللمس) |
// +------------------------------------------+
// | Foundation | <-- أدوات أساسية
// | (Key, BuildContext, أنواع أساسية) |
// +------------------------------------------+
// | Engine (C++) | <-- Skia, Dart VM, المنصة
// | (عرض Skia, النص, قنوات المنصة) |
// +------------------------------------------+
// | Platform (نظام التشغيل المضيف) | <-- Android, iOS, الويب, إلخ
// +------------------------------------------+
طبقة الأساس
توفر طبقة الأساس اللبنات الأساسية: الفئات الأساسية والدوال المساعدة والتجريدات المستقلة عن المنصة. تتضمن فئات مثل Key و BuildContext وبدائيات الرسوم المتحركة الأساسية.
طبقة العرض
تتعامل طبقة العرض مع حساب التخطيط والرسم. تنفذ نظام التخطيط القائم على القيود حيث تمرر الودجات الأب القيود للأسفل وتعيد الودجات الأبناء أحجامها للأعلى. فئة RenderObject هي جوهر هذه الطبقة.
طبقة الودجات
توفر طبقة الودجات الإطار التركيبي. هنا تعيش StatelessWidget و StatefulWidget و InheritedWidget. تدير شجرة العناصر وتتعامل مع عملية إعادة البناء الفعالة.
طبقتا Material و Cupertino
هذه أعلى الطبقات مستوى وتوفر ودجات جاهزة للاستخدام تتبع إرشادات تصميم محددة. Material تنفذ تصميم Material من Google، بينما Cupertino تنفذ لغة تصميم iOS من Apple.
ودجات Material مقابل Cupertino
// ودجات Material Design (نمط Android):
import 'package:flutter/material.dart';
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Material App')),
body: ElevatedButton(
onPressed: () {},
child: Text('Material Button'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
),
);
// ودجات Cupertino (نمط iOS):
import 'package:flutter/cupertino.dart';
CupertinoApp(
home: CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Cupertino App'),
),
child: CupertinoButton(
onPressed: () {},
child: Text('Cupertino Button'),
),
),
);
Platform.isIOS لعرض ودجات Cupertino على iOS وودجات Material على Android بشكل شرطي، مما يمنح المستخدمين تجربة منصة مألوفة.الملخص
في هذا الدرس، استكشفت معمارية Flutter بعمق. تعلمت كيف يختلف Flutter عن التطوير الأصلي و React Native بامتلاكه خط أنابيب العرض بالكامل. فهمت استراتيجية التجميع المزدوجة لـ Dart (JIT للتطوير، AOT للإنتاج)، ودور محرك Skia، والأشجار الثلاث (الودجات، العناصر، العرض)، وفلسفة "كل شيء ودجة"، وقنوات المنصة للوصول الأصلي، وخط أنابيب العرض الكامل، والبنية الطبقية للإطار. ستساعدك هذه المعرفة الأساسية في كتابة تطبيقات Flutter أكثر كفاءة وأفضل بنية.