هيكل المشروع والتكوين
إنشاء مشروع Flutter جديد
تبدأ كل رحلة Flutter بإنشاء مشروع جديد. أمر flutter create ينشئ هيكل مشروع كامل بجميع الملفات والمجلدات اللازمة لبناء تطبيقات على منصات متعددة. دعنا نستكشف كيفية إنشاء مشروع وفهم كل ملف ومجلد يولده.
إنشاء مشروع باستخدام flutter create
# إنشاء مشروع أساسي
flutter create my_app
# إنشاء مع مؤسسة محددة (نطاق معكوس)
flutter create --org com.example my_app
# إنشاء لمنصات محددة فقط
flutter create --platforms android,ios,web my_app
# إنشاء مشروع بلغة محددة
flutter create --android-language kotlin --ios-language swift my_app
# إنشاء أنواع مختلفة من المشاريع
flutter create --template=app my_app # تطبيق كامل (افتراضي)
flutter create --template=package my_pkg # حزمة Dart
flutter create --template=plugin my_plugin # إضافة منصة
flutter create --template=module my_module # وحدة إضافة للتطبيق
my_app و flutter_todo صالحة، لكن MyApp و my-app و 123app غير صالحة.تخطيط مجلد المشروع
بعد تشغيل flutter create my_app، تحصل على مجلد مشروع بالهيكل التالي. فهم كل ملف ومجلد ضروري لتطوير Flutter الفعال.
هيكل المشروع الكامل
my_app/
+-- android/ # كود وتكوين خاص بـ Android
| +-- app/
| | +-- build.gradle # تكوين بناء التطبيق
| | +-- src/
| | +-- main/
| | +-- AndroidManifest.xml
| | +-- kotlin/... # كود Android الأصلي
| +-- build.gradle # تكوين بناء المشروع
| +-- settings.gradle # إعدادات Gradle
+-- ios/ # كود وتكوين خاص بـ iOS
| +-- Runner/
| | +-- AppDelegate.swift
| | +-- Info.plist # تكوين تطبيق iOS
| | +-- Assets.xcassets # أيقونات وصور التطبيق
| +-- Runner.xcworkspace # مساحة عمل Xcode
+-- lib/ # كود DART الخاص بك هنا
| +-- main.dart # نقطة دخول التطبيق
+-- test/ # اختبارات الوحدة والودجات
| +-- widget_test.dart # اختبار ودجة افتراضي
+-- web/ # ملفات خاصة بالويب
| +-- index.html # نقطة دخول الويب
| +-- manifest.json # بيان تطبيق الويب
+-- linux/ # ملفات سطح مكتب Linux
+-- macos/ # ملفات سطح مكتب macOS
+-- windows/ # ملفات سطح مكتب Windows
+-- pubspec.yaml # تكوين المشروع
+-- pubspec.lock # إصدارات الاعتماديات المقفلة
+-- analysis_options.yaml # قواعد محلل Dart
+-- .gitignore # قواعد تجاهل Git
+-- README.md # ملف readme المشروع
مجلد lib/
مجلد lib/ هو حيث يعيش كل كود Dart المصدري الخاص بك. هذا أهم مجلد في مشروعك. عندما ينمو مشروعك، ستنظم الكود في مجلدات فرعية هنا.
تنظيم lib/ النموذجي للمشاريع الأكبر
lib/
+-- main.dart # نقطة الدخول
+-- app.dart # تكوين MaterialApp
+-- config/ # تكوين التطبيق، السمات، المسارات
| +-- theme.dart
| +-- routes.dart
+-- models/ # نماذج البيانات
| +-- user.dart
| +-- product.dart
+-- screens/ # صفحات شاشة كاملة
| +-- home_screen.dart
| +-- profile_screen.dart
+-- widgets/ # ودجات قابلة لإعادة الاستخدام
| +-- custom_button.dart
| +-- product_card.dart
+-- services/ # استدعاءات API، قاعدة بيانات، إلخ
| +-- api_service.dart
| +-- auth_service.dart
+-- providers/ # إدارة الحالة
| +-- auth_provider.dart
+-- utils/ # دوال مساعدة وثوابت
+-- constants.dart
+-- helpers.dart
نقطة دخول main.dart
يبدأ كل تطبيق Flutter بملف main.dart داخل مجلد lib/. دالة main() هي نقطة دخول التطبيق، وتستدعي runApp() لبدء إطار عمل Flutter.
main.dart الافتراضي
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Text(
'\$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
فهم runApp()
تأخذ دالة runApp() ودجة وتجعلها جذر شجرة الودجات. تنفخ الودجة المعطاة وتربطها بالشاشة. تصبح هذه الودجة السلف الأعلى لجميع الودجات الأخرى في تطبيقك.
كيف يعمل runApp()
// يقوم runApp() بما يلي:
// 1. يأخذ الودجة الجذر (مثل MyApp())
// 2. ينشئ العنصر الجذر
// 3. يربطه بخط أنابيب العرض
// 4. يطلق أول دورة بناء/تخطيط/رسم
// 5. يعد حلقة الأحداث لتفاعلات المستخدم
void main() {
// يمكنك القيام بالتهيئة قبل runApp()
WidgetsFlutterBinding.ensureInitialized();
// مثلاً: تهيئة Firebase، تحميل التكوين، إلخ
// await Firebase.initializeApp();
runApp(const MyApp());
}
// أبسط تطبيق Flutter ممكن:
void main() {
runApp(
const Center(
child: Text(
'Hello, Flutter!',
textDirection: TextDirection.ltr,
),
),
);
}
ودجة MaterialApp
ودجة MaterialApp هي عادةً الودجة الجذر لتطبيق Flutter الذي يستخدم Material Design. تغلف عدة ودجات أساسية تحتاجها معظم التطبيقات: التنقل، التنسيق، التعريب، والمزيد.
تكوين MaterialApp
MaterialApp(
// هوية التطبيق
title: 'My App', // يستخدمه مبدل مهام النظام
debugShowCheckedModeBanner: false, // إزالة شارة التصحيح
// التنسيق
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
fontFamily: 'Roboto',
),
darkTheme: ThemeData.dark(useMaterial3: true),
themeMode: ThemeMode.system, // اتباع إعداد النظام
// التنقل
home: const HomeScreen(), // المسار الافتراضي
routes: {
'/home': (context) => const HomeScreen(),
'/profile': (context) => const ProfileScreen(),
'/settings': (context) => const SettingsScreen(),
},
// التعريب
locale: const Locale('en', 'US'),
supportedLocales: const [
Locale('en', 'US'),
Locale('ar', 'SA'),
],
// معالجة الأخطاء
builder: (context, child) {
return MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaler: TextScaler.noScaling,
),
child: child!,
);
},
)
CupertinoApp بدلاً من MaterialApp. لنظام تصميم مخصص بالكامل، استخدم WidgetsApp التي توفر الوظائف الأساسية بدون أي لغة تصميم.تعمق في pubspec.yaml
ملف pubspec.yaml هو قلب تكوين مشروع Flutter الخاص بك. يحدد اسم مشروعك واعتمادياته وأصوله وخطوطه والمزيد. فهم كل قسم أمر بالغ الأهمية.
مثال كامل على pubspec.yaml
name: my_app
description: A Flutter application for task management.
publish_to: 'none' # احذف هذا السطر إذا كنت تنشر على pub.dev
version: 1.0.0+1 # الإصدار: رئيسي.ثانوي.ترقيعي+رقم البناء
environment:
sdk: '>=3.2.0 <4.0.0' # قيد إصدار Dart SDK
dependencies:
flutter:
sdk: flutter
# حزم واجهة المستخدم
cupertino_icons: ^1.0.6 # أيقونات بنمط iOS
google_fonts: ^6.1.0 # تكامل خطوط Google
# إدارة الحالة
provider: ^6.1.1 # إدارة حالة بسيطة
flutter_bloc: ^8.1.3 # نمط BLoC
# الشبكات
http: ^1.2.0 # طلبات HTTP
dio: ^5.4.0 # عميل HTTP متقدم
# التخزين المحلي
shared_preferences: ^2.2.2 # تخزين مفتاح-قيمة
hive: ^2.2.3 # قاعدة بيانات NoSQL
# أدوات مساعدة
intl: ^0.19.0 # التدويل
url_launcher: ^6.2.2 # فتح عناوين URL
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.1 # قواعد الفحص
build_runner: ^2.4.7 # توليد الكود
mockito: ^5.4.4 # محاكاة الاختبار
flutter:
uses-material-design: true # تفعيل أيقونات Material
# إعلانات الأصول
assets:
- assets/images/ # مجلد كامل
- assets/icons/ # مجلد آخر
- assets/data/config.json # ملف محدد
# إعلانات الخطوط المخصصة
fonts:
- family: CustomFont
fonts:
- asset: assets/fonts/CustomFont-Regular.ttf
- asset: assets/fonts/CustomFont-Bold.ttf
weight: 700
- asset: assets/fonts/CustomFont-Italic.ttf
style: italic
قيود الإصدار
فهم قيود الإصدار
# صيغة إصدار الاعتماديات:
dependencies:
# صيغة الإقحام (موصى بها) - تسمح بتحديثات ثانوية وترقيعية
provider: ^6.1.1 # >=6.1.1 <7.0.0
# صيغة النطاق - نطاق صريح
http: '>=1.0.0 <2.0.0' # نفس ^1.0.0
# إصدار محدد (غير موصى به)
dio: 5.4.0 # بالضبط 5.4.0
# أي إصدار (خطير)
intl: any # أي إصدار، تجنب هذا!
# اعتمادية Git
my_package:
git:
url: https://github.com/user/repo.git
ref: main # فرع أو وسم أو hash commit
# اعتمادية مسار (حزمة محلية)
my_local_pkg:
path: ../my_local_pkg
إدارة الاعتماديات
أوامر إدارة الاعتماديات
# إضافة اعتمادية
flutter pub add provider
flutter pub add dio
# إضافة اعتمادية تطوير
flutter pub add --dev mockito
flutter pub add --dev build_runner
# إزالة اعتمادية
flutter pub remove provider
# جلب جميع الاعتماديات (تنزيلها)
flutter pub get
# ترقية الاعتماديات لأحدث إصدارات متوافقة
flutter pub upgrade
# فحص الحزم القديمة
flutter pub outdated
# حل تعارضات الاعتماديات
flutter pub upgrade --major-versions
^) لقيود الإصدار. تسمح بإصلاحات الأخطاء والتحديثات الثانوية مع منع التغييرات المكسرة. شغّل flutter pub outdated بانتظام للحفاظ على تحديث اعتمادياتك.التعامل مع الأصول
الأصول هي ملفات مجمّعة مع تطبيقك، مثل الصور والخطوط وملفات JSON وبيانات أخرى. يجب إعلانها في pubspec.yaml قبل استخدامها.
هيكل مجلد الأصول والاستخدام
# هيكل المجلد:
my_app/
+-- assets/
| +-- images/
| | +-- logo.png
| | +-- 2.0x/logo.png # دقة 2x
| | +-- 3.0x/logo.png # دقة 3x
| +-- icons/
| | +-- home.svg
| +-- data/
| +-- countries.json
# إعلان pubspec.yaml:
flutter:
assets:
- assets/images/
- assets/icons/
- assets/data/countries.json
# استخدام الأصول في كود Dart:
// الصور
Image.asset('assets/images/logo.png')
// بيانات JSON
final String jsonString = await rootBundle.loadString(
'assets/data/countries.json'
);
final data = json.decode(jsonString);
pubspec.yaml، يجب تشغيل flutter pub get وإجراء إعادة تشغيل سريع (وليس فقط إعادة تحميل سريع) لتفعيل التغييرات. لا يمكن لإعادة التحميل السريع اكتشاف إعلانات الأصول الجديدة.ملف .gitignore
ينشئ Flutter ملف .gitignore شامل يستبعد مخرجات البناء وملفات IDE والملفات المولدة الخاصة بالمنصة من التحكم بالإصدار.
إدخالات .gitignore المهمة
# خاص بـ Flutter/Dart
.dart_tool/ # ذاكرة تخزين أدوات Dart
.packages # تكوين حزم قديم
build/ # مجلد مخرجات البناء
.flutter-plugins # تسجيلات الإضافات المولدة
.flutter-plugins-dependencies
# خاص بـ IDE
.idea/ # Android Studio / IntelliJ
.vscode/ # VS Code (اختياري، بعض الفرق تتتبعه)
*.iml # ملفات وحدات IntelliJ
# مخرجات بناء المنصة
**/android/.gradle/
**/android/captures/
**/android/local.properties
**/ios/Pods/
**/ios/.symlinks/
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Flutter.podspec
# ملفات مولدة
*.g.dart # ملفات مولدة بـ build runner
*.freezed.dart # ملفات Freezed مولدة
*.mocks.dart # ملفات Mockito مولدة
pubspec.lock # ضمّنه للتطبيقات، استبعده للحزم
# ملفات حساسة
.env # متغيرات البيئة
*.jks # مخازن مفاتيح Java
*.keystore # مخازن مفاتيح Android
pubspec.lock في التحكم بالإصدار لضمان استخدام جميع أعضاء الفريق نفس إصدارات الاعتماديات. لـ حزم Flutter، لا تضمّن pubspec.lock حتى يتمكن المستهلكون من حل إصدارات اعتمادياتهم الخاصة.analysis_options.yaml
ملف analysis_options.yaml يكوّن محلل Dart، الذي يوفر التحليل الثابت والفحص وفحوصات جودة الكود. يساعد في اكتشاف الأخطاء وفرض معايير الترميز قبل تشغيل الكود.
تكوين analysis_options.yaml
include: package:flutter_lints/flutter.yaml
analyzer:
exclude:
- "**/*.g.dart" # استبعاد الملفات المولدة
- "**/*.freezed.dart"
errors:
invalid_annotation_target: ignore
missing_required_param: error # تعامل كخطأ
missing_return: error # تعامل كخطأ
language:
strict-casts: true # لا تحويلات ضمنية
strict-raw-types: true # لا أنواع عامة خام
linter:
rules:
# قواعد الأسلوب
- prefer_const_constructors
- prefer_const_declarations
- prefer_final_fields
- prefer_final_locals
- avoid_print # استخدم التسجيل بدلاً
- sort_constructors_first
- sort_unnamed_constructors_first
# قواعد السلامة
- always_declare_return_types
- avoid_dynamic_calls
- cancel_subscriptions
- close_sinks
# التوثيق
- public_member_api_docs: false # عطّل للتطبيقات
أساسيات build.gradle (Android)
ملفات build.gradle تكوّن عملية بناء Android. يوجد ملفان: ملف على مستوى المشروع وملف على مستوى التطبيق. نادراً ما تحتاج لتعديلهما، لكن فهمهما يساعد عند إضافة ميزات خاصة بـ Android.
أقسام android/app/build.gradle الرئيسية
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
android {
namespace "com.example.my_app"
compileSdk flutter.compileSdkVersion
defaultConfig {
applicationId "com.example.my_app" // معرف تطبيق فريد
minSdk flutter.minSdkVersion // الحد الأدنى لإصدار Android
targetSdk flutter.targetSdkVersion // إصدار Android المستهدف
versionCode 1 // رقم الإصدار الداخلي
versionName "1.0.0" // سلسلة إصدار العرض
}
buildTypes {
release {
signingConfig signingConfigs.debug // غيّره للإنتاج!
minifyEnabled true // تفعيل تقليص الكود
proguardFiles getDefaultProguardFile(
'proguard-android-optimize.txt'
), 'proguard-rules.pro'
}
}
}
flutter {
source '../..' // يشير إلى جذر مشروع Flutter
}
dependencies {
// اعتماديات خاصة بـ Android تذهب هنا
}
applicationId أو minSdk أو targetSdk في build.gradle، حدّث أيضاً القيم المقابلة في تكوين Flutter. applicationId هو ما يعرّف تطبيقك بشكل فريد على Google Play Store ويجب ألا يتغير أبداً بعد النشر.تشغيل وبناء تطبيقك
الآن بعد فهمك لهيكل المشروع، دعنا نراجع الأوامر الأساسية لتشغيل وبناء تطبيق Flutter.
أوامر Flutter الأساسية
# التشغيل في وضع التصحيح (مع إعادة التحميل السريع)
flutter run
# التشغيل على جهاز محدد
flutter devices # عرض الأجهزة المتاحة
flutter run -d chrome # التشغيل على Chrome
flutter run -d emulator-5554 # التشغيل على محاكي محدد
# التشغيل في وضع الإصدار
flutter run --release
# التشغيل في وضع التنميط (لتنميط الأداء)
flutter run --profile
# البناء للإنتاج
flutter build apk # Android APK
flutter build appbundle # Android App Bundle (لـ Play Store)
flutter build ios # iOS
flutter build web # الويب
flutter build windows # سطح مكتب Windows
flutter build macos # سطح مكتب macOS
flutter build linux # سطح مكتب Linux
# مسح ذاكرة التخزين المؤقت للبناء
flutter clean
# تحليل الكود للمشكلات
flutter analyze
الملخص
في هذا الدرس، تعلمت كيفية إنشاء مشروع Flutter باستخدام flutter create واستكشفت كل ملف ومجلد في هيكل المشروع المولّد. فهمت دور lib/ لكود Dart الخاص بك، و main.dart كنقطة دخول، و runApp() للتمهيد، و MaterialApp لتكوين التطبيق على مستوى واسع. أتقنت pubspec.yaml لإدارة الاعتماديات والأصول، وتعرفت على .gitignore للتحكم بالإصدار، و analysis_options.yaml لجودة الكود، و build.gradle لتكوين Android. أنت الآن جاهز لبدء بناء تطبيق Flutter بثقة.