Push Notifications ו-Deep Links

📚 פיתוח Mobile ⏱️ 10 דק׳ 🎓 בינוני ✓ חינם לגמרי
Push Notifications ו-Deep Links

למה Push Notifications ו-Deep Links חשובים עכשיו יותר מתמיד

65% מהמשתמשים שמקבלים push notification חוזרים לאפליקציה תוך שעה. בלי notification, הם פשוט לא חוזרים. אבל זה לא רק לשלוח הודעה: notification שמוביל למסך הביתי הריק, במקום ישירות למוצר שעניין את המשתמש, מאבד את ה-conversion לחלוטין. Deep links הם הגשר בין ה-notification לתוכן הנכון. והטכנולוגיה השתנתה: ב-2024 Google סגרה את FCM Legacy API, כל קוד שלא עודכן ל-FCM v1 פשוט הפסיק לעבוד. שיעור זה מלמד לבנות את שני המנגנונים נכון, עם Claude כ-debugging partner.

ארכיטקטורת Notifications, מה קורה מאחורי הקלעים

לפני שכותבים שורת קוד, חשוב להבין את הזרימה. ישנן שלוש שכבות:

טעות נפוצה: מפתחים רבים גילו ב-2024 שה-notifications שלהם הפסיקו לעבוד בלי התראה. הסיבה: FCM legacy API נסגר. אם לא עברתם ל-FCM v1 credentials ב-EAS, שום notification Android לא יגיע.

Prompt לSetup מלא עם Expo Notifications

הפרומפט הבא מייצר setup end-to-end שמכסה את כל ה-edge cases:

תעזור לי לsetup push notifications ב-React Native
You are a React Native push notifications expert. Set up expo-notifications for a production app targeting iOS 15+ and Android 8+ with 500K DAU. Requirements: 1. Permission request: show custom rationale UI before the OS dialog (increases grant rate from ~40% to ~70%) 2. Token registration: detect simulator vs real device, get Expo push token (SDK 53+, no experienceId needed), save to /api/push-token with { token, platform, appVersion, userId } 3. Android: create notification channel 'orders' with importance HIGH before requesting permission 4. Three listener types: - Foreground: show in-app toast, suppress OS notification - Background tap: navigate by response.notification.request.content.data.screen - Cold start (quit state): handle via Linking.getInitialURL() in App.tsx 5. Token refresh: listen with addPushTokenListener and re-save on token change TypeScript, no 'any'. Comment every non-obvious line.

Deep Links, Custom Scheme לעומת Universal Links

ישנם שני סוגי deep links, וחשוב לדעת מתי להשתמש בכל אחד:

סוגדוגמהיתרוןחיסרון
Custom Schememyapp://product/123פשוט להגדיר, עובד גם offlineכל app יכול לregister אותו, אין security. אם האפליקציה לא מותקנת, כישלון.
Universal Links (iOS)https://store.co.il/product/123מאומת בserver, נופל ל-Safari אם לא מותקןדורש apple-app-site-association על ה-server, מחזיר 200 עם Content-Type: application/json בלי redirect
App Links (Android)https://store.co.il/product/123זהה ל-Universal Linksדורש assetlinks.json ב-/.well-known/

הסטנדרט ב-2025: שמרו custom scheme כ-fallback, והשתמשו ב-Universal Links/App Links כברירת מחדל. אם חנות ישראלית של סטארטאפ ת"א רוצה שלקוח שקיבל SMS עם לינק יגיע ישירות לעמוד המוצר, Universal Link הוא הפתרון.

Prompt להגדרת Deep Links עם React Navigation

Claude מייצר את כל הקבצים הנדרשים בבקשה אחת:

Configure deep links for React Native with React Navigation v6.

Schemes:
- Custom scheme: myapp://
- Universal Links iOS: https://app.mystore.co.il (needs apple-app-site-association)
- App Links Android: https://app.mystore.co.il (needs assetlinks.json)

Paths:
- /product/:productId → ProductDetailScreen
- /order/:orderId → OrderTrackingScreen
- /promo/:code → HomeScreen with promo modal
- /chat/:userId → ChatScreen
- / → HomeScreen

Generate:
1. linking config for React Navigation
2. apple-app-site-association JSON
3. assetlinks.json for Android
4. Test commands: xcrun simctl and adb for verification
5. Cold start handler in App.tsx using Linking.getInitialURL()

Cold Start, הבאג שכולם נתקלים בו

כשמשתמש מקבל notification כשהאפליקציה סגורה לחלוטין, מה שנקרא "quit state", ה-addNotificationResponseReceivedListener לא מופעל. הפתרון:

// App.tsx, בתוך useEffect לפני שNavigation mount
useEffect(() => {
  // Cold start: notification tap when app was quit
  Notifications.getLastNotificationResponseAsync().then(response => {
    if (response?.notification.request.content.data?.screen) {
      // Queue navigation, navigation may not be ready yet
      setTimeout(() => {
        navigationRef.current?.navigate(
          response.notification.request.content.data.screen
        );
      }, 300); // 300ms delay to ensure navigation is mounted
    }
  });

  // Cold start: deep link when app was quit
  Linking.getInitialURL().then(url => {
    if (url) handleDeepLink(url);
  });
}, []);

שימו לב: ב-Android יש race condition ידוע, Linking.getInitialURL() יכולה לחזור null אם ה-JS thread עוד לא מוכן. ה-timeout של 300ms פותר זאת ברוב המקרים.

טעויות נפוצות

Custom scheme הוא iOS בלבד; Universal Links עובדים בiOS ובAndroid
Custom scheme (myapp://) לא מאומת, כל app יכול לreg אותו. Universal Links (https://) מחייבים אימות על ה-server
Universal Links עובדים רק עם HTTP
Custom schemes לא נתמכים ב-React Navigation v6
Apple מחייבת rationale לפי App Store Review Guidelines
iOS שואל פעם אחת בלבד, rationale מסביר את הערך ומעלה שיעור האישור
נדרש לעמידה ב-GDPR
נדרש רק ב-Android 13+
השתמשו ב-addNotificationReceivedListener עם try/catch
הוסיפו setTimeout(3000) לפני כל navigation
השתמשו ב-getLastNotificationResponseAsync() ו-getInitialURL() ב-App.tsx עם setTimeout 300ms
שמרו את ה-deep link ב-AsyncStorage ובדקו ב-app open

סיכום

רוצה ללמוד עם מעקב התקדמות, קוויזים ותעודה?

כל 130 השיעורים פתוחים בחינם, כולל נגן אינטראקטיבי, שמירת התקדמות ותעודה דיגיטלית בסיום.