الحلقة 5: التفاعل والاستجابة — ما وراء التنبيه العرفي
إرسال الإشعار هو نصف المعركة فقط. القوة الحقيقية للتفاعل تكمن في ما يحدث بعد أن ينقر المستخدم على التنبيه. لا ينبغي للتطبيق الاحترافي أن يفتح الشاشة الرئيسية فحسب؛ بل يجب أن يوجه المستخدم إلى السياق الدقيق للإشعار — وهي عملية تُعرف باسم "الروابط العميقة" (Deep Linking).
في هذا الدرس، سنحترف:
- دورة حياة التطبيق: التعامل مع حالات المقدمة، الخلفية، وحالة الإغلاق التام (Killed).
- مستمعي الاستجابة للإشعارات: التقاط نقرات المستخدم في الوقت الفعلي.
- استخراج البيانات: سحب البيانات المخصصة (Payload) من الإشعار.
- مشكلة "البداية الباردة": التعامل مع التفاعلات عندما يكون التطبيق مغلقاً تماماً.
حالات التفاعل الثلاث
عندما يتفاعل المستخدم مع إشعار، قد يكون تطبيقك في واحدة من ثلاث حالات:
- المقدمة (Foreground): المستخدم يستخدم التطبيق بنشاط حالياً.
- الخلفية (Background): التطبيق مصغر ولكنه لا يزال في الذاكرة.
- الإغلاق التام (Killed): التطبيق لا يعمل على الإطلاق.
يجب أن يكون منطق الإشعارات الخاص بك قوياً بما يكفي للتعامل مع السيناريوهات الثلاثة لضمان تجربة "روابط عميقة" سلسة.
1. التقاط النقرات باستخدام المستمعين (Listeners)
الطريقة الأساسية لاكتشاف تفاعل المستخدم هي addNotificationResponseReceivedListener. من الناحية المثالية، يجب وضع هذا المستمع في أعلى مستوى من تطبيقك (مثل App.tsx أو مخطط الجذر).
index.tstypescriptimport * as Notifications from 'expo-notifications'; import { useEffect } from 'react'; export default function RootLayout() { useEffect(() => { // ينطلق هذا الكود عندما ينقر المستخدم على الإشعار const subscription = Notifications.addNotificationResponseReceivedListener(response => { const { screen, itemId } = response.notification.request.content.data; console.log(`نقر المستخدم على إشعار للشاشة: ${screen}`); // مثال: الانتقال لشاشة محددة if (screen === 'Details') { // navigation.navigate('Details', { id: itemId }); } }); return () => subscription.remove(); }, []); }
2. التعامل مع حالة الإغلاق التام (Cold Starts)
إذا كان التطبيق مغلقاً تماماً (Killed) عندما نقر المستخدم على الإشعار، فقد لا يكون المستمع الذي حددناه أعلاه جاهزاً في الوقت المناسب لالتقاط الحدث.
لحل هذه المشكلة، نستخدم getLastNotificationResponseAsync خلال مرحلة تهيئة التطبيق.
index.tstypescriptconst handleInitialNotification = async () => { const lastResponse = await Notifications.getLastNotificationResponseAsync(); if (lastResponse) { const data = lastResponse.notification.request.content.data; console.log("تم فتح التطبيق عبر نقرة إشعار:", data); // تنفيذ منطق الانتقال هنا } }; useEffect(() => { handleInitialNotification(); }, []);
3. استخراج البيانات "المخفية"
يمكن لكل إشعار أن يحمل كائناً من البيانات (data) بصيغة JSON. هذا هو المكان الذي تخزن فيه البيانات الوصفية اللازمة للانتقال، مثل المعرفات (IDs) أو الفئات أو الروابط.
index.tstypescript// عند الجدولة: content: { title: "رسالة جديدة", data: { url: "https://snabcode.com/blog/i18n", type: "external_link" } } // عند الاستلام: const url = response.notification.request.content.data.url; if (url) { Linking.openURL(url); }
التكامل مع نظام التنقل (Navigation)
لتنفيذ ميزة "الروابط العميقة" بشكل احترافي، يوصى باستخدام مرجع تنقل عالمي (Global Navigation Ref) أو خطاف (hook) مخصص لديه وصول إلى جهاز التوجيه الخاص بك (مثل useRouter في Expo Router).
النمط الاحترافي:
- الاستماع للاستجابة في مستوى الجذر (Root).
- التحقق من هيكل البيانات.
- الانتقال باستخدام نظام التوجيه الخاص بتطبيقك.
التحدي الخاص بك
عزز إشعار "التفكير اليومي" الخاص بك من الدرس السابق. قم بتنفيذ المنطق لاكتشاف متى ينقر المستخدم عليه واستخدم alert() لمحاكاة توجيهه إلى "شاشة تفكير" متخصصة بناءً على بيانات الإشعار.
“[!TIP] اختبر دائماً حالة "الإغلاق التام" عن طريق إغلاق تطبيقك يدوياً، وإرسال إشعار مجدول، ثم النقر عليه من قائمة التنبيهات في النظام. هذا هو المكان الذي تختبئ فيه معظم أخطاء الإشعارات!