نتيجة لازدياد شعبية الهواتف الذكية وتطبيقات الهاتف المحمول كان مطورو الويب يبحثون عن طرق لإنشاء تطبيقات الهاتف المحمول باستخدام JavaScript. أدى هذا الطلب المتزايد إلى تطوير العديد من أطر عمل JavaScript القادرة على تشغيل تطبيقات شبيهة بالتطبيقات الأصلية على الأجهزة المحمولة. في هذه المقالة يقارن يوهانس شتاين مهندس برمجيات Toptal المستقل بين الخيارين الأكثر شيوعًا حاليًا لأطر عمل JavaScript الموجهة للجوال وهما Cordova و React Native. من خلال فحص مزاياها ومخاطرها يتعمق في تفاصيل كل منها ويقارنها عبر التخصصات المختلفة.

الاختلافات في الفلسفة

من المهم أن تتذكر أن شعار React Native “تعلم مرة واحدة واكتب في أي مكان” يختلف عن الشعار المعتاد عبر الأنظمة الأساسية “اكتب مرة واحدة ابدأ في أي مكان”. يؤدي هذا إلى شيئين: أولاً لا يمكننا فقط أخذ قاعدة أكواد React الحالية من مشروع الويب الخاص بنا وتحويلها إلى تطبيق جوال ببضع نقرات فقط. ومع ذلك فإن React و React Native يشتركان بالفعل في الكثير من المفاهيم الأساسية مع أحد الأمثلة على الأنظمة المكونة لهما ونتيجة لذلك يبدو React Native مألوفًا على الفور. بينما تشترك React في الكثير من أوجه التشابه مع React Native إلا أن هناك بعض الاختلافات الجوهرية والتي تتراوح من طريقة التعامل مع أوراق الأنماط إلى نوع المكونات التي يمكننا استخدامها.

ثانيًا قد نجد أنفسنا غير قادرين على مشاركة كود React Native عند استهداف منصات مختلفة. يحدث هذا عندما نفضل أن تتصرف عناصر واجهة المستخدم بشكل أصلي مع نظامها الأساسي المحدد مما يمنح المستخدم بدوره تجربة أفضل وشعورًا أصليًا بالتطبيق. مثال واضح على ذلك هو القائمة الجانبية للدرج في تطبيقات Android وهو أمر غير شائع جدًا في تطبيقات iOS.

قرطبة لا تشارك هذه الفلسفة. ليس من غير المألوف البدء في تطوير تطبيق ويب خالص ثم تجميعه لاحقًا كتطبيق كوردوفا وإعادة استخدام أكبر قدر ممكن من التعليمات البرمجية لجميع الأنظمة الأساسية (المحمولة) التي نريد استهدافها.

حرية التنمية

على الأجهزة المحمولة تقوم كوردوفا بتشغيل تطبيق من صفحة واحدة داخل متصفح الويب المدمج للهاتف المحمول يسمى WebView ثم يقوم بتغليفه كتطبيق أصلي. بينما يبدو أنه تطبيق أصلي من الخارج يعمل كود الويب الخاص بنا داخل محرك متصفح الجوال. بالنسبة لنا هذا يعني أننا لسنا مقيدين بمكتبة أو إطار عمل معين. إذا كنا نستخدم Vanilla JavaScript أو jQuery أو Angular أو أي شيء آخر فيمكن تجميع أي من هذه الخيارات في تطبيق جوال مع Cordova. كوردوفا لا تفرض على كومة التكنولوجيا لدينا. طالما لدينا ملف index.html فنحن على أتم الاستعداد. أحد الأمثلة البسيطة هو مقتطف الشفرة التالي:

<html>
  <head>
    <title>My Cordova App</title>
  </head>
  <body>
    <div id="tapme">Tap me</div>
    <script>
      // Select our element
      var element = document.getElementById('tapme');
      
      // Send an alert once it was tapped/clicked
      element.addEventListener('click', function() {
        alert('Hello there!');
      });
    </script>
  </body>
