Command Palette

Search for a command to run...

Hướng dẫn tích hợp Push Notifications với React Native và Expo

Tích hợp Push Notifications với React Native và Expo

Có một sự thật tàn khốc trong thế giới Mobile App: Hơn 70% người dùng sẽ tải ứng dụng của bạn về, mở lên xem một lần, sau đó quên lãng nó mãi mãi ở một góc nào đó trên màn hình.

Làm thế nào để gọi họ quay lại? Làm sao để báo cho họ biết có một tin nhắn mới, một mã giảm giá cực sốc, hay một bài hướng dẫn leo rank vừa được cập nhật? Câu trả lời duy nhất và hiệu quả nhất chính là: Push Notifications.

Trong bài học này, chúng ta sẽ đập tan định kiến "làm thông báo đẩy rất khó" bằng cách tận dụng hệ thống siêu việt của Expo. Không cần cấu hình Firebase rắc rối ngay từ đầu, không cần đụng chạm vào code Native của Apple hay Google, bạn sẽ gửi được thông báo đầu tiên chỉ sau 15 phút!

1. Cơ chế hoạt động của Push Notifications

Trước khi gõ code, bạn cần hiểu luồng đi của một thông báo. Nó không hề đơn giản là việc App tự nháy lên.

Cơ chế hoạt động của Push Notifications

Quá trình này bao gồm 3 trạm trung chuyển:

  1. Lấy Token: Khi người dùng mở app và cho phép nhận thông báo, điện thoại sẽ kết nối với máy chủ của Apple (APNs) hoặc Google (FCM) để xin một dãy mã định danh duy nhất (gọi là Push Token). Mỗi điện thoại cài app của bạn sẽ có một mã riêng biệt.
  2. Lưu trữ: Ứng dụng của bạn lấy được Token đó và gửi lên Backend (Máy chủ Database của bạn) để cất đi.
  3. Phát lệnh: Khi bạn muốn gửi tin báo khuyến mãi, Backend của bạn sẽ cầm nội dung tin nhắn + mã Token đó gửi cho hệ thống phân phối của Expo. Expo sẽ tự động dịch ngôn ngữ ra chuẩn của Apple/Google và bắn thẳng xuống điện thoại người dùng.

⚠️ LƯU Ý: Thông báo đẩy KHÔNG hoạt động trên máy ảo iOS Simulator. Bạn bắt buộc phải dùng điện thoại thật có cài Expo Go để thực hành bài này!

2. Cài đặt và cấu hình expo-notifications

Mở Terminal trong thư mục dự án của bạn và chạy lệnh cài đặt:

npx expo install expo-notifications expo-device expo-constants

expo-notifications

(Chúng ta cài thêm expo-device để kiểm tra xem người dùng có đang dùng điện thoại thật hay không, vì máy ảo không tạo được Token).

Tiếp theo, hãy thiết lập hành vi mặc định của thông báo khi ứng dụng đang được mở (Foreground). Đặt đoạn code này ở file gốc của ứng dụng (thường là app/_layout.tsx hoặc App.js), NẰM NGOÀI component chính:

import * as Notifications from 'expo-notifications'

// Thiết lập: Nếu app đang mở mà có thông báo tới, thì phải làm gì?
Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true, // Vẫn hiển thị popup thông báo
    shouldPlaySound: true, // Phát âm thanh
    shouldSetBadge: false, // Không đổi số phù hiệu trên icon app
  }),
})

3. Viết hàm cấp quyền và lấy Expo Push Token

Bây giờ, chúng ta sẽ tạo một nút bấm để xin quyền người dùng và lấy mã Token quyền lực đó.

Hãy tạo một màn hình NotificationScreen.tsx và nhập đoạn code sau:

import React, { useState, useEffect } from 'react'
import { View, Text, TouchableOpacity, StyleSheet, Alert, Platform } from 'react-native'
import * as Notifications from 'expo-notifications'
import * as Device from 'expo-device'
import Constants from 'expo-constants'

export default function NotificationScreen() {
  const [expoPushToken, setExpoPushToken] = useState('')

  // Hàm cốt lõi để đăng ký và lấy Token
  async function registerForPushNotificationsAsync() {
    let token

    // 1. Kiểm tra xem có phải điện thoại thật không
    if (Device.isDevice) {
      // 2. Kiểm tra quyền hiện tại
      const { status: existingStatus } = await Notifications.getPermissionsAsync()
      let finalStatus = existingStatus

      // 3. Nếu chưa có quyền, bật popup xin phép (Bài học từ Bài 16)
      if (existingStatus !== 'granted') {
        const { status } = await Notifications.requestPermissionsAsync()
        finalStatus = status
      }

      // 4. Nếu người dùng từ chối, dừng lại
      if (finalStatus !== 'granted') {
        Alert.alert('Thất bại', 'Bạn chưa cấp quyền nhận thông báo!')
        return
      }

      // 5. Nếu đồng ý, tiến hành lấy Expo Push Token
      const projectId = Constants.expoConfig?.extra?.eas?.projectId ?? Constants.easConfig?.projectId
      token = (await Notifications.getExpoPushTokenAsync({ projectId })).data

      console.log('Token của bạn là:', token)
      setExpoPushToken(token)
    } else {
      Alert.alert('Lỗi', 'Phải dùng điện thoại thật để lấy Push Token!')
    }

    // 6. Cấu hình Channel cho Android 8.0 trở lên (Bắt buộc)
    if (Platform.OS === 'android') {
      Notifications.setNotificationChannelAsync('default', {
        name: 'default',
        importance: Notifications.AndroidImportance.MAX,
        vibrationPattern: [0, 250, 250, 250],
        lightColor: '#FF231F7C',
      })
    }

    return token
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Quản Lý Thông Báo</Text>

      <TouchableOpacity style={styles.button} onPress={registerForPushNotificationsAsync}>
        <Text style={styles.buttonText}>🔔 Kích Hoạt & Lấy Token</Text>
      </TouchableOpacity>

      {expoPushToken ? (
        <View style={styles.tokenBox}>
          <Text style={styles.tokenLabel}>Token của bạn:</Text>
          <Text style={styles.tokenText} selectable={true}>
            {expoPushToken}
          </Text>
        </View>
      ) : null}
    </View>
  )
}

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 },
  title: { fontSize: 24, fontWeight: 'bold', marginBottom: 30 },
  button: { backgroundColor: '#00b894', padding: 15, borderRadius: 10 },
  buttonText: { color: '#fff', fontWeight: 'bold', fontSize: 16 },
  tokenBox: { marginTop: 30, padding: 15, backgroundColor: '#dfe6e9', borderRadius: 10, width: '100%' },
  tokenLabel: { fontWeight: 'bold', marginBottom: 5 },
  tokenText: { fontSize: 12, color: '#2d3436' },
})

Sau khi quét mã QR bằng Expo Go trên điện thoại thật và bấm nút, một mã định dạng như ExponentPushToken[xxxxxxxxxxxx] sẽ xuất hiện trên màn hình. Hãy copy nó!

4. Gửi lệnh bắn thông báo (Test)

Trong thực tế, việc bắn thông báo sẽ do Backend (NodeJS, Python, PHP...) của bạn đảm nhiệm. Nhưng để test ngay lúc này, Expo đã cung cấp một công cụ tuyệt vời.

Expo Push Notification Tool

  1. Bạn hãy truy cập vào trang: https://expo.dev/notifications
  2. Ở field To (Expo push token), hãy dán cái mã bạn vừa copy trên màn hình điện thoại vào.
  3. Ở field Message title: Nhập Tướng mới đã ra mắt!
  4. Ở field Message body: Nhập Katarina đã có cẩm nang cách khắc chế. Vào xem ngay!
  5. Bấm nút Send Notification.

BÙM! Ngay lập tức, điện thoại của bạn sẽ rung lên và thông báo sẽ thả xuống từ cạnh trên màn hình!

Lên lịch thông báo nội bộ (Local Notification)

Ngoài việc đẩy từ Server, bạn cũng có thể cài đặt app tự nhắc nhở người dùng (ví dụ: Báo thức, nhắc uống nước, nhắc vào điểm danh hàng ngày) mà không cần mạng.

const scheduleLocalNotification = async () => {
  await Notifications.scheduleNotificationAsync({
    content: {
      title: '⏰ Đã đến giờ luyện tập!',
      body: 'Hãy vào làm 1 trận khởi động tay nào.',
    },
    trigger: { seconds: 5 }, // Thông báo sẽ nổ sau 5 giây kể từ khi bấm
  })
}

Kết luận: Push Notifications là công cụ "phải có"

Bạn đã chính thức nắm giữ công cụ giữ chân người dùng mạnh mẽ nhất. Hệ thống expo-notifications giúp làm phẳng mọi sự khác biệt phức tạp giữa iOS và Android, cung cấp cho bạn một luồng đi đồng nhất và mượt mà:

  1. Xin quyền người dùng + Check điện thoại thật.
  2. Sinh ra mã ExpoPushToken.
  3. Gửi Token đó lên công cụ phân phối của Expo để bắn thông báo về máy.

Chúc mừng bạn đã hoàn thành xuất sắc phần lớn nội dung của series này. Ứng dụng của bạn bây giờ không chỉ là một cái vỏ giao diện, mà đã biết chụp ảnh, vẽ bản đồ và rung lên bần bật báo tin nhắn!

Tuy nhiên, nếu ứng dụng của bạn chỉ chạy tốt mà chuyển cảnh giật lag, hoặc bạn muốn đem nó ra cài đặt trực tiếp lên điện thoại người khác (không qua Expo Go) thì sao?

Hãy bước vào những bài học thú vị tiếp theo!

Bài viết liên quan

Học cách tạo ứng dụng Camera tùy chỉnh bằng React Native và Expo

Làm sao để người dùng đổi Avatar trong app? Học cách chọn ảnh từ máy, tự xây dựng giao diện chụp ảnh chuyên nghiệp và tải file lên server với React Native và Expo.

Hướng dẫn xin quyền truy cập (Permissions) trong React Native

Hướng dẫn chi tiết cách xin quyền (Permissions) trên thiết bị mobile với React Native & Expo. Nắm vững cách dùng expo-location và Linking để xử lý khi bị từ chối.

Hướng dẫn cách dùng React Native Maps: Hiển thị bản đồ & Lấy tọa độ GPS

Hướng dẫn hiển thị bản đồ trong React Native bằng thư viện react-native-maps. Tìm hiểu cách ghim vị trí (Marker) và tích hợp GPS theo thời gian thực.

Hướng dẫn cài đặt môi trường React Native & Expo trong 15 phút

Bạn sợ cài đặt môi trường lập trình mobile phức tạp? Hướng dẫn chi tiết cách dùng Expo Go, Node.js để chạy app React Native ngay lập tức.