مقدمة إلى تخزين البيانات المحلي في فلاتر
مقدمة إلى تخزين البيانات المحلي في فلاتر
تحتاج كل تطبيقات Flutter الحقيقية تقريباً إلى الاحتفاظ بالبيانات بين الجلسات. سواء كنت تحفظ تفضيلات المستخدم، أو تخزن مؤقتاً استجابات الـ API، أو تدير سلة تسوق، أو تعمل على قاعدة بيانات محلية من السجلات، فإن تخزين البيانات المحلي مهارة أساسية. لا تمتلك Flutter نظام تخزين واحداً مدمجاً — بدلاً من ذلك، توفر نظاماً بيئياً غنياً من الحزم المناسبة لأشكال البيانات وأحجامها ومتطلبات الأداء المختلفة.
في هذا الدرس ستستعرض المشهد الكامل لخيارات التخزين المتاحة لمطوري Flutter، وتفهم المقايضات بينها، وتتعلم كيفية اختيار الأداة المناسبة لأي متطلب معين.
خيارات التخزين المحلي الرئيسية
يختار مطورو Flutter عادةً من ست فئات من التخزين المحلي:
- SharedPreferences — أزواج مفتاح-قيمة خفيفة الوزن للإعدادات البسيطة
- SQLite (عبر sqflite) — محرك قاعدة بيانات علائقية كاملة للبيانات المنظمة
- Hive — مخزن مفتاح-قيمة / صندوق NoSQL سريع مع محولات الأنواع الاختيارية
- Drift (المعروف سابقاً بـ Moor) — غلاف SQLite تفاعلي آمن من حيث الأنواع مع DSL بلغة Dart
- File / Path Provider — إدخال/إخراج ملفات خام لأي بيانات ثنائية أو نصية
- Flutter Secure Storage — تخزين مفتاح-قيمة مشفر مدعوم بسلسلة مفاتيح المنصة
SharedPreferences
SharedPreferences (الحزمة: shared_preferences) تغلف SharedPreferences الخاصة بنظام Android وNSUserDefaults الخاصة بنظام Apple. تخزن خريطة مسطحة من الأنواع البدائية (bool، int، double، String، List<String>) مُسلسلة على القرص كـ XML أو قائمة خصائص.
SharedPreferences — قراءة وكتابة
import 'package:shared_preferences/shared_preferences.dart';
Future<void> saveTheme(String theme) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('theme', theme);
}
Future<String> loadTheme() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('theme') ?? 'light';
}
الأفضل لـ: تفضيلات المستخدم (السمة، اللغة، علامات التأهيل، الإصدار الأخير المشاهد). تجنب تخزين الكائنات الكبيرة أو المجموعات أو البيانات الحساسة هنا — فهو غير مشفر وغير مصمم للاستعلام.
SQLite عبر sqflite
تضع حزمة sqflite محرك SQLite مباشرةً داخل حزمة التطبيق. تكتب SQL خاماً أو تستخدم أساليب مساعدة لإدارة الجداول والفهارس والمعاملات. إنه الخيار الصحيح عندما تكون بياناتك علائقية بطبيعتها — مثل جهات الاتصال والمهام والسجلات المالية ذات علاقات المفاتيح الخارجية.
sqflite — فتح قاعدة بيانات وإدراج صف
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
Future<Database> openAppDatabase() async {
final dbPath = await getDatabasesPath();
return openDatabase(
join(dbPath, 'app.db'),
version: 1,
onCreate: (db, version) async {
await db.execute('''
CREATE TABLE tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
done INTEGER NOT NULL DEFAULT 0
)
''');
},
);
}
Future<void> insertTask(Database db, String title) async {
await db.insert('tasks', {'title': title, 'done': 0});
}
الأفضل لـ: البيانات العلائقية المنظمة، والاستعلامات المعقدة باستخدام JOIN أو GROUP BY، والبيانات التي تحتاج إلى فهرسة للبحث السريع. المقايضة: تكتب سلاسل SQL خاماً (عرضة للأخطاء) وتدير عمليات الترحيل يدوياً.
Hive
Hive (الحزمة: hive_flutter) مخزن NoSQL خفيف الوزن مكتوب بلغة Dart الخالصة. تعيش البيانات في صناديق مكتوبة (فكر فيها كمجموعات). باستخدام TypeAdapter يمكنك تسلسل فئات Dart الخاصة بك مباشرةً. يُعدّ Hive أسرع بكثير من SQLite لعمليات القراءة والكتابة البسيطة لأنه يعمل كمخزن في الذاكرة مدعوم بملفات ثنائية — بدون عبء تحليل SQL.
الأفضل لـ: تخزين الكائنات مؤقتاً، والتطبيقات التي تعمل أولاً دون اتصال، والتفضيلات الأغنى من الأنواع البدائية. المقايضة: لا توجد استعلامات علائقية؛ ربط البيانات عبر الصناديق يتم في كود Dart.
Drift (المعروف سابقاً بـ Moor)
Drift يجلس فوق SQLite لكنه يستبدل سلاسل SQL الخاماً بـ DSL Dart آمن من حيث الأنواع يُولَّد وقت البناء. تُكتشف التغييرات في المخطط وقت الترجمة، لا في وقت التشغيل. كما يدعم الاستعلامات التفاعلية — Stream يُصدر قائمة جديدة في كل مرة يتغير فيها الجدول الأساسي — مما يتكامل بشكل طبيعي مع StreamBuilder في Flutter.
الأفضل لـ: التطبيقات المتوسطة إلى الكبيرة التي تحتاج قوة SQLite لكنها تريد الأمان وقت الترجمة والتفاعلية. المقايضة: يضيف توليد الكود إلى خط أنابيب البناء (build_runner).
File / Path Provider
للبيانات التي لا تناسب نموذج المفتاح-القيمة أو الجداول — الصور وملفات PDF والتسجيلات الصوتية وتصدير JSON — تكتب مباشرةً إلى نظام الملفات باستخدام dart:io وتحدد المجلدات باستخدام path_provider. توفر الحزمة مواقع صحيحة للمنصة مثل مجلد المستندات ومجلد ذاكرة التخزين المؤقت المؤقتة.
الأفضل لـ: الملفات الثنائية والكتل النصية الكبيرة والمحتوى الذي ينشئه المستخدم والتقارير التي يولدها التطبيق. المقايضة: أنت مسؤول عن كل منطق التسلسل والإصدار والتنظيف.
Flutter Secure Storage
Flutter Secure Storage (الحزمة: flutter_secure_storage) تخزن أزواج المفتاح-القيمة مشفرةً بـ AES على نظام Android (عبر EncryptedSharedPreferences أو Android Keystore) ومخزنة في iOS/macOS Keychain. لا تُكتب القيم أبداً على القرص بنص عادي.
الأفضل لـ: الرموز المميزة وكلمات المرور وأرقام PIN ومفاتيح API ورموز التحديث — أي شيء سيكون حادثة أمنية إذا استُخرج من الجهاز. المقايضة: أبطأ من SharedPreferences؛ يتعامل فقط مع قيم String.
اختيار خيار التخزين المناسب
استخدم دليل القرار هذا عند اختيار خلفية التخزين:
- إعدادات بسيطة (bool، int، String)؟ → SharedPreferences
- بيانات اعتماد أو رموز مميزة حساسة؟ → Flutter Secure Storage
- بيانات علائقية مع استعلامات SQL؟ تحتاج أماناً وقت الترجمة؟ → Drift
- بيانات علائقية، مرتاح مع SQL الخام؟ → sqflite
- رسم بياني للكائنات، تحتاج سرعة، لا استعلامات معقدة؟ → Hive
- ملفات ثنائية، صور، كتل عشوائية؟ → File + path_provider
مقارنة سريعة
يلخص الجدول أدناه الأبعاد الرئيسية عبر جميع الخيارات الستة:
| الخيار | نموذج البيانات | مشفر | تفاعلي | التعقيد |
|---|---|---|---|---|
| SharedPreferences | مفتاح-قيمة (أنواع بدائية) | لا | لا | منخفض |
| Secure Storage | مفتاح-قيمة (String) | نعم | لا | منخفض |
| Hive | مفتاح-قيمة / كائنات | اختياري | ValueListenable | متوسط |
| sqflite | علائقي (SQL) | لا | لا | متوسط |
| Drift | علائقي (Dart DSL) | لا | Stream | متوسط-عالي |
| File / path_provider | بايتات خام / نص | يدوي | لا | متفاوت |
الخلاصة
يمنحك النظام البيئي للتخزين المحلي في Flutter أداةً لكل سيناريو. SharedPreferences يتعامل مع الإعدادات البسيطة بسطر واحد من الكود. Flutter Secure Storage يؤمن القيم الحساسة باستخدام سلاسل مفاتيح المنصة. Hive يوفر استمرارية كائنات سريعة وبدون مخطط ثابت. sqflite يجلب كامل قوة SQL إلى جهازك. Drift يضيف أماناً وقت الترجمة والتفاعلية فوق SQLite. path_provider + dart:io يغطي أي احتياج قائم على الملفات. في الدروس القادمة ستنفذ كل خيار بكود حقيقي وتتعلم الأنماط المستخدمة في تطبيقات Flutter الاحترافية.