</html>

يعني هذا المثال أنه يمكننا استخدام أي شيء نرغب فيه إلى حد كبير مثل استخدام مدير الحزم مثل NPM أو Bower أو استخدام محول مثل Babel أو CoffeeScript أو TypeScript أو مجمع مثل Webpack أو Rollup أو أي شيء آخر تمامًا. لا يهم طالما أن النتيجة هي ملف index.html يقوم بتحميل جميع جافا سكريبت وأوراق الأنماط التي نحتاجها.

React Native كما يوحي الاسم يبني على React. من المهم أن نفهم أن جزء React في React Native هو أحد ميزاته الأساسية. إذا لم تكن من محبي الطبيعة التصريحية لـ React بما في ذلك JSX وتكوينها وتدفق البيانات فمن المحتمل أنك لن تكون سعيدًا بـ React Native. في حين أن React Native يشعر على الفور بأنه مألوف لمطوري React للوهلة الأولى هناك بعض الاختلافات التي يجب تذكرها. مع React Native ليس لدينا أي HTML أو CSS. بدلاً من ذلك تركز هذه التقنية على جانب JavaScript. كبديل لـ CSS تتم كتابة الأنماط مضمنة و Flexbox هو نموذج التصميم الافتراضي.

سيبدو التطبيق الأكثر مجردة من React Native مشابهًا لهذا المثال:

// Import the React module for JSX conversion
import { React } from 'react';
// Import React Native's components
import {
  View,
  Text,
  AppRegistry,
  TouchableOpacity,
} from 'react-native';

// Create an App component
const App = () => {
  // Define our press handler
  const onPress = () => alert('Hello there!');
  
  // Compose the components we are going to render
  return (
    <View>
      <TouchableOpacity onPress={onPress} />
        <Text>Tap me!</Text>
      </TouchableOpacity>
    </View>
  );
};

// Registers the `App` component as our main entry point
AppRegistry.registerComponent('App', () => App);

لدى React Native أداة حزم خاصة بها. يقوم بتجميع جميع ملفات JavaScript في ملف عملاق واحد والذي يتم استهلاكه وتنفيذه بواسطة JavaScriptCore محرك JavaScript من Apple. يتم استخدام JavaScriptCore على iOS و Android بينما تشغل ChakraCore تطبيقات React Native UWP. بشكل افتراضي يستخدم React Native مترجم JavaScript Babel مما يسمح لنا باستخدام صيغة ECMAScript 2015+ (ECMAScript 6). على الرغم من أنه ليس من الضروري استخدام بنية ECMAScript 2015+  إلا أنه يتم تشجيعها بالتأكيد حيث أن جميع الأمثلة الرسمية ووحدات الطرف الثالث تتبناها. نظرًا لأن React Native تهتم بعملية التغليف والترحيل يمكن أن تستفيد كود التطبيق ووحدات الطرف الثالث من هذه الميزات دون الحاجة إلى تكوين الأدوات لأنفسنا.

باختصار يُعد React Native منهجًا متمحورًا حول رد الفعل لتطوير الأجهزة المحمولة بينما يسمح لنا كوردوفا بتجميع تقنيات الويب داخل غلاف WebView.

شكل ومظهر Native

الشيء الوحيد المهم للمستخدمين هو أن يكون لديهم شكل وأسلوب Native للتطبيق. نظرًا لأن تطبيقات كوردوفا عادةً ما تكون تطبيقات ويب بسيطة فهناك بعض الأشياء التي قد تبدو غريبة في البداية. قد تتراوح المشاكل من الملاحظات المرئية المفقودة على مناطق النقر إلى التمرير الذي لا يبدو سلسًا كالحرير كما هو الحال في التطبيقات الأصلية إلى وجود تأخير 300 مللي ثانية في أحداث النقر. على الرغم من وجود حلول لجميع هذه المشكلات يجب أن نتذكر أننا قد نحتاج إلى بذل بعض الجهد الإضافي إذا أردنا أن يشعر تطبيق كوردوفا بأنه قريب من التطبيقات المحلية قدر الإمكان. في كوردوفا لا يمكننا الوصول إلى أي عناصر تحكم Native. إذا أردنا الحصول على مظهر Native فلدينا خياران: إما إعادة إنشاء عناصر تحكم Native مثل الأزرار وعناصر الإدخال باستخدام HTML و CSS أو تنفيذ الوحدات الأصلية التي تصل مباشرةً إلى عناصر التحكم الأصلية. يمكننا القيام بذلك بأنفسنا أو باستخدام مكتبة تابعة لجهة خارجية مثل Ionic أو Onsen UI. لاحظ أنه من المهم إبقائهم على اطلاع دائم بتحديثات نظام التشغيل فور ظهورها. في بعض الأحيان تحسين مظهر نظام التشغيل المحمول كما حدث عندما تم تقديم iOS 7. سيؤدي وجود تطبيق غير قادر على تكييفه إلى إخراج المستخدمين من التجربة. يمكننا أيضًا اللجوء إلى تضمين مكونات كوردوفا الإضافية التي تربطنا بالجانب الأصلي للأشياء. تعد مكتبة Ace من Microsoft واحدة من عناصر التحكم الأصلية الأكثر اكتمالا.

مع React Native من ناحية أخرى لدينا إمكانية الوصول إلى عناصر التحكم الأصلية والتفاعل خارج الصندوق. يتم تعيين مكونات مثل Text أو TextInput أو Slider إلى نظيراتها الأصلية. بينما تتوفر بعض المكونات لجميع الأنظمة الأساسية تعمل المكونات الأخرى فقط على أنظمة أساسية محددة. كلما اقتربنا من أن يكون لتطبيقنا مظهر وشعور أصليان زادت حاجتنا إلى استخدام المكونات المتوفرة فقط لهذا النظام الأساسي المحدد وبالتالي كلما تباعدت قاعدة التعليمات البرمجية الخاصة بنا. تعد تفاعلات اللمس والإيماءات جزءًا من React Native أيضًا.

مقارنة الأداء بین React Native  وCordova

نظرًا لأن كوردوفا ليس لديها سوى WebView تحت تصرفها فنحن ملزمون بقيود WebView. على سبيل المثال بعد إصدار 4.0 بدأ Android أخيرًا في استخدام محرك Chrome  (الأسرع بكثير) باعتباره WebView الافتراضي. أثناء استخدام iOS كان التطبيق الذي يعمل داخل محرك WebView الافتراضي أبطأ بشكل ملحوظ من نفس التطبيق في متصفح Safari للجوال لفترة طويلة. علاوة على ذلك نظرًا لأن JavaScript عبارة عن سلسلة واحدة فقد نواجه مشكلات إذا كان هناك الكثير من الأشياء التي تحدث في كود التطبيق الخاص بنا. تؤدي هذه القيود إلى رسوم متحركة بطيئة وقد لا يشعر تطبيقنا بالاستجابة كما نود أن يكون. بينما قد تكون هناك بعض الحيل التي يمكننا استخدامها هنا وهناك في النهاية نحن ملزمون بحدود متصفح الجوال.

تستخدم React Native سلاسل رسائل متعددة وبالتالي يتم تشغيل عناصر واجهة المستخدم في سلسلة المحادثات الخاصة بها. نظرًا لأن مكونات React ترتبط بالعروض الأصلية فإن JavaScript لا يقوم بالمهمة الصعبة في React Native.

سير عمل مطور React Native وCordova

تقدم Cordova أداة مساعدة لسطر الأوامر لإنشاء قوالب مشروع جديدة وبدء التطبيق في المحاكي وبناء التطبيق للجهاز الفعلي في وضع الإنتاج. في معظم الأحيان نقوم بتطوير التطبيق على مستعرض سطح المكتب وقد نجمعه لاحقًا كتطبيق للهاتف المحمول. مع الحرية التي توفرها كوردوفا نحتاج إلى معالجة سير عمل التطوير بأنفسنا. إذا أردنا إعادة التحميل المباشر على الجهاز فنحن بحاجة إلى تنفيذه بأنفسنا. لتصحيح أخطاء تطبيقات كوردوفا نطبق نفس المبادئ المستخدمة لتصحيح أخطاء موقع الويب. في نظام iOS على سبيل المثال سنقوم بتوصيل أجهزتنا المحمولة عبر USB وفتح Safari وأدوات المطور الخاصة به.

تقدم React Native واجهة سطر أوامر مماثلة وتقدم سير عمل تطوير مألوفًا لمطوري الويب. نحصل على إعادة شحن مباشرة من خارج منطقة الجزاء. بمجرد تغيير مكون React يتم إعادة تحميل تطبيقنا بالتغييرات التي أجريناها. إحدى أكثر الميزات إثارة هي استبدال الوحدة النمطية الساخنة والتي تعيد جزئيًا تحميل التغييرات في المكون الذي قمنا به دون تغيير حالة التطبيق. يمكننا حتى الاتصال بجهاز حقيقي ومعرفة ما إذا كانت التغييرات التي أجريناها تعمل كما نتوقعها على جهاز حقيقي. يمكن تصحيح أخطاء تطبيقات React Native الخاصة بنا عن بُعد باستخدام Chrome لسطح المكتب. معالجة الخطأ واضحة في React Native؛ إذا واجهنا خطأ فإن تطبيقنا يعرض خلفية حمراء ويظهر تتبع المكدس. بفضل خرائط المصادر يمكننا رؤية موقع الخطأ بالضبط. عندما نضغط عليها يفتح محررنا المفضل في الموقع الدقيق للرمز.

قابلية التوسعة والوصول إلى الميزات الأصلية

من جانب JavaScript للأشياء نحن أحرار في استخدام أي مكتبة JavaScript بما في ذلك الحزم من NPM. ومع ذلك نظرًا لأن React Native ليست بيئة متصفح فقد نجد صعوبة في استخدام التعليمات البرمجية التي تعتمد على DOM. تضم React Native وحدتي CommonJS و ES2015 لذلك يسهل دمج أي مكتبات تستخدم هذه التنسيقات.

يمتلك كل من Cordova و React Native القدرة على إنشاء واستخدام المكونات الإضافية التي تتصل بالجانب الأصلي للأشياء. يوفر Cordova واجهة برمجة تطبيقات منخفضة المستوى لإنشاء واجهتنا الخاصة والتي تمنحنا قدرًا كبيرًا من التحكم ولكنها تؤدي إلى استخدام المزيد من النماذج المعيارية الأصلية وجافا سكريبت.

إذا كان علينا أن نكتب افتراضيًا مكونًا إضافيًا لـ Cordova iOS في Objective-C فقد يبدو مثل مقتطف الشفرة التالي. سيقوم المكون الإضافي الخاص بنا بتسجيل معلمة الإدخال فقط.

#import <Cordova/CDVPlugin.h>

// Create a class that inherits from CDVPlugin
@interface Log : CDVPlugin
- (void)log:(CDVInvokedUrlCommand*)command;
@end

// The actual implementation of the class we just defined
@implementation Log

- (void)log:(CDVInvokedUrlCommand*)command
{
    CDVPluginResult* pluginResult = nil;
    
    // We are getting all parameters and taking the first one
    NSString* echo = [command.arguments objectAtIndex:0];

    // We are checking for the validity of the parameters
    if (echo != nil && [echo length] > 0) {
        // We are just printing the parameter using the native log method
        NSLog(echo);
      
        // Let's create a result for the plugin
        pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:echo];
    }

    // Let's send a signal back with the plugin's result
    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

@end

من أجل استخدام الوحدة سيساعد هذا الجزء من كود JavaScript في:

window.log = function(str, callback) {
    cordova.exec(callback, function(err) {
        callback('Nothing to echo.');
    }, "Log", "log", [str]);
};

لاستخدام المكون الإضافي نحتاج فقط إلى استدعاء وظيفة السجل:

window.log('Hello native!');

من ناحية أخرى تتبع React Native فلسفة مختلفة يقوم تلقائيًا بتعيين أنواع JavaScript إلى نظيراتها الأصلية عند كتابة المكونات الإضافية مما يسهل توصيل التعليمات البرمجية الأصلية بجافا سكريبت. دعنا نلقي نظرة على جزء من التعليمات البرمجية الضرورية لإنشاء وحدة أصلية باستخدام React Native:

#import "RCTBridgeModule.h"

@interface Log : NSObject <RCTBridgeModule>
@end

@implementation Log

RCT_EXPORT_MODULE();

// This makes this method available NativeModules.Log.log
RCT_EXPORT_METHOD(log:(NSString *)message)
{
  NSLog(message);
}
@end

React Native يربط الوحدة بالنسبة لنا باستدعاءات RCT_EXPORT_MODULE و  RCT_EXPORT_METHOD. يمكننا الآن الوصول إليه باستخدام NativeModules.Log.log على النحو التالي:

import { React } from 'react';
import {
  View,
  Text,
  AppRegistry,
  NativeModules
  TouchableOpacity,
} from 'react-native';

// Create an App component
const App = () => {
  // Log with our module once we tap the text
  const onPress = () => NativeModules.Log.log('Hello there');
  
  return (
    <View>
      <TouchableOpacity onPress={onPress} />
        <Text>Tap me!</Text>
      </TouchableOpacity>
    </View>
  );
};

// Registers the `App` component as our main entry point
AppRegistry.registerComponent('App', () => App);

بينما ألقينا نظرة فاحصة فقط على إنشاء وحدة نمطية في iOS باستخدام Objective-C تنطبق نفس المبادئ على إنشاء وحدة لنظام Android باستخدام Java.

نحتاج إلى ربط المكونات الإضافية الأصلية داخل ملفات المشروع لكل منصة. مع نظام التشغيل iOS على سبيل المثال هذا يعني أنه يجب علينا ربط الجزء الأصلي المترجم بتطبيقنا وإضافة ملفات الرأس المقابلة. يمكن أن تكون هذه عملية طويلة خاصة إذا كان هناك الكثير من الوحدات الأصلية. لحسن الحظ تم تبسيط ذلك بشكل كبير باستخدام أداة سطر أوامر تسمى rnpm والتي أصبحت جزءًا من React Native نفسها.

الخلاصة: React Native أم Cordova؟

لكل من React Native و Cordova أغراض مختلفة ولذلك فهي تلبي الاحتياجات المختلفة. لذلك من الصعب القول إن إحدى التقنيات أفضل من الأخرى في جميع التخصصات.

باستخدام كوردوفا يمكنك تحويل تطبيق الصفحة الواحدة الحالي الخاص بك بسرعة إلى تطبيق جوال لمنصات مختلفة على حساب التفاعلات التي ليس بالضرورة أن يكون لها الشعور الأصلي لمنصتها المحددة.

باستخدام React Native تتمتع التطبيقات بمظهر وإحساس أكثر أصالة ولكن على حساب إعادة تنفيذ أجزاء من التعليمات البرمجية لبعض الأنظمة الأساسية المستهدفة. إذا كنت قد انخرطت بالفعل في React وكنت مهتمًا بتطوير تطبيقات الهاتف المحمول فإن React Native تبدو امتدادًا طبيعيًا.

للمزيد اقرأ: أفضل أدوات إدارة حالة React لتطبيقات المؤسسة

منشور ذات صلة
لغة C 6 Minutes

قوة لغة البرمجة C

جاسم ناظري

لغة C هي لغة تجميع محمولة تقريبًا. إنه قريب من الجهاز قدر الإمكان بينما يكون متاحًا عالميًا تقريبًا لهياكل المعالجات الحالية. يوجد مترجم C واحد على الأقل لكل معمارية موجودة تقريبًا.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

السلة