الفرق بين Flutter وReact Native في اللغة والرسم والأداء والتوظيف ودعم العربية والأمان، ومتى نختار كل واحد منهما.
لا أحدهما أفضل بالمطلق. اختر React Native إن كان فريقك يعمل أصلًا بـ JavaScript أو TypeScript مع React، أو أردت واجهة مبنية من عناصر كل منصة الأصلية، أو كنت تشارك المنطق مع منتج ويب. واختر Flutter إن أردت واجهة مخصصة محكومة بدقة وتبدو متطابقة على كل جهاز، ولا مانع لديك من اعتماد لغة Dart. وفي معظم تطبيقات الأعمال يؤدي أيٌّ منهما الغرض، ويحسم الاختيار الفريقُ والتصميم والصيانة على المدى الطويل، لا أرقام الاختبارات المقارنة.
كلاهما ناضج، وكلاهما ينشر على App Store وGoogle Play من قاعدة شيفرة واحدة، وكلاهما يتغير بسرعة. وحيث قد تكون التفاصيل قد تغيّرت نبّهنا إلى ذلك، فراجع التوثيق الحالي قبل أن تلتزم.
اللغة والمنظومة
يستخدم **React Native** لغة JavaScript أو TypeScript مع React. فإن كان مطورو الويب لديك يكتبون React أصلًا انتقلت مهاراتهم، وأمكن للتطبيق أن يشارك المنتج الويب في الأنواع وقواعد التحقق وعملاء الواجهات البرمجية. ومنظومة npm ضخمة، لكن جودتها متفاوتة، وكثير من حزمها يفترض وجود متصفح.
ويستخدم **Flutter** لغة Dart، وهي لغة قوية الأنواع من Google. ومن يعرف Java أو C# أو Kotlin أو Swift يصبح منتجًا فيها سريعًا. ومنظومة الحزم في pub.dev أصغر، لكن عناصر الواجهة الأساسية من تطوير الفريق نفسه ومتسقة.
كيف يرسم كل منهما الواجهة
هذا هو أهم فرق تقني بينهما، وبه تُفسَّر معظم الفروق الأخرى.
يحوّل React Native مكونات React إلى عناصر المنصة الأصلية نفسها، فالزر فيه زر حقيقي في iOS أو Android. والأشكال والسلوكيات الجديدة للنظام تصل في الغالب مع نظام التشغيل. وثمن ذلك أن المنصتين تتصرفان باختلاف طفيف، وعليك أن تختبرهما معًا.
أما Flutter فيرسم كل نقطة في الشاشة بنفسه بمحرك رسم خاص به، ولا يستخدم عناصر المنصة. والنتيجة واجهة متطابقة على المنصتين وتحكم كامل في الحركة والتصميم المخصص. وثمن ذلك أن الشكل الأصلي يُعاد إنتاجه بعناصر Flutter نفسها، فإذا غيّرت المنصة لغتها البصرية لحقها تطبيقك حين يلحق بها Flutter. كما أن إدخال النص وإمكانية الوصول من تنفيذ الإطار نفسه، فاختبرهما بقارئات شاشة حقيقية.
الأداء
كلاهما سريع بما يكفي لأغلبية تطبيقات الأعمال: القوائم والنماذج والخرائط والدفع ولوحات المتابعة. يحوّل Flutter شيفرة Dart مسبقًا إلى شيفرة آلة في الإصدارات النهائية ويتحكم في كل إطار، فتأتي الحركة متسقة. ويشغّل React Native شيفرة JavaScript على محرك Hermes، وقد استبدلت بنيته الأحدث الجسر غير المتزامن القديم، فأزالت مصدرًا قديمًا للكلفة الإضافية.
وعمليًا، يأتي البطء في أي منهما من التطبيق نفسه في الغالب: قوائم طويلة لا تُحمَّل عند الحاجة، أو عمل ثقيل على الخيط الرئيسي، أو صور كبيرة الحجم. أما الألعاب والرسوميات اللحظية الثقيلة وخطوط الكاميرا المتقدمة والواقع المعزز فهي الحالات التي ننظر فيها إلى الشيفرة الأصلية الكاملة أو محرك ألعاب.
التكامل مع النظام والميزات الأصلية
يستطيع كلاهما استدعاء الشيفرة الأصلية: React Native عبر الوحدات الأصلية، وFlutter عبر قنوات المنصة وFFI. وللاحتياجات الشائعة، كالكاميرا والموقع والإشعارات والقياسات الحيوية والمشتريات داخل التطبيق، حزم جيدة الصيانة في الاثنين. أما الاحتياجات غير المعتادة، كميزة جديدة تمامًا في نظام التشغيل أو حزمة تطوير خاصة بمصرف، فقد تحتاج إلى طبقة وصل مكتوبة بـ Swift أو Kotlin. وأيًّا كان الإطار الذي تختاره، أبقِ في المشروع شخصًا يستطيع قراءة الشيفرة الأصلية.
المطورون والأدوات والاختبار
**التوظيف.** مجموعة مطوري JavaScript وReact أكبر، فيصبح فريق متمرس في React منتجًا في React Native أسرع. ومطورو Dart أقل عددًا، لكن لغتهم سريعة التعلم. افحص سوقك المحلية ولا تعتمد على ادعاءات عامة.
**الأدوات.** كلاهما يوفّر إعادة التحميل الفوري. ويأتي Flutter بعدة متكاملة: حزمة التطوير والمنسّق والمحلّل وأدوات DevTools. وتبدأ معظم مشاريع React Native الجديدة بـ Expo، الذي يتولى جزءًا كبيرًا من الإعداد الأصلي وعملية البناء.
**الاختبار.** يتضمن Flutter اختبارات الوحدات والعناصر والتكامل، إضافة إلى اختبارات اللقطات المرجعية التي تكشف التراجع البصري. وتستعمل فرق React Native عادة Jest ومكتبة React Native Testing Library للمكونات، وأداة مثل Detox أو Maestro للمسارات الكاملة. وفي الاثنين اختبر على أجهزة حقيقية، وعلى المنصتين، وبكلتا اللغتين.
التحديثات والصيانة على المدى الطويل
يصدر الإطاران إصدارات متكررة، ولا ترقية منهما مجانية. ففي React Native يعتمد الجهد على عدد المكتبات الأصلية التي تستخدمها، لأن كلًّا منها يجب أن يدعم الإصدار الجديد. وفي Flutter قد تتأخر الحزم الخارجية عن الإصدار الجديد. أبقِ الاعتماديات قليلة وجيدة الصيانة في الحالتين.
ويستطيع React Native نشر إصلاحات JavaScript دون مراجعة المتجر عبر خدمات تحديث مثل خدمة Expo، وضمن قواعد كل متجر. ولا يملك Flutter ما يعادل ذلك من تطويره هو، وإن وُجدت خدمات من جهات خارجية. وكلاهما تدعمه شركة كبرى ومجتمع مفتوح المصدر نشط، وكلاهما يحمل قدرًا من احتمال تغيّر الأولويات، فافصل منطق العمل عن طبقة الواجهة ليكون أي انتقال مستقبلي أرخص.
الدعم من اليمين إلى اليسار والعربية
كلاهما يدعم التخطيط من اليمين إلى اليسار والعربية دعمًا جيدًا. فعنصر Directionality وملحقات التوطين في Flutter تقلب التخطيط عند تغيّر اللغة، وصيغ البداية والنهاية في الهوامش والمحاذاة تُبقي التخطيط واعيًا بالاتجاه. أما React Native فيتبع اتجاه النظام عبر I18nManager ويدعم خصائص البداية والنهاية في الأنماط، لكن فرض الاتجاه أثناء التشغيل يحتاج عادة إلى إعادة تحميل التطبيق، وهذا يهمّ إن كان المستخدم يبدّل اللغة من داخل التطبيق.
وفي الإطارين اختبر النص المختلط (عربي مع أسماء لاتينية وأرقام)، والأيقونات المعكوسة، ومؤشر حقول النص وتحديدها، والخطوط العربية وارتفاع السطر، وصيغ التاريخ والأرقام. وللقائمة الأوسع راجع مقال [تصميم المنتجات ثنائية اللغة](/blog/designing-bilingual-rtl-products).
اعتبارات الأمان
لا يجعل أي من الإطارين التطبيق آمنًا أو غير آمن بذاته. المهم واحد في الاثنين: أبقِ الأسرار خارج الجهاز، فكل ما يُضمَّن في التطبيق يمكن استخراجه؛ وخزّن الرموز في Keychain أو Keystore عبر حزمة جيدة الصيانة؛ واستخدم تثبيت الشهادات حيث تبرر المخاطر ذلك؛ وراجع الاعتماديات وافحصها دائمًا.
حزمة JavaScript، حتى لو صُرّفت إلى شيفرة Hermes الثنائية، يمكن فحصها. وإصدارات Dart النهائية تُصرَّف إلى شيفرة أصلية ويمكن تعتيمها، وهذا يرفع جهد من يحاول الهندسة العكسية للتطبيق لكنه ليس حماية. وضخامة منظومة npm تعني تعرضًا أكبر لمخاطر سلسلة التوريد ينبغي إدارته، أما pub.dev فأصغر لكنها ليست محصّنة. ونهجنا في ذلك في دليل [تطوير التطبيقات الآمنة](/guides/secure-app-development).
المقارنة جنبًا إلى جنب
| الموضوع | React Native | Flutter |
|---|---|---|
| اللغة | JavaScript أو TypeScript مع React | Dart |
| الواجهة | عناصر المنصة الأصلية | محرك رسم خاص به |
| الشكل والإحساس | يتبع كل منصة تلقائيًا | متطابق افتراضيًا، ويُعاد إنتاج شكل المنصة |
| الأداء | جيد لتطبيقات الأعمال، مع الانتباه للعمل على الخيط الرئيسي | حركة متسقة، وجيد لتطبيقات الأعمال |
| الشيفرة الأصلية | وحدات أصلية بـ Swift أو Kotlin | قنوات المنصة وFFI |
| المشاركة مع ويب React | قوية: الأنواع والمنطق وعملاء الواجهات | قليلة، فالعدة منفصلة |
| التوظيف | مجموعة كبيرة من مطوري JavaScript وReact | مجموعة أصغر وتعلّم سريع |
| التحديث دون مراجعة المتجر | ممكن لتغييرات JavaScript، ضمن قواعد المتجر | عبر خدمات خارجية فقط |
| من اليمين إلى اليسار | مدعوم، وتغيير الاتجاه أثناء التشغيل يحتاج غالبًا إلى إعادة تحميل | مدعوم، ويتبع اللغة أثناء التشغيل |
| منصات أخرى | الجوال أولًا، والويب بأدوات إضافية | الجوال والويب وسطح المكتب في إطار واحد |
متى نختار كل واحد
- الفريق أو العميل يعمل أصلًا بـ React وTypeScript.
- هناك منتج ويب يمكن للتطبيق أن يشاركه المنطق والأنواع.
- الإحساس الأصلي الذي يتبع المنصة أهم من تطابق الشاشات نقطةً بنقطة.
- إصلاح الأخطاء دون انتظار مراجعة المتجر ذو قيمة.
- واجهة مخصصة يقودها الإطار البصري للعلامة يجب أن تتطابق على المنصتين.
- التطبيق يعتمد على حركة غنية أو رسم مخصص.
- لا يوجد فريق JavaScript قائم يمكن البناء عليه.
- قد تحتاج لاحقًا إلى سطح المكتب أو الويب من المنظومة نفسها.
إن اعتمد المنتج على ميزات عميقة في المنصة أو على أفضل أداء ممكن، فقد تكون شيفرة Swift وKotlin الأصلية هي الجواب. ويشرح مقال [أصلي أم متعدد المنصات](/blog/native-or-cross-platform) ومدخل [التطبيق متعدد المنصات](/glossary/cross-platform-app) في المسرد هذا الاختيار.