Capacitor + React — بناء تطبيقات موبايل متعددة المنصات من تطبيقك الويب (2026)

كود React الخاص بك، يعمل أصلياً على iOS و Android. يسد Capacitor الفجوة بين الويب والموبايل — مما يمنحك وصولاً كاملاً إلى واجهات برمجة التطبيقات الأصلية مثل الكاميرا، تحديد الموقع، الإشعارات الفورية، والمصادقة البيومترية مع الحفاظ على قاعدة كود React الحالية.
ما ستتعلمه
بنهاية هذا الدليل، ستكون قادراً على:
- فهم كيفية عمل Capacitor والفرق بينه وبين React Native أو Cordova
- إضافة Capacitor إلى مشروع React موجود (مبني على Vite)
- الوصول إلى ميزات الجهاز الأصلية: الكاميرا، نظام الملفات، الاهتزاز اللمسي، والتخزين المحلي
- بناء وتشغيل تطبيقك على محاكيات iOS و Android
- التعامل مع الكود الخاص بكل منصة بشكل نظيف
- تكوين أيقونات التطبيق، شاشات البداية، والروابط العميقة
- تحضير تطبيقك للنشر على App Store و Google Play
المتطلبات الأساسية
قبل البدء، تأكد من توفر:
- Node.js 20+ مثبت (
node --version) - معرفة قوية بـ React و TypeScript
- Xcode 16+ (لـ iOS — macOS فقط)
- Android Studio مع محاكي مُعد (لـ Android)
- CocoaPods مثبت (
sudo gem install cocoapods) لـ iOS - محرر أكواد مثل VS Code
لماذا Capacitor؟
Capacitor هو بيئة تشغيل من Ionic تتيح لك نشر تطبيقات الويب كتطبيقات موبايل أصلية. على عكس React Native، تحتفظ بكود React القياسي المبني على DOM — HTML و CSS وكل شيء. وعلى عكس Cordova (الذي يحل محله Capacitor)، يستخدم بنية إضافات حديثة، ودعم TypeScript من الدرجة الأولى، ويمكنه حتى العمل كتطبيق ويب تقدمي في نفس الوقت.
| الميزة | Capacitor | React Native | Cordova |
|---|---|---|---|
| عرض الواجهة | WebView (HTML/CSS الخاص بك) | عناصر أصلية | WebView |
| نظام الإضافات | حديث، TypeScript أولاً | وحدات جسر | XML قديم |
| دعم PWA | مدمج | لا يوجد | محدود |
| النظام البيئي | متنامي، مدعوم من Ionic | ضخم | في انحدار |
| منحنى التعلم | منخفض (إذا كنت تعرف الويب) | متوسط-مرتفع | منخفض |
الخطوة 1: إنشاء مشروع React + Vite
سنبدأ بمشروع Vite + React + TypeScript جديد. إذا كان لديك مشروع بالفعل، انتقل إلى الخطوة 2.
npm create vite@latest my-mobile-app -- --template react-ts
cd my-mobile-app
npm installتأكد من أنه يعمل:
npm run devافتح http://localhost:5173 — يجب أن ترى صفحة Vite + React الافتراضية.
الخطوة 2: تثبيت Capacitor
أضف نواة Capacitor وأداة سطر الأوامر إلى مشروعك:
npm install @capacitor/core
npm install -D @capacitor/cliقم بتهيئة Capacitor:
npx cap initسيُطلب منك:
- اسم التطبيق:
My Mobile App - معرف الحزمة:
com.example.mymobileapp(تدوين النطاق المعكوس)
هذا ينشئ ملف capacitor.config.ts في جذر مشروعك:
import type { CapacitorConfig } from "@capacitor/cli";
const config: CapacitorConfig = {
appId: "com.example.mymobileapp",
appName: "My Mobile App",
webDir: "dist",
server: {
androidScheme: "https",
},
};
export default config;يخبر webDir: "dist" Capacitor بموقع أصول الويب المبنية — بالنسبة لـ Vite، هو dist.
الخطوة 3: إضافة المنصات الأصلية
أضف منصتي iOS و Android:
npm install @capacitor/ios @capacitor/android
npx cap add ios
npx cap add androidهذا ينشئ مجلدات ios/ و android/ مع مشاريع Xcode و Android Studio أصلية كاملة.
ابنِ تطبيقك الويب وزامنه مع المشاريع الأصلية:
npm run build
npx cap syncنفّذ دائماً npx cap sync بعد تعديل كود الويب أو تثبيت إضافات Capacitor جديدة. هذا ينسخ مجلد dist/ المبني إلى المشاريع الأصلية ويحدّث التبعيات الأصلية.
الخطوة 4: التشغيل على المحاكيات
iOS (macOS فقط)
npx cap open iosهذا يفتح المشروع في Xcode. اختر محاكي (مثلاً iPhone 15 Pro) وانقر على زر التشغيل، أو شغّل من الطرفية:
npx cap run iosAndroid
npx cap open androidهذا يفتح المشروع في Android Studio. اختر محاكي وانقر على تشغيل، أو:
npx cap run androidيجب أن ترى تطبيق React يعمل داخل غلاف أصلي على كلا المنصتين.
الخطوة 5: الوصول إلى الكاميرا بإضافة أصلية
لنبنِ شيئاً حقيقياً — ميزة التقاط الصور باستخدام إضافة Camera من Capacitor.
ثبّت الإضافة:
npm install @capacitor/camera
npx cap syncأنشئ hook مخصص src/hooks/useCamera.ts:
import { Camera, CameraResultType, CameraSource } from "@capacitor/camera";
export function useCamera() {
const takePhoto = async () => {
const photo = await Camera.getPhoto({
quality: 90,
allowEditing: false,
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
});
return photo.webPath;
};
const pickFromGallery = async () => {
const photo = await Camera.getPhoto({
quality: 90,
allowEditing: false,
resultType: CameraResultType.Uri,
source: CameraSource.Photos,
});
return photo.webPath;
};
return { takePhoto, pickFromGallery };
}استخدمه الآن في مكوّن src/components/PhotoCapture.tsx:
import { useState } from "react";
import { useCamera } from "../hooks/useCamera";
export function PhotoCapture() {
const { takePhoto, pickFromGallery } = useCamera();
const [photoUrl, setPhotoUrl] = useState<string | null>(null);
const handleTakePhoto = async () => {
try {
const url = await takePhoto();
if (url) setPhotoUrl(url);
} catch (error) {
console.error("خطأ في الكاميرا:", error);
}
};
const handlePickPhoto = async () => {
try {
const url = await pickFromGallery();
if (url) setPhotoUrl(url);
} catch (error) {
console.error("خطأ في المعرض:", error);
}
};
return (
<div className="photo-capture">
<h2>التقاط صورة</h2>
<div className="buttons">
<button onClick={handleTakePhoto}>التقط صورة</button>
<button onClick={handlePickPhoto}>اختر من المعرض</button>
</div>
{photoUrl && (
<div className="preview">
<img src={photoUrl} alt="صورة ملتقطة" />
</div>
)}
</div>
);
}أذونات iOS
لـ iOS، تحتاج إلى إضافة أوصاف الأذونات. افتح ios/App/App/Info.plist وأضف:
<key>NSCameraUsageDescription</key>
<string>يحتاج هذا التطبيق إلى الوصول للكاميرا لالتقاط الصور</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>يحتاج هذا التطبيق إلى الوصول لمكتبة الصور لاختيار الصور</string>أذونات Android
لـ Android، يتعامل Capacitor مع الأذونات تلقائياً، لكن تحقق في android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />أعد البناء والمزامنة:
npm run build
npx cap sync
npx cap run iosالخطوة 6: التخزين المحلي مع Preferences
توفر إضافة Preferences من Capacitor مخزن مفتاح-قيمة يستمر بين عمليات تشغيل التطبيق — المكافئ المحمول لـ localStorage لكن أكثر موثوقية.
npm install @capacitor/preferences
npx cap syncأنشئ أداة تخزين src/lib/storage.ts:
import { Preferences } from "@capacitor/preferences";
export const storage = {
async get<T>(key: string): Promise<T | null> {
const { value } = await Preferences.get({ key });
if (!value) return null;
return JSON.parse(value) as T;
},
async set(key: string, value: unknown): Promise<void> {
await Preferences.set({
key,
value: JSON.stringify(value),
});
},
async remove(key: string): Promise<void> {
await Preferences.remove({ key });
},
async clear(): Promise<void> {
await Preferences.clear();
},
};استخدمه لحفظ الصور:
import { storage } from "../lib/storage";
// حفظ رابط صورة
await storage.set("lastPhoto", photoUrl);
// استرجاعها لاحقاً
const lastPhoto = await storage.get<string>("lastPhoto");الخطوة 7: الاستجابة اللمسية
أضف ردود فعل لمسية لضغطات الأزرار — لمسة صغيرة تجعل التطبيقات تبدو أصلية:
npm install @capacitor/haptics
npx cap syncأنشئ أداة اهتزاز src/lib/haptics.ts:
import { Haptics, ImpactStyle } from "@capacitor/haptics";
import { Capacitor } from "@capacitor/core";
export const haptics = {
async impact(style: ImpactStyle = ImpactStyle.Medium) {
if (Capacitor.isNativePlatform()) {
await Haptics.impact({ style });
}
},
async notification(type: "success" | "warning" | "error") {
if (Capacitor.isNativePlatform()) {
await Haptics.notification({ type: type as any });
}
},
async vibrate() {
if (Capacitor.isNativePlatform()) {
await Haptics.vibrate();
}
},
};لاحظ فحص Capacitor.isNativePlatform() — يضمن أن الاهتزازات تعمل فقط على الأجهزة الحقيقية، وليس في المتصفح. استخدمه في زر التصوير:
import { haptics } from "../lib/haptics";
import { ImpactStyle } from "@capacitor/haptics";
const handleTakePhoto = async () => {
await haptics.impact(ImpactStyle.Light);
const url = await takePhoto();
if (url) setPhotoUrl(url);
};الخطوة 8: اكتشاف المنصة وواجهة المستخدم التكيفية
تطبيقك يعمل على الويب و iOS و Android. أحياناً تحتاج سلوكاً خاصاً بالمنصة:
import { Capacitor } from "@capacitor/core";
export function getPlatformInfo() {
return {
platform: Capacitor.getPlatform(), // 'web' | 'ios' | 'android'
isNative: Capacitor.isNativePlatform(),
isIOS: Capacitor.getPlatform() === "ios",
isAndroid: Capacitor.getPlatform() === "android",
isWeb: Capacitor.getPlatform() === "web",
};
}استخدم هذا لتنسيق تكيفي:
import { getPlatformInfo } from "../lib/platform";
function AppHeader() {
const { isIOS } = getPlatformInfo();
return (
<header
style={{
paddingTop: isIOS ? "env(safe-area-inset-top)" : "0",
}}
>
<h1>تطبيقي</h1>
</header>
);
}المناطق الآمنة (Safe Areas)
أجهزة iOS ذات النتوء تحتاج معالجة المناطق الآمنة. أضف هذا CSS:
:root {
--sat: env(safe-area-inset-top);
--sab: env(safe-area-inset-bottom);
--sal: env(safe-area-inset-left);
--sar: env(safe-area-inset-right);
}
body {
padding-top: var(--sat);
padding-bottom: var(--sab);
padding-left: var(--sal);
padding-right: var(--sar);
}في capacitor.config.ts، فعّل تغطية شريط الحالة:
const config: CapacitorConfig = {
// ...
ios: {
contentInset: "automatic",
},
};الخطوة 9: الإشعارات الفورية
أضف الإشعارات الفورية بإضافة Push Notifications من Capacitor:
npm install @capacitor/push-notifications
npx cap syncأنشئ خدمة إشعارات src/lib/notifications.ts:
import { PushNotifications } from "@capacitor/push-notifications";
import { Capacitor } from "@capacitor/core";
export async function initPushNotifications() {
if (!Capacitor.isNativePlatform()) {
console.log("الإشعارات الفورية غير متاحة على الويب");
return;
}
// طلب الإذن
const permStatus = await PushNotifications.requestPermissions();
if (permStatus.receive !== "granted") {
console.warn("لم يتم منح إذن الإشعارات");
return;
}
// التسجيل لدى Apple/Google
await PushNotifications.register();
// الاستماع لرمز التسجيل
PushNotifications.addListener("registration", (token) => {
console.log("رمز الإشعارات:", token.value);
// أرسل هذا الرمز إلى الخادم الخلفي
});
// الاستماع للإشعارات الواردة
PushNotifications.addListener(
"pushNotificationReceived",
(notification) => {
console.log("إشعار مستلم:", notification);
}
);
// الاستماع للنقر على الإشعارات
PushNotifications.addListener(
"pushNotificationActionPerformed",
(action) => {
console.log("إجراء الإشعار:", action);
// الانتقال إلى الشاشة المناسبة
}
);
}استدعِه من App.tsx:
import { useEffect } from "react";
import { initPushNotifications } from "./lib/notifications";
function App() {
useEffect(() => {
initPushNotifications();
}, []);
return <>{/* تطبيقك */}</>;
}الخطوة 10: الأيقونات وشاشة البداية
توليد الأيقونات
استخدم حزمة @capacitor/assets لتوليد جميع الأحجام المطلوبة من صورة مصدر واحدة:
npm install -D @capacitor/assetsضع صورك المصدرية:
assets/icon-only.png— أيقونة 1024x1024 (بدون خلفية)assets/icon-background.png— خلفية أيقونة 1024x1024assets/splash.png— شاشة بداية 2732x2732
ولّد جميع أيقونات المنصات:
npx capacitor-assets generateهذا ينشئ جميع الأحجام المطلوبة لـ iOS و Android في المشاريع الأصلية.
إعداد شاشة البداية
ثبّت إضافة شاشة البداية:
npm install @capacitor/splash-screen
npx cap syncأعدّها في capacitor.config.ts:
const config: CapacitorConfig = {
// ...
plugins: {
SplashScreen: {
launchShowDuration: 2000,
backgroundColor: "#1a1a2e",
showSpinner: false,
androidScaleType: "CENTER_CROP",
splashFullScreen: true,
splashImmersive: true,
},
},
};أخفِها برمجياً في تطبيقك:
import { SplashScreen } from "@capacitor/splash-screen";
// عندما يكون تطبيقك جاهزاً
await SplashScreen.hide();الخطوة 11: إعادة التحميل المباشر أثناء التطوير
كتابة npm run build && npx cap sync في كل مرة تغيّر فيها الكود بطيء. فعّل إعادة التحميل المباشر لتسريع التطوير:
حدّث capacitor.config.ts للتطوير:
import type { CapacitorConfig } from "@capacitor/cli";
const config: CapacitorConfig = {
appId: "com.example.mymobileapp",
appName: "My Mobile App",
webDir: "dist",
server: {
// تفعيل إعادة التحميل المباشر في التطوير
url: "http://عنوان_IP_المحلي:5173",
cleartext: true,
},
};
export default config;اعثر على عنوان IP المحلي:
# macOS
ipconfig getifaddr en0الآن شغّل Vite ونفّذ على الجهاز:
npm run dev
npx cap run ios --livereload --externalتذكر إزالة server.url قبل البناء للإنتاج! لا تريد أن يشير تطبيقك المنشور إلى خادم تطوير.
الخطوة 12: البناء للإنتاج
iOS
- افتح في Xcode:
npx cap open ios - اختر Product ثم Archive
- في المنظم، انقر على Distribute App
- اتبع خطوات التوقيع والرفع إلى App Store Connect
Android
أنشئ APK أو AAB موقّع:
cd android
./gradlew bundleReleaseملف AAB سيكون في android/app/build/outputs/bundle/release/app-release.aab.
وقّعه بمفتاحك:
jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 \
-keystore my-release-key.jks \
app-release.aab alias_nameارفع AAB إلى Google Play Console.
مثال التطبيق الكامل
إليك App.tsx كامل يجمع كل شيء:
import { useEffect, useState } from "react";
import { SplashScreen } from "@capacitor/splash-screen";
import { PhotoCapture } from "./components/PhotoCapture";
import { storage } from "./lib/storage";
import { initPushNotifications } from "./lib/notifications";
import { getPlatformInfo } from "./lib/platform";
import "./App.css";
function App() {
const [platform, setPlatform] = useState("");
const [savedPhotos, setSavedPhotos] = useState<string[]>([]);
useEffect(() => {
const init = async () => {
const info = getPlatformInfo();
setPlatform(info.platform);
// تحميل الصور المحفوظة
const photos = await storage.get<string[]>("photos");
if (photos) setSavedPhotos(photos);
// تهيئة الإشعارات الفورية
await initPushNotifications();
// إخفاء شاشة البداية
await SplashScreen.hide();
};
init();
}, []);
return (
<div className="app">
<header className="app-header">
<h1>تطبيقي المحمول</h1>
<span className="platform-badge">{platform}</span>
</header>
<main>
<PhotoCapture />
{savedPhotos.length > 0 && (
<section className="gallery">
<h2>الصور المحفوظة</h2>
<div className="photo-grid">
{savedPhotos.map((url, i) => (
<img key={i} src={url} alt={`صورة ${i + 1}`} />
))}
</div>
</section>
)}
</main>
</div>
);
}
export default App;استكشاف الأخطاء وإصلاحها
خطأ "Unable to determine the current platform"
تأكد من تنفيذ npx cap sync بعد تثبيت إضافات جديدة.
فشل بناء iOS مع أخطاء التوقيع
افتح Xcode، اذهب إلى Signing & Capabilities، واختر فريق التطوير الخاص بك. مع حساب Apple Developer المجاني، يمكنك الاختبار على جهاز حقيقي لكن لا يمكنك النشر.
محاكي Android بطيء
فعّل تسريع العتاد (HAXM على Intel، Hypervisor على Apple Silicon). استخدم صورة نظام x86_64 لأداء أفضل.
الكاميرا لا تعمل في المتصفح
بعض إضافات Capacitor تعمل بشكل بديل على الويب، وبعضها لا. إضافة Camera تفتح منتقي ملفات على الويب كبديل.
إعادة التحميل المباشر لا تتصل على الجهاز
تأكد أن جهازك وحاسوب التطوير على نفس شبكة Wi-Fi، وتحقق من إعدادات جدار الحماية.
الخطوات التالية
- استكشف سجل إضافات Capacitor لمزيد من الميزات الأصلية
- أضف المصادقة البيومترية مع
@capacitor/biometrics - ادمج الروابط العميقة مع
@capacitor/appللتنقل عبر الروابط - أعدّ CI/CD مع Appflow أو GitHub Actions للبناء الآلي
- فكّر في إضافة Ionic Framework فوقه لمكونات واجهة مستخدم محمولة جاهزة
الخلاصة
يتيح لك Capacitor استغلال مهارات React والويب لبناء تطبيقات محمولة أصلية حقيقية — بدون تعلم Swift أو Kotlin. تحتفظ بأدواتك المألوفة (Vite و TypeScript و CSS)، وتحصل على وصول لواجهات برمجة التطبيقات الأصلية عبر نظام إضافات نظيف، ويمكنك حتى شحن نفس الكود كتطبيق ويب تقدمي.
النهج عملي: للتطبيقات الموجهة بشكل أساسي للمحتوى أو النماذج أو عمليات CRUD، يقدم Capacitor نتائج بجودة أصلية بجزء صغير من الجهد المطلوب للتطوير الأصلي الكامل. للألعاب كثيفة GPU أو التطبيقات التي تحتاج تكاملاً عميقاً مع المنصة، قد يكون التطوير الأصلي أو React Native أنسب.
ابدأ بتطبيق React الموجود لديك، أضف Capacitor، وانشر على كلا المتجرين — كل ذلك من قاعدة كود واحدة.
ناقش مشروعك معنا
نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.
دعنا نجد أفضل الحلول لاحتياجاتك.
مقالات ذات صلة

بناء تطبيق موبايل متعدد المنصات باستخدام Expo و React Native و TypeScript في 2026
تعلّم كيفية بناء تطبيق موبايل جاهز للإنتاج من الصفر باستخدام Expo SDK 52 و React Native و TypeScript. يغطي هذا الدليل التوجيه القائم على الملفات، واجهات البرمجة الأصلية، إدارة الحالة، والنشر على App Store و Google Play.

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

إضافة المصادقة لتطبيق Next.js 15 باستخدام Auth.js v5: البريد الإلكتروني وOAuth والتحكم بالأدوار
تعلم كيفية إضافة نظام مصادقة جاهز للإنتاج لتطبيق Next.js 15 باستخدام Auth.js v5. يغطي هذا الدليل الشامل تسجيل الدخول عبر Google OAuth وبيانات الاعتماد بالبريد الإلكتروني وكلمة المرور والمسارات المحمية والتحكم بالوصول حسب الأدوار.