دمج واجهات React Native مع تطبيقات أصيلة قائمة
إطار العمل React Native رائعٌ لبرمجة تطبيق جوال جديد من البداية. لكن، يُمكنك كذلك استخدامه لإضافة واجهة (view) واحدة أو ميّزة إلى التطبيقات الأصيلة الموجودة بالفعل. يمكنك باتّباع بضعة خطواتٍ إضافةُ ميّزات جديدة باستخدام React Native إلى تطبيقك، مثل شاشات (screens) جديدة، وأقسام واجهات، ...إلخ.
تختلف الخطوات حسب النظام الأساسي الذي تستهدفه:
- الدمج مع تطبيقات Android قائمة مكتوبة بلغة Java
- الدمج مع تطبيقات iOS قائمة مكتوبة بلغة Objective-C
- الدمج مع تطبيقات iOS قائمة مكتوبة بلغة Swift
الدمج مع تطبيقات Android قائمة مكتوبة بلغة Java
المفاهيم الرئيسية
أهمّ الأمور لدمج مكونات React Native في تطبيق Android الخاص بك هي:
- إعداد اعتماديات (dependencies) إطار العمل React Native وهيكل المجلّدات (directory structure).
- كتابة مكونات React Native باستخدام JavaScript.
- إضافة واجهة
ReactRootView
إلى تطبيق Android الخاص بك. ستكون هذه الواجهة بمثابة الحاوية لمكون React Native الخاص بك. - بدء تشغيل خادم React Native وتشغيل التطبيق الأصيل.
- تحقّق من أن جانب React Native من التطبيق الخاص بك يعمل كما هو متوقع.
المتطلبات الأساسية
اتبع إرشادات بناء مشاريعٍ بشيفرة أصيلة في الدرس التقديمي لتهيئة بيئة التطوير الخاصة بك لإنشاء تطبيقات React Native لنظام التشغيل Android.
1. إعداد بنية المجلدات (directory structure)
لتسهيل العمل، أنشئ مجلدًا جديدًا لمشروع React Native المُدمَج الخاص بك، ثم انسخ مشروع Android الحالي إلى مجلد فرعي باسم /android
.
2. تثبيت اعتماديات JavaScript
انتقل إلى المجلّد الجذر (root directory) للمشروع الخاص بك وأنشئ ملف package.json
جديد بالمحتويات التالية:
{
"name": "MyReactNativeApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "yarn react-native start"
}
}
بعد ذلك، تأكّد من تثبيت مدير الحزم Yarn.
ثبّت حزمتي react
وreact-native
. افتح طرفيّةً (terminal) أو مَحثَّ أوامر (command prompt)، ثم انتقل إلى المجلّد الذي يحتوي على ملف package.json
ونفّذ الأمر التالي:
$ yarn add react-native
سيؤدي هذا إلى طباعة رسالةٍ مشابهة لما يلي (مرِّر لأعلى مُخرجات yarn
لمشاهدتها):
warning "react-native@0.52.2" has unmet peer dependency "react@16.2.0".
هذا يعني أنّنا بحاجة إلى تثبيت React كذلك:
$ yarn add react@version_printed_above
ضع مكان version_printed_above الإصدار المذكور في رسالة التحذير التي ظهرت لك آنفًا ضمن "react@16.2.0".
أنشأَ Yarn مجلدَ /node_modules
جديد. يخزّن هذا المجلد جميع اعتماديات JavaScript المطلوبة لإنشاء مشروعك.
أضف node_modules/
إلى ملفّ .gitignore
الخاص بك.
إضافة React Native إلى تطبيقك
إعداد maven
أضف اعتماديّة React Native إلى ملفّ build.gradle
الخاص بتطبيقك:
dependencies {
implementation "com.android.support:appcompat-v7:27.1.1"
...
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "org.webkit:android-jsc:+"
}
ملاحظة: إذا أردت التأكد من استعمال نسخة معينة من React Native على الدوام في بناء تطبيقك الأصيل، فاستبدل +
بنسخة React Native التي نزّلتها من npm
.
أضف خانةً إلى مجلّد maven الخاص بإطار React Native إلى ملفّ build.gradle
. تأكد من إضافته إلى كتلة "allprojects"، فوق مستودعات maven الأخرى:
allprojects {
repositories {
maven {
// All of React Native (JS, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
...
}
...
}
ملاحظة: تأكّد من أن المسار صحيح! لا ينبغي أن تواجهك أية أخطاء من قبيل Failed to resolve: com.facebook.react:react-native:0.x.x بعد تشغيل مزامنة Gradle في Android Studio.
تفعيل الربط التلقائي للوحدات الأصيلة
للاستفادة من قوة الربط التلقائي autolinking يجب أن نطبقه في عدة مواضع، أولًا أضف المدخل التالي إلى settings.gradle
:
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
ثم أضف المدخل التالي إلى أسفل app/build.gradle
:
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
إعداد الأذونات (permissions)
بعد ذلك، تأكد من تفعيل إذن الإنترنت في ملفّ AndroidManifest.xml
:
<uses-permission android:name="android.permission.INTERNET" />
إذا كنت بحاجة إلى الوصول إلى نشاط DevSettingsActivity
، فأضف السطر التالي إلى AndroidManifest.xml
:
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
يُستخدَم هذا فقط في وضع التطوير (dev mode) عند إعادة تحميل JavaScript من خادم التطوير، لذا يمكنك إزالته في بناءات الإصدار (release builds) إذا كنت بحاجة إلى ذلك.
مرور النصوص الواضحة (مستويات الواجهة البرمجية الأعلى من 28)
بدءًا من Android 9 (مستوى API 28)، يُعطَّل مرور النصوص الواضحة (cleartext traffic) بشكل افتراضي؛ يمنع هذا تطبيقك من الاتصال بالمجمّع Metro. التغييرات أدناه تسمح بمرور النصوص الواضحة في بناءات التنقيح (debug builds).
أضف خيار usesCleartextTraffic
إلى Debug AndroidManifest.xml
الخاص بك:
<!-- ... -->
<application
android:usesCleartextTraffic="true" tools:targetApi="28" >
<!-- ... -->
</application>
<!-- ... -->
هذا غير مطلوب لبناءات الإصدار (Release builds).
لمعرفة المزيد حول ضبط أمان الشبكة (Network Security Config) وسياسة مرور النصوص الواضحة (cleartext traffic policy)، راجع هذا الرابط.
دمج الشيفرة
سنُعدّل الآن تطبيق Android الأصيل لدمج React Native معه.
مكون React Native
الجزء الأول من الشيفرة التي سنكتبها هي شيفرة React Native لشاشة "Hello World" الجديدة التي سندمجها في تطبيقنا.
1. إنشاء ملف index.js
أولاً، أنشئ ملفّ index.js
فارغ في جذر مشروع React Native الخاص بك.
ملفّ index.js
هو نقطة البداية لتطبيقات React Native، وهو ضروري دائمًا. يمكن أن يكون ملفًا صغيرًا يطلب (يستورد require
) ملفًا آخر يمثّل جزءًا من مكوّن أو تطبيق React Native الخاص بك، أو يمكن أن يحتوي على كامل الشيفرة البرمجية اللازمة لذلك. في حالتنا، سنضع كامل الشيفرة في ملفّ index.js
.
2. أضف شيفرة React Native الخاصة بك
أنشئ المكوّن في ملفّ index.js
الخاص بك. في نموذجنا هنا، سنضيف مكون <Text>
بسيط داخل مكوّن <View>
مُنسَّق:
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
const HelloWorld = () => {
return (
<View style={styles.container}>
<Text style={styles.hello}>Hello, World</Text>
</View>
);
};
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center'
},
hello: {
fontSize: 20,
textAlign: 'center',
margin: 10
}
});
AppRegistry.registerComponent(
'MyReactNativeApp',
() => HelloWorld
);
3. ضبط الأذونات لشاشة رسائل أخطاء التطوير
إذا كان تطبيقك يستهدف واجهة Android البرمجيّة من المستوى 23 أو أكثر، فتأكد من تمكين إذن android.permission.SYSTEM_ALERT_WINDOW
لبناء التطوير (development build). يمكنك التحقق من ذلك باستخدام Settings.canDrawOverlays(this);
. هذا مطلوب في بناءات التطوير لأنّه من الواجب عرض أخطاء تطوير React Native فوق كل النوافذ الأخرى. نظرًا لنظام الأذونات الجديد الذي قُدِّم في المستوى 23 من الواجهة البرمجيّة (Android M)، فلا بدّ للمستخدم أن يُوافق على عرض شاشة فوق جميع الشاشات الأخرى. يمكن تفعيل الإذن عن طريق إضافة الشيفرة التالية إلى النشاط (Activity) في التابع onCreate()
.
private final int OVERLAY_PERMISSION_REQ_CODE = 1; // اختر أي قيمة
...
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
}
}
أخيرًا، يجب إعادة تعريف (override) التابع onActivityResult()
(كما هو موضح في الشيفرة أدناه) للتعامل مع حالتي قبول الإذن أو رفضه لتجربة مستخدم متجانسة. إضافةً إلى ذلك، لدمج الوحدات النمطية الأصيلة التي تستخدم startActivityForResult
، نحتاج إلى تمرير النتيجة إلى التابع onActivityResult
الخاص بنسخة ReactInstanceManager
الخاصة بنا.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
// SYSTEM_ALERT_WINDOW إذن غير معطى
}
}
}
mReactInstanceManager.onActivityResult( this, requestCode, resultCode, data );
}
الرابط العجيب: ReactRootView
لنُضِف شيفرةً أصيلة لبدء مشغل React Native الآني (React Native runtime) ولنجعَله يُصيِّر مكوّن JavaScript الخاص بنا. للقيام بهذا، سنُنشئ نشاطًا Activity
ليُنشئ واجهة ReactRootView
، ويبدأ تطبيق React بداخله مع ضبطه كواجهة رئيسيّة للمحتوى.
ملاحظة: إذا كنت تستهدف نسخ Android الأقدم من النسخة 5، فاستعمل صنف AppCompatActivity
من حزمة com.android.support:appcompat
عوضًا عن Activity
.
public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler {
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SoLoader.init(this, false);
mReactRootView = new ReactRootView(this);
List<ReactPackage> packages = new PackageList(getApplication()).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
// Remember to include them in `settings.gradle` and `app/build.gradle` too.
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setCurrentActivity(this)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index")
.addPackages(packages)
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
// السلسلة النصيّة ("MyReactNativeApp")
// يجب أن تُطابق السلسلة النصيّة الموجودة في
// AppRegistry.registerComponent() في index.js
mReactRootView.startReactApplication(mReactInstanceManager, "MyReactNativeApp", null);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
}
ملاحظة: إذا كنت تستخدم حزمةَ بدايةٍ مساعدة (starter kit) للعمل مع React Native، فاستبدل السلسلة النصيّة "HelloWorld"
بتلك الموجودة في ملفّ index.js
الخاص بك (وهي المعامل الأول للتابع AppRegistry.registerComponent()
).
نفذ العملية "Sync Project files with Gradle".
إذا كنت تستخدم Android Studio، فاستخدم Alt + Enter
لإضافة جميع الاستيرادات المفقودة في صنف MyReactActivity. كن حريصًا على استخدام إعداد BuildConfig
الخاص بحزمتك وليس الحزمة الموجودة في حزمة facebook
.
ينبغي تعيين السمة Theme
التي تخص MyReactActivity
لتكون Theme.AppCompat.Light.NoActionBar
لأن بعض مكونات واجهة مستخدم React Native تعتمد على هذه السمة.
<activity
android:name=".MyReactActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
</activity>
ملاحظة: يمكن مشاركة ReactInstanceManager
من طرف عدّة أنشطة أو أجزاء (fragments) متعددة. عليك إنشاء ReactFragment
أو ReactActivity
خاصّة بك ويجب أن يكونَ لديك حامل مفرد (singleton holder) يحمل ReactInstanceManager
. عندما تحتاج ReactInstanceManager
(على سبيل المثال، لتوصيل ReactInstanceManager
بدورة حياة تلك الأنشطة أو الأجزاء) فاستخدم تلك التي يوفّرها المفرد.
بعد ذلك، نحتاج إلى تمرير بعض من دوال رد النداء لدورة حياة النشاط (activity lifecycle callbacks) إلى ReactInstanceManager
و ReactRootView
:
@Override
protected void onPause() {
super.onPause();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause(this);
}
}
@Override
protected void onResume() {
super.onResume();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this, this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostDestroy(this);
}
if (mReactRootView != null) {
mReactRootView.unmountReactApplication();
}
}
نحتاج كذلك إلى تمرير أحداث زر الرجوع إلى React Native:
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
يسمح هذا للغة JavaScript بالتحكم في ما يحدث عندما يضغط المستخدم على زر رجوع الجهاز (لتنفيذ عملية التنقل [navigation] على سبيل المثال). عندما لا تُعالج JavaScript الضغط على زر الرجوع، سيُستدعى تابع invokeDefaultOnBackPressed
الخاص بك. افتراضيًّا، يُنهي هذا نشاطَك (Activity
) ببساطة.
وأخيرا، علينا ربط قائمة التطوير (dev menu). افتراضيًًا، تُفعَّل القائمة عبر هز الجهاز، ولكن هذا ليس مفيدًا في برامج المحاكاة. لذلك سنجعلها تظهر عندما تضغط على زر القائمة في الجهاز hardware menu button (استخدم Ctrl + M
إذا كنت تستخدم محاكي Android Studio):
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
}
نشاطك جاهز الآن لتشغيل شيفرة JavaScript.
اختبار الدمج
انتهيت الآن من جميع الخطوات الأساسية لدمج React Native مع تطبيقك الحالي. سنبدأ الآن بتشغيل مُحزّم React Native لإنشاء حزمة index.bundle
والخادم الذي سيعمل على المضيف المحلي localhost
.
1. تشغيل المُحزّم
لتشغيل تطبيقك، عليك أولاً تشغيل خادم التطوير (development server) عبر تنفيذ الأمر التالي من المجلّد الجذر لمشروع React Native الخاص بك:
$ yarn start
2. تشغيل التطبيق
يمكنك الآن بناء تطبيقك كأيّ تطبيق Android آخر وتشغيله كالمعتاد.
بمجرد الوصول إلى نشاطك القائم على React داخل التطبيق، من المفترض أن تُحمَّل شيفرة JavaScript من خادم التطوير مع عرض الشاشة التالية:
إنشاء بناء إصدار (release build) في Android Studio
يمكنك استخدام Android Studio لإنشاء بناءات الإصدار أيضًا! كل ما عليك فعله هو إنشاء بناءات الإصدار من تطبيق Android الأصيل الموجود مسبقًا. هناك خطوة إضافية واحدة فقط، والتي يجب عليك القيام بها قبل كل بناء إصدار. تحتاج إلى تنفيذ ما يلي لإنشاء حزمة React Native، والتي ستُضمَّن مع تطبيق Android الأصيل الخاص بك:
$ npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/com/your-company-name/app-package-name/src/main/assets/index.android.bundle --assets-dest android/com/your-company-name/app-package-name/src/main/res/
ملاحظة: لا تنس استبدال المسارات في الأمر بالمسارات الصحيحة وإنشاء مجلد الأصول (assets folder) إذا لم يكن موجودًا.
الآن أنشئ بناء إصدارٍ لتطبيقك الأصيل من داخل Android Studio كالمعتاد وسيكون كل شيء على ما يرام!
ماذا بعد؟
يمكنك الآن متابعة تطوير تطبيقك كالمعتاد. راجع توثيق التنقيح والنشر لمعرفة المزيد حول العمل مع React Native.
الدمج مع تطبيقات iOS قائمة مكتوبة بلغة Objective-C
المفاهيم الرئيسية
أهمّ الأمور لدمج مكونات React Native في تطبيق iOS الخاص بك هي:
- إعداد اعتماديات (dependencies) إطار العمل React Native وهيكل المجلّدات (directory structure).
- فهم مكونات React Native التي ستستخدمها في تطبيقك.
- إضافة هذه المكوّنات كاعتماديّاتٍ باستخدام CocoaPods.
- كتابة مكونات React Native باستخدام JavaScript.
- إضافة عرض
RCTRootView
إلى تطبيق iOS الخاص بك. سيكون هذا العرض بمثابة الحاوية لمكون React Native الخاص بك. - بدء تشغيل خادم React Native وتشغيل التطبيق الأصيل.
- تحقّق من أن جانب React Native من التطبيق الخاص بك يعمل كما هو متوقع.
المتطلبات الأساسية
اتبع إرشادات بناء مشاريعٍ بشيفرة أصيلة في الدرس التقديمي لتهيئة بيئة التطوير الخاصة بك لإنشاء تطبيقات React Native لنظام التشغيل iOS.
1. إعداد بنية المجلدات (directory structure)
لتسهيل العمل، أنشئ مجلدًا جديدًا لمشروع React Native المُدمَج الخاص بك، ثم انسخ مشروع iOS الحالي إلى مجلد فرعي باسم /ios
.
2. تثبيت اعتماديات JavaScript
انتقل إلى المجلّد الجذر (root directory) للمشروع الخاص بك وأنشئ ملف package.json
جديد بالمحتويات التالية:
{
"name": "MyReactNativeApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "yarn react-native start"
}
}
بعد ذلك، تأكّد من تثبيت مدير الحزم Yarn.
ثبّت حزمتي react
وreact-native
. افتح طرفيّةً (terminal) أو مَحثَّ أوامر (command prompt)، ثم انتقل إلى المجلّد الذي يحتوي على ملف package.json
ونفّذ الأمر التالي:
// yarn
yarn add react-native
// أو
// npm
npm install react-native
سيؤدي هذا إلى طباعة رسالةٍ مشابهة لما يلي (مرِّر لأعلى مُخرجات yarn
لمشاهدتها):
warning "react-native@0.52.2" has unmet peer dependency "react@16.2.0".
هذا يعني أنّنا بحاجة إلى تثبيت React كذلك:
//yarn
yarn add react@version_printed_above
//أو
//npm
npm install react@version_printed_above
ضع مكان version_printed_above الإصدار المذكور في رسالة التحذير التي ظهرت لك آنفًا ضمن "react@16.2.0".
أنشأت عملية التثبيت الآن مجلدَ /node_modules
جديد. يخزّن هذا المجلد جميع اعتماديات JavaScript المطلوبة لإنشاء مشروعك.
أضف node_modules/
إلى ملفّ .gitignore
الخاص بك.
3. تثبيت CocoaPods
CocoaPods هي أداةٌ لإدارة الحزم لتطوير تطبيقات iOS و macOS. سنستخدمها لإضافة شيفرة إطار React Native الفعليّة محليًا إلى مشروعك الحالي.
نوصي بتثبيت CocoaPods باستخدام Homebrew.
brew install cocoapods
ملاحظة: من الممكن تقنيًا الاستغناء عن أداة CocoaPods، ولكن هذا سيتطلب إضافة مكتباتٍ وروابط يدويًّا، ما سيُعقّد هذه العملية.
إضافة React Native إلى تطبيقك
لنفترض أن التطبيق الذي تُريد دمج مكونات جديدة معه هو لعبة 2048. إليك ما تبدو عليه القائمة الرئيسية للتطبيق الأصيل دون React Native.
أدوات سطر الأوامر لبيئة Xcode
لتثبيت أدوات سطر الأوامر (Command Line Tools). اختر "Preferences..." في قائمة Xcode. انتقل إلى لوحة Locations وثبّت الأدوات عن طريق تحديد أحدث إصدارٍ في قائمة Command Line Tools المنسدلة.
إعداد اعتماديات CocoaPods
قبل دمج React Native مع تطبيقك، ستحتاج إلى تحديد أجزاء إطار React Native التي تريد دمجها مع التطبيق. سنستخدم CocoaPods لتحديد أي من هذهِ المواصفات الفرعيّة (subspecs) سيعتمد عليها تطبيقك.
قائمة المواصفات الفرعية المدعومة متوفّرة في الملفّ /node_modules/react-native/React.podspec
. وتُسمَّى عمومًا حسب وظيفتها. على سبيل المثال، ستحتاج دائمًا إلى المواصفة الفرعيّة Core
. التي تحتوي على AppRegistry
و StyleSheet
و View
وغيرها من المكتبات الرئيسية في إطار React Native. إذا كنت ترغب في إضافة مكتبة Text
الخاصة بإطار React Native (لاستخدام عناصر <Text>
على سبيل المثال)، فستحتاج إلى المواصفة الفرعيّة RCTText
. إذا كنت ترغب باستخدام مكتبة Image (لعناصر <Image>
مثلًا)، فستحتاج إلى المواصفة الفرعيّة RCTImage
.
يمكنك تحديد المواصفات الفرعية التي سيعتمد عليها تطبيقك في ملف Podfile
. أسهل طريقة لإنشاء ملفّ Podfile
هي تنفيذ الأمر init
الخاص بأداة CocoaPods في المجلد الفرعي/ios
الخاص بمشروعك:
pod init
سوف يحتوي ملف Podfile
على إعداد نموذجيّ (boilerplate setup) يُمكنك تعديله حسب طريقة الدمج التي تريدها.
ملاحظة: تختلف نسخة Podfile
بحسب نسخة react-native، راجع https://react-native-community.github.io/upgrade-helper لمعرفة نسخة Podfile
التي يجب استخدامها.
يجب أن يبدو ملفّ Podfile
مشابهًا لهذا في النهاية:
# The target name is most likely the name of your project.
# اسم الهدف سيكون في أغلب الظن اسمَ مشروعك
target 'NumberTileGame' do
# Your 'node_modules' directory is probably in the root of your project,
# but if not, adjust the `:path` accordingly
# مجلدُ الاعتماديات موجود على الأغلب في جذر مشروعك، إن لم يكن كذلك، فعدّل المسار
pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
pod 'React', :path => '../node_modules/react-native/'
pod 'React-Core', :path => '../node_modules/react-native/'
pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
pod 'ReactCommon/callinvoker', :path => "../node_modules/react-native/ReactCommon"
pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
end
بعد إنشاء ملف Podfile
الخاص بك، ستكون جاهزًا لتثبيت React Native.
$ pod install
سيكون الخرج مشابها لما يلي:
Analyzing dependencies
Fetching podspec for `React` from `../node_modules/react-native`
Downloading dependencies
Installing React (0.62.0)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There are 3 dependencies from the Podfile and 1 total pod installed.
إذا فشل هذا مع وجود أخطاء تحتوي على xcrun، فتأكّد من تعيين أدوات Command Line Tools في Xcode عبر قائمة Preferences ثمّ Locations.
دمج الشيفرة
سنُعدّل الآن تطبيق iOS الأصيل لدمج React Native معه. سنضيف شاشة "High Score" لتطبيق 2048 الذي بين أيدينا باستخدام React Native.
مكون React Native
الجزء الأول من الشيفرة التي سنكتبها هي شيفرة React Native لشاشة "High Score" الجديدة التي سندمجها في تطبيقنا.
1. إنشاء ملف index.js
أولاً، أنشئ ملفّ index.js
فارغ في جذر مشروع React Native الخاص بك.
ملفّ index.js
هو نقطة البداية لتطبيقات React Native، وهو ضروري دائمًا. يمكن أن يكون ملفًا صغيرًا يطلب (يستورد require
) ملفًا آخر يمثّل جزءًا من مكوّن أو تطبيق React Native الخاص بك، أو يمكن أن يحتوي على كامل الشيفرة البرمجية اللازمة لذلك. في حالتنا، سنضع كامل الشيفرة في ملفّ index.js
.
2. أضف شيفرة React Native الخاصة بك
أنشئ المكوّن في ملفّ index.js
الخاص بك. في نموذجنا هنا، سنضيف مكون <Text>
بسيط داخل مكوّن <View>
مُنسَّق:
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
const RNHighScores = ({ scores }) => {
const contents = scores.map((score) => (
<Text key={score.name}>
{score.name}:{score.value}
{'\n'}
</Text>
));
return (
<View style={styles.container}>
<Text style={styles.highScoresTitle}>
2048 High Scores!
</Text>
<Text style={styles.scores}>{contents}</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF'
},
highScoresTitle: {
fontSize: 20,
textAlign: 'center',
margin: 10
},
scores: {
textAlign: 'center',
color: '#333333',
marginBottom: 5
}
});
// Module name
AppRegistry.registerComponent('RNHighScores', () => RNHighScores);
RNHighScores
هو اسم وحدتك الذي سيُستخدَم عند إضافة عرض إلى React Native من داخل تطبيق iOS الخاص بك.
الرابط العجيب: RCTRootView
الآن، وبعد إنشاء مكون React Native الخاص بك عبر ملفّ index.js
، تحتاج إلى إضافة هذا المكون إلى مُتحكّم ViewController
جديد أو موجود مسبقا. أيسر سبيل إلى ذلك هو إنشاء مسار حدث (event path) اختياريًّا يُشير إلى المكون الخاص بك، ثم إضافة هذا المكون إلى ViewController
موجود.
سنربط مكوّن React Native الخاص بنا مع عرض أصيل جديد في متحكّم ViewController
، والذي سيستضيف المكوّن. الواجهة الأصيلة تسمّى RCTRootView
.
1. إنشاء مسار حدث (Event Path)
يمكنك إضافة رابط جديد في قائمة اللعبة الرئيسية للانتقال إلى صفحة "High Score" المبنيّة بإطار React Native.
2. معالج الأحداث
سنضيف الآن معالج أحداثٍ من رابط القائمة. سيُضاف تابع إلى متحكّم ViewController
الرئيسي للتطبيق الخاص بك. هنا سنعتمد على واجهة RCTRootView
.
عند إنشاء تطبيق React Native، يُستخدَم المُجمّع Metro لإنشاء ملفّ index.bundle
الذي سيُقدَّم من طرف خادم React Native. سيحتوي ملفّ index.bundle
على وحدة RNHighScore
الخاصة بنا. لذا، سنحتاج إلى توجيه عرض RCTRootView الخاص بنا إلى مكان الملفّ index.bundle
(عبر NSURL
) وربطه بالوحدة.
لتسهيل التنقيح (debugging)، سنُسجّل (log) أنّ معالج الأحداث قد استُدعَى. بعد ذلك، سننشئ سلسلة نصيّة تحتوي على مكان شيفرة React Native الموجودة داخل ملفّ index.bundle
. أخيرًا، سننشئ الواجهة RCTRootView
الرئيسيّة. لاحظ كيف نُشير إلى الاسم RNHighScores
على أنّه اسم الوحدة (moduleName) الذي أنشأناه أعلاه عند كتابة شيفرة مكوّن React Native الخاص بنا.
أولاً استورد ترويسة RCTRootView
:
#import <React/RCTRootView.h>
الخاصيّات الأوليّةinitialProperties
موجودة هنا لأغراضٍ توضيحيّة ولتكون لدينا بعض البيانات لعرضها في شاشة "High Score". في مكوّن React Native الخاص بنا، سنستخدم this.props
للوصول إلى هذه البيانات.
- (IBAction)highScoreButtonPressed:(id)sender {
NSLog(@"High Score Button Pressed");
NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
RCTRootView *rootView =
[[RCTRootView alloc] initWithBundleURL: jsCodeLocation
moduleName: @"RNHighScores"
initialProperties:
@{
@"scores" : @[
@{
@"name" : @"Alex",
@"value": @"42"
},
@{
@"name" : @"Joel",
@"value": @"10"
}
]
}
launchOptions: nil];
UIViewController *vc = [[UIViewController alloc] init];
vc.view = rootView;
[self presentViewController:vc animated:YES completion:nil];
}
لاحظ أن المقطع RCTRootView initWithURL
يبدأ بتشغيل آلة افتراضية JSC جديدة (JSC VM). لتوفير الموارد وتبسيط الاتصال بين واجهات React Native في أجزاء مختلفة من التطبيق الأصلي، يُمكنك إنشاء عدّة واجهات مدعومة من React Native مرتبطة بوقت تشغيل JS واحد. للقيام بهذا، استخدم RCTBridge initWithBundleURL
بدلاً من استخدام[RCTRootView alloc] initWithURL
لإنشاء جسر ثم استخدم RCTRootView initWithBridge
.
عند نقل تطبيقك إلى بيئة الإنتاج (production)، يمكن لعنوان NSURL الإشارة إلى ملفّ مُحزَّم مسبقًا (pre-bundled) على القرص عبر سطرٍ برمجيّ مثل:
[[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
يمكنك استخدام برمجيّة react-native-xcode.sh
الموجودة في المسار node_modules/react-native/scripts/
لإنشاء هذا الملف المُحزّم مسبقًا.
3. الربط
اربط الرابط الجديد في القائمة الرئيسية بتابعِ معالجِ الأحداث المضاف حديثًا.
من أسهل الطرق للقيام بهذا هي فتح الواجهة في لوحة العمل (storyboard) والنقر بزر الفأرة الأيمن على الرابط الجديد. حدّد حدثًا مثل حدث Touch Up Inside
، واسحبه إلى لوحة العمل ثم حدّد العرض المُنشَأ من القائمة المتوفرة.
اختبار الدمج
انتهيت الآن من جميع الخطوات الأساسية لدمج React Native مع تطبيقك الحالي. سنبدأ الآن بتشغيل المُجمّع Metro لإنشاء حزمة index.bundle
والخادم الذي سيعمل على المضيف المحلي localhost
.
1. إضافة استثناء App Transport Security
حظرت شركة Apple تحميل موارد نصوص HTTP الضمنيّة (implicit cleartext HTTP). لذلك نحتاج إلى إضافة ما يلي إلى ملف Info.plist
الخاص بالتطبيق (أو ما يعادله).
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
سياسة أمان App Transport Security مفيدة لمستخدمي التطبيق. تأكّد من إعادة تمكينها قبل إطلاق تطبيقك للإنتاج.
2. تشغيل المُحزّم
لتشغيل تطبيقك، عليك أولاً تشغيل خادم التطوير (development server) عبر تنفيذ الأمر التالي من المجلّد الجذر لمشروع React Native الخاص بك:
//npm
npm start
//yarn
yarn start
3. تشغيل التطبيق
إذا كنت تستخدم Xcode أو محرّرك المفضّل، فأنشئ تطبيق iOS أصيل وشغّله كالمعتاد. أو يمكنك تشغيل التطبيق من سطر الأوامر عبر تنفيذ الأمر التالي من المجلّد الجذر لمشروعك :
$ npx react-native run-ios
سترى الآن في تطبيقنا، رابطًا يشير إلى شاشة "High Scores"، وعند النقر فوقه، سترى مكوّن React Native الخاص بك.
هذه هي الشاشة الرئيسيّة للتطبيق الأصيل:
هذه شاشة مكوّن React Native:
إذا واجهتك مشكلة في تقرير الوحدات (module resolution) عند تشغيل تطبيقك، فيرجى الاطلاع على هذه الصفحة للحصول على معلوماتٍ قد تساعدك على حل مشكلتك. يبدو هذا التعليق حلًّا ممكنًا.
ماذا بعد؟
يمكنك الآن متابعة تطوير تطبيقك كالمعتاد. راجع توثيق التنقيح والنشر لمعرفة المزيد حول العمل مع React Native.
الدمج مع تطبيقات iOS قائمة مكتوبة بلغة Swift
المفاهيم الرئيسية
أهمّ الأمور لدمج مكونات React Native في تطبيق iOS الخاص بك هي:
- إعداد اعتماديات (dependencies) إطار العمل React Native وهيكل المجلّدات (directory structure).
- فهم مكونات React Native التي ستستخدمها في تطبيقك.
- إضافة هذه المكوّنات كاعتماديّاتٍ باستخدام CocoaPods.
- كتابة مكونات React Native باستخدام JavaScript.
- إضافة عرض
RCTRootView
إلى تطبيق iOS الخاص بك. سيكون هذا العرض بمثابة الحاوية لمكون React Native الخاص بك. - بدء تشغيل خادم React Native وتشغيل التطبيق الأصيل.
- تحقّق من أن جانب React Native من التطبيق الخاص بك يعمل كما هو متوقع.
المتطلبات الأساسية
اتبع إرشادات بناء مشاريعٍ بشيفرة أصيلة في الدرس التقديمي لتهيئة بيئة التطوير الخاصة بك لإنشاء تطبيقات React Native لنظام التشغيل iOS.
1. إعداد بنية المجلدات (directory structure)
لتسهيل العمل، أنشئ مجلدًا جديدًا لمشروع React Native المُدمَج الخاص بك، ثم انسخ مشروع iOS الحالي إلى مجلد فرعي باسم /ios
.
2. تثبيت اعتماديات JavaScript
انتقل إلى المجلّد الجذر (root directory) للمشروع الخاص بك وأنشئ ملف package.json
جديد بالمحتويات التالية:
{
"name": "MyReactNativeApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "yarn react-native start"
}
}
بعد ذلك، تأكّد من تثبيت مدير الحزم Yarn.
ثبّت حزمتي react
وreact-native
. افتح طرفيّةً (terminal) أو مَحثَّ أوامر (command prompt)، ثم انتقل إلى المجلّد الذي يحتوي على ملف package.json
ونفّذ الأمر التالي:
$ yarn add react-native
سيؤدي هذا إلى طباعة رسالةٍ مشابهة لما يلي (مرِّر لأعلى مُخرجات yarn
لمشاهدتها):
warning "react-native@0.52.2" has unmet peer dependency "react@16.2.0".
هذا يعني أنّنا بحاجة إلى تثبيت React كذلك:
$ yarn add react@version_printed_above
ضع مكان version_printed_above الإصدار المذكور في رسالة التحذير التي ظهرت لك آنفًا ضمن "react@16.2.0".
أنشأَ Yarn مجلدَ /node_modules
جديد. يخزّن هذا المجلد جميع اعتماديات JavaScript المطلوبة لإنشاء مشروعك.
أضف node_modules/
إلى ملفّ .gitignore
الخاص بك.
3. تثبيت CocoaPods
CocoaPods هي أداةٌ لإدارة الحزم لتطوير تطبيقات iOS و macOS. سنستخدمها لإضافة شيفرة إطار React Native الفعليّة محليًا إلى مشروعك الحالي.
نوصي بتثبيت CocoaPods باستخدام Homebrew.
$ brew install cocoapods
ملاحظة: من الممكن تقنيًا الاستغناء عن أداة CocoaPods، ولكن هذا سيتطلب إضافة مكتباتٍ وروابط يدويًّا، ما سيُعقّد هذه العملية.
إضافة React Native إلى تطبيقك
لنفترض أن التطبيق الذي تُريد دمج مكونات جديدة معه هو لعبة 2048. إليك ما تبدو عليه القائمة الرئيسية للتطبيق الأصيل دون React Native.
أدوات سطر الأوامر لبيئة Xcode
لتثبيت أدوات سطر الأوامر (Command Line Tools). اختر "Preferences..." في قائمة Xcode. انتقل إلى لوحة Locations وثبّت الأدوات عن طريق تحديد أحدث إصدارٍ في قائمة Command Line Tools المنسدلة.
إعداد اعتماديات CocoaPods
قبل دمج React Native مع تطبيقك، ستحتاج إلى تحديد أجزاء إطار React Native التي تريد دمجها مع التطبيق. سنستخدم CocoaPods لتحديد أي من هذهِ المواصفات الفرعيّة (subspecs) سيعتمد عليها تطبيقك.
قائمة المواصفات الفرعية المدعومة متوفّرة في الملفّ /node_modules/react-native/React.podspec
. وتُسمَّى عمومًا حسب وظيفتها. على سبيل المثال، ستحتاج دائمًا إلى المواصفة الفرعيّة Core
. التي تحتوي على AppRegistry
و StyleSheet
و View
وغيرها من المكتبات الرئيسية في إطار React Native. إذا كنت ترغب في إضافة مكتبة Text
الخاصة بإطار React Native (لاستخدام عناصر <Text>
على سبيل المثال)، فستحتاج إلى المواصفة الفرعيّة RCTText
. إذا كنت ترغب باستخدام مكتبة Image
(لعناصر <Image>
مثلًا)، فستحتاج إلى المواصفة الفرعيّة RCTImage
.
يمكنك تحديد المواصفات الفرعية التي سيعتمد عليها تطبيقك في ملف Podfile
. أسهل طريقة لإنشاء ملفّ Podfile
هي تنفيذ الأمر init
الخاص بأداة CocoaPods في المجلد الفرعي/ios
الخاص بمشروعك:
$ pod init
سوف يحتوي ملف Podfile
على إعداد نموذجيّ (boilerplate setup) يُمكنك تعديله حسب طريقة الدمج التي تريدها.
ملاحظة: تختلف نسخة Podfile
بحسب نسخة react-native، راجع https://react-native-community.github.io/upgrade-helper لمعرفة نسخة Podfile
التي يجب استخدامها.
يجب أن يبدو ملفّ Podfile
مشابهًا لهذا في النهاية:
source 'https://github.com/CocoaPods/Specs.git'
# مطلوب للتطبيقات المكتوبة بلغة
# Swift
platform :ios, '8.0'
use_frameworks!
# The target name is most likely the name of your project.
# اسم الهدف سيكون في أغلب الظن اسمَ مشروعك
target 'swift-2048' do
# Your 'node_modules' directory is probably in the root of your project,
# but if not, adjust the `:path` accordingly
# مجلدُ الاعتماديات موجود على الأغلب في جذر مشروعك، إن لم يكن كذلك، فعدّل المسار
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'Core',
'CxxBridge', # Include this for RN >= 0.47
'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43
'RCTText',
'RCTNetwork',
'RCTWebSocket', # needed for debugging
# Add any other subspecs you want to use in your project
# أضف أي مواصفات فرعية أخرى حسب ما تريد الاعتماد عليه في مشروعك
]
# Explicitly include Yoga if you are using RN >= 0.42.0
pod "Yoga", :path => "../node_modules/react-native/ReactCommon/yoga"
# Third party deps podspec link
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
end
بعد إنشاء ملف Podfile
الخاص بك، ستكون جاهزًا لتثبيت React Native.
$ pod install
سيكون الخرج مشابها لما يلي:
Analyzing dependencies
Fetching podspec for `React` from `../node_modules/react-native`
Downloading dependencies
Installing React (0.62.0)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There are 3 dependencies from the Podfile and 1 total pod installed.
إذا فشل هذا مع وجود أخطاء تحتوي على xcrun، فتأكّد من تعيين أدوات Command Line Tools في Xcode عبر قائمة Preferences ثمّ Locations.
إذا حصلت على تنبيه مشابه للنصّ التالي:
"The swift-2048 [Debug] target overrides the FRAMEWORK_SEARCH_PATHS build setting defined in Pods/Target Support Files/Pods-swift-2048/Pods-swift-2048.debug.xcconfig. This can lead to problems with the CocoaPods installation"
فتأكّد من أن مسارات البحث عن أطر العمل Framework Search Paths
في إعدادات البناء Build Settings
لكل من Debug
وRelease
تحتوي فقط على $(inherited)
.
دمج الشيفرة
سنُعدّل الآن تطبيق iOS الأصيل لدمج React Native معه. سنضيف شاشة "High Score" لتطبيق 2048 الذي بين أيدينا باستخدام React Native.
مكون React Native
الجزء الأول من الشيفرة التي سنكتبها هي شيفرة React Native لشاشة "High Score" الجديدة التي سندمجها في تطبيقنا.
1. إنشاء ملف index.js
أولاً، أنشئ ملفّ index.js
فارغ في جذر مشروع React Native الخاص بك.
ملفّ index.js
هو نقطة البداية لتطبيقات React Native، وهو ضروري دائمًا. يمكن أن يكون ملفًا صغيرًا يطلب (require
) ملفًا آخر يمثّل جزءًا من مكوّن أو تطبيق React Native الخاص بك، أو يمكن أن يحتوي على كامل الشيفرة البرمجية اللازمة لذلك. في حالتنا، سنضع كامل الشيفرة في ملفّ index.js
.
2. أضف شيفرة React Native الخاصة بك
أنشئ المكوّن في ملفّ index.js
الخاص بك. في نموذجنا هنا، سنضيف مكون <Text>
بسيط داخل مكوّن <View>
مُنسَّق:
import React from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
const RNHighScores = ({ scores }) => {
const contents = scores.map((score) => (
<Text key={score.name}>
{score.name}:{score.value}
{'\n'}
</Text>
));
return (
<View style={styles.container}>
<Text style={styles.highScoresTitle}>
2048 High Scores!
</Text>
<Text style={styles.scores}>{contents}</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF'
},
highScoresTitle: {
fontSize: 20,
textAlign: 'center',
margin: 10
},
scores: {
textAlign: 'center',
color: '#333333',
marginBottom: 5
}
});
// Module name
AppRegistry.registerComponent('RNHighScores', () => RNHighScores);
RNHighScores
هو اسم وحدتك الذي سيُستخدَم عند إضافة عرض إلى React Native من داخل تطبيق iOS الخاص بك.
الرابط العجيب: RCTRootView
الآن، وبعد إنشاء مكون React Native الخاص بك عبر ملفّ index.js
، تحتاج إلى إضافة هذا المكون إلى مُتحكّم ViewController
جديد أو موجود مسبقا. أيسر سبيل إلى ذلك هو إنشاء مسار حدث (event path) اختياريًّا يُشير إلى المكون الخاص بك، ثم إضافة هذا المكون إلى ViewController
موجود.
سنربط مكوّن React Native الخاص بنا مع عرض أصيل جديد في متحكّم ViewController
، والذي سيستضيف المكوّن. العرضُ الأصيل يُسمّى RCTRootView
.
1. إنشاء مسار حدث (Event Path)
يمكنك إضافة رابط جديد في قائمة اللعبة الرئيسية للانتقال إلى صفحة "High Score" المبنيّة بإطار React Native.
2. معالج الأحداث
سنضيف الآن معالج أحداثٍ من رابط القائمة. سيُضاف تابع إلى متحكّم ViewController
الرئيسي للتطبيق الخاص بك. هنا سنعتمد على عرض RCTRootView
.
عند إنشاء تطبيق React Native، يُستخدَم المجمّع Metro لإنشاء ملفّ index.bundle
الذي سيُقدَّم من طرف خادم React Native. سيحتوي ملفّ index.bundle
على وحدة RNHighScore
الخاصة بنا. لذا، سنحتاج إلى توجيه عرض RCTRootView
الخاص بنا إلى مكان الملفّ index.bundle
(عبر NSURL
) وربطه بالوحدة.
لتسهيل التنقيح (debugging)، سنُسجّل (log) أنّ معالج الأحداث قد استُدعَى. بعد ذلك، سننشئ سلسلة نصيّة تحتوي على مكان شيفرة React Native الموجودة داخل ملفّ index.bundle
. أخيرًا، سننشئ عرض RCTRootView
الرئيسيّ. لاحظ كيف نُشير إلى الاسم RNHighScores
على أنّه اسم الوحدة moduleName
الذي أنشأناه أعلاه عند كتابة شيفرة مكوّن React Native الخاص بنا.
أولاً استورد (عبر import
) مكتبة React
:
import React
الخاصيّات الأوليّةinitialProperties
موجودة هنا لأغراضٍ توضيحيّة، ولتكون لدينا بعض البيانات لعرضها في شاشة "High Score". في مكوّن React Native الخاص بنا، سنستخدم this.props
للوصول إلى هذه البيانات.
@IBAction func highScoreButtonTapped(sender : UIButton) {
NSLog("Hello")
let jsCodeLocation = URL(string: "http://localhost:8081/index.bundle?platform=ios")
let mockData:NSDictionary = ["scores":
[
["name":"Alex", "value":"42"],
["name":"Joel", "value":"10"]
]
]
let rootView = RCTRootView(
bundleURL: jsCodeLocation,
moduleName: "RNHighScores",
initialProperties: mockData as [NSObject : AnyObject],
launchOptions: nil
)
let vc = UIViewController()
vc.view = rootView
self.present(vc, animated: true, completion: nil)
}
لاحظ أن المقطع RCTRootView initWithURL
يبدأ بتشغيل آلة افتراضية JSC جديدة (JSC VM). لتوفير الموارد وتبسيط الاتصال بين عروض React Native في أجزاء مختلفة من التطبيق الأصلي، يُمكنك إنشاء عدّة واجهات مدعومة من React Native مرتبطة بوقت تشغيل JS واحد. للقيام بهذا، استخدم RCTBridge initWithBundleURL
بدلاً من ستخدام RCTRootView bundleURL
لإنشاء جسر ثم استخدم RCTRootView initWithBridge
.
عند نقل تطبيقك إلى بيئة الإنتاج (production)، يمكن لعنوان NSURL
الإشارة إلى ملفّ مُحزَّم مسبقًا (pre-bundled) على القرص عبر سطرٍ برمجيّ مثل:
let mainBundle = NSBundle(URLForResource: "main" withExtension:"jsbundle")
يمكنك استخدام برمجيّة react-native-xcode.sh
الموجودة في المسار node_modules/react-native/scripts/
لإنشاء هذا الملف المُحزّم مسبقًا.
3. الربط
اربط الرابط الجديد في القائمة الرئيسية بتابعِ معالجِ الأحداث المضاف حديثًا.
من أسهل الطرق للقيام بهذا هي فتح العرض في لوحة العمل (storyboard) والنقر بزر الفأرة الأيمن على الرابط الجديد. حدّد حدثًا مثل حدث Touch Up Inside
، واسحبه إلى لوحة العمل ثم حدّد العرض المُنشَأ من القائمة المتوفرة.
اختبار الدمج
انتهيت الآن من جميع الخطوات الأساسية لدمج React Native مع تطبيقك الحالي. سنبدأ الآن بتشغيل مُحزّم React Native لإنشاء حزمة index.bundle
والخادم الذي سيعمل على المضيف المحلي localhost
.
1. إضافة استثناء App Transport Security
حظرت شركة Apple تحميل موارد نصوص HTTP الضمنيّة (implicit cleartext HTTP). لذلك نحتاج إلى إضافة ما يلي إلى ملف Info.plist
الخاص بالتطبيق (أو ما يعادله).
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
سياسة أمان App Transport Security مفيدة لمستخدمي التطبيق. تأكّد من إعادة تمكينها قبل إطلاق تطبيقك للإنتاج.
2. تشغيل المُحزّم
لتشغيل تطبيقك، عليك أولاً تشغيل خادم التطوير (development server) عبر تنفيذ الأمر التالي من المجلّد الجذر لمشروع React Native الخاص بك:
$ npm start
3. تشغيل التطبيق
إذا كنت تستخدم Xcode أو محرّرك المفضّل، فأنشئ تطبيق iOS أصيل وشغّله كالمعتاد. أو يمكنك تشغيل التطبيق من سطر الأوامر عبر تنفيذ الأمر التالي من المجلّد الجذر لمشروعك:
$ npx react-native run-ios
سترى الآن في تطبيقنا، رابطًا يشير إلى شاشة "High Scores"، وعند النقر فوقه، سترى مكوّن React Native الخاص بك.
هذه هي الشاشة الرئيسيّة للتطبيق الأصيل:
هذه شاشة مكوّن React Native:
إذا واجهتك مشكلة في تقرير الوحدات (module resolution) عند تشغيل تطبيقك، فيرجى الاطلاع على هذه الصفحة للحصول على معلوماتٍ قد تساعدك على حل مشكلتك. يبدو هذا التعليق حلًّا ممكنًا.
ماذا بعد؟
يمكنك الآن متابعة تطوير تطبيقك كالمعتاد. راجع توثيق التنقيح والنشر لمعرفة المزيد حول العمل مع React Native.