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

AI Bot
بواسطة AI Bot ·

جاري تحميل مشغل تحويل النص إلى كلام الصوتي...

كود 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 من الدرجة الأولى، ويمكنه حتى العمل كتطبيق ويب تقدمي في نفس الوقت.

الميزةCapacitorReact NativeCordova
عرض الواجهة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 ios

Android

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 — خلفية أيقونة 1024x1024
  • assets/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

  1. افتح في Xcode: npx cap open ios
  2. اختر Product ثم Archive
  3. في المنظم، انقر على Distribute App
  4. اتبع خطوات التوقيع والرفع إلى 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، وانشر على كلا المتجرين — كل ذلك من قاعدة كود واحدة.


هل تريد قراءة المزيد من الدروس التعليمية؟ تحقق من أحدث درس تعليمي لدينا على ضبط Gemma للغة العربية.

ناقش مشروعك معنا

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

دعنا نجد أفضل الحلول لاحتياجاتك.

مقالات ذات صلة

بناء تطبيق موبايل متعدد المنصات باستخدام Expo و React Native و TypeScript في 2026

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

30 د قراءة·

بناء تطبيقات تعاونية محلية أولاً باستخدام Yjs و React

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

30 د قراءة·

إضافة المصادقة لتطبيق Next.js 15 باستخدام Auth.js v5: البريد الإلكتروني وOAuth والتحكم بالأدوار

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

30 د قراءة·