Skip to content

推送通知

1. 推送通知简介

推送通知是移动应用中非常重要的功能,它允许应用在后台向用户发送消息,即使应用没有被打开。推送通知可以用于:

  • 提醒用户新消息或更新
  • 发送重要的系统通知
  • 推广活动和促销信息
  • 提醒用户完成未完成的操作
  • 提供个性化的内容推荐

在 React Native 中,实现推送通知通常有两种方式:

  1. 本地通知:由应用本身触发,不需要服务器
  2. 远程推送通知:由服务器发送,通过苹果的 APNs (Apple Push Notification service) 或 Google 的 FCM (Firebase Cloud Messaging)

2. 本地通知

2.1 安装依赖

我们可以使用 @react-native-community/push-notification-iosreact-native-push-notification 库来实现本地通知:

bash
npm install @react-native-community/push-notification-ios react-native-push-notification
# 或
npx expo install @react-native-community/push-notification-ios

2.2 配置

iOS 配置

  1. ios/Podfile 中添加:
ruby
pod 'PushNotificationIOS', :path => '../node_modules/@react-native-community/push-notification-ios'
  1. 运行 pod install

  2. AppDelegate.m 中添加推送通知相关代码

Android 配置

  1. android/app/src/main/AndroidManifest.xml 中添加:
xml
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application ...>
  <receiver
    android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver"
    android:exported="false">
    <intent-filter>
      <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
  </receiver>
  <receiver
    android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationReceiver"
    android:exported="false">
    <intent-filter>
      <action android:name="com.google.android.c2dm.intent.RECEIVE" />
      <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
      <action android:name="com.google.android.gcm.intent.RETRY" />
      <action android:name="com.dieam.reactnativepushnotification.notification.RECEIVED" />
      <action android:name="com.dieam.reactnativepushnotification.notification.OPEN" />
      <action android:name="com.dieam.reactnativepushnotification.notification.DELETE" />
    </intent-filter>
  </receiver>
  <service
    android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
    android:exported="false">
    <intent-filter>
      <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
  </service>
</application>
  1. android/app/build.gradle 中添加:
txt
dependencies {
  // ...
  implementation 'com.google.firebase:firebase-messaging:21.1.0'
}

2.3 基本使用

javascript
import React, { useEffect } from 'react';
import { View, Button, Platform } from 'react-native';
import PushNotification from 'react-native-push-notification';

const App = () => {
  // 配置推送通知
  useEffect(() => {
    // 配置推送通知
    PushNotification.configure({
      // 当应用在前台时收到通知
      onNotification: function(notification) {
        console.log('NOTIFICATION:', notification);
        
        // 处理通知点击
        if (notification.userInteraction) {
          console.log('用户点击了通知');
        }
      },
      
      // 仅 iOS: 本地通知权限
      requestPermissions: Platform.OS === 'ios',
    });
  }, []);

  // 发送本地通知
  const sendLocalNotification = () => {
    PushNotification.localNotification({
      title: '测试通知',
      message: '这是一条本地通知',
      bigText: '这是通知的详细内容',
      subText: '副标题',
      color: '#FF0000',
      vibrate: true,
      vibration: 300,
      playSound: true,
      soundName: 'default',
      actions: ['查看', '关闭'],
    });
  };

  // 发送延迟通知
  const scheduleNotification = () => {
    PushNotification.localNotificationSchedule({
      title: '延迟通知',
      message: '5秒后发送的通知',
      date: new Date(Date.now() + 5 * 1000),
      repeatType: 'day', // 每天重复
    });
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Button title="发送本地通知" onPress={sendLocalNotification} />
      <Button title="发送延迟通知" onPress={scheduleNotification} />
    </View>
  );
};

export default App;

3. 远程推送通知

3.1 使用 Firebase Cloud Messaging (FCM)

3.1.1 安装依赖

bash
npm install @react-native-firebase/app @react-native-firebase/messaging
# 或
npx expo install @react-native-firebase/app @react-native-firebase/messaging

3.1.2 配置 Firebase

  1. 登录 Firebase 控制台
  2. 创建一个新项目
  3. 为 iOS 和 Android 添加应用
  4. 下载配置文件:
    • iOS: GoogleService-Info.plist
    • Android: google-services.json

3.1.3 集成配置

iOS 配置
  1. GoogleService-Info.plist 添加到 ios/ 目录
  2. Podfile 中添加:
ruby
pod 'Firebase/Messaging'
  1. 运行 pod install

  2. AppDelegate.m 中添加:

objective-c
@import Firebase;

// 在 didFinishLaunchingWithOptions 方法中
[FIRApp configure];
  1. 在 Xcode 中启用推送通知:
    • 打开项目 -> Capabilities -> Push Notifications -> 启用
Android 配置
  1. google-services.json 添加到 android/app/ 目录

  2. android/build.gradle 中添加:

txt
buildscript {
  dependencies {
    // ...
    classpath 'com.google.gms:google-services:4.3.10'
  }
}
  1. android/app/build.gradle 末尾添加:
txt
apply plugin: 'com.google.gms.google-services'

3.2 基本使用

javascript
import React, { useEffect } from 'react';
import { View, Text } from 'react-native';
import messaging from '@react-native-firebase/messaging';

const App = () => {
  useEffect(() => {
    // 请求通知权限
    const requestPermission = async () => {
      const authStatus = await messaging().requestPermission();
      const enabled = authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
                     authStatus === messaging.AuthorizationStatus.PROVISIONAL;
      
      if (enabled) {
        console.log('通知权限已授予');
      }
    };

    requestPermission();

    // 获取设备令牌
    messaging().getToken().then(token => {
      console.log('设备令牌:', token);
      // 将令牌发送到服务器
    });

    // 监听前台通知
    const unsubscribe = messaging().onMessage(async remoteMessage => {
      console.log('收到前台通知:', remoteMessage);
    });

    // 监听通知点击
    messaging().onNotificationOpenedApp(remoteMessage => {
      console.log('用户点击了通知:', remoteMessage);
    });

    // 检查应用是否通过点击通知打开
    messaging().getInitialNotification().then(remoteMessage => {
      if (remoteMessage) {
        console.log('应用通过通知打开:', remoteMessage);
      }
    });

    return unsubscribe;
  }, []);

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>推送通知示例</Text>
    </View>
  );
};

export default App;

4. 高级配置

4.1 通知渠道(Android)

Android 8.0+ 要求为通知设置渠道:

javascript
import PushNotification from 'react-native-push-notification';

// 创建通知渠道
if (Platform.OS === 'android') {
  PushNotification.createChannel(
    {
      channelId: 'default-channel-id',
      channelName: '默认通知渠道',
      channelDescription: '默认的通知渠道',
      importance: 4,
      vibrationPattern: [0, 250, 250, 250],
      lightColor: '#FF231F7C',
    },
    (created) => console.log(`通知渠道创建结果: ${created}`)
  );
}

// 使用渠道发送通知
PushNotification.localNotification({
  channelId: 'default-channel-id',
  title: '测试通知',
  message: '这是一条带有渠道的通知',
});

4.2 通知样式

javascript
// 大图样式
PushNotification.localNotification({
  title: '图片通知',
  message: '这是一条带有图片的通知',
  bigPictureUrl: 'https://example.com/image.jpg',
  bigLargeIconUrl: 'https://example.com/icon.jpg',
  largeIconUrl: 'https://example.com/icon.jpg',
});

// 列表样式
PushNotification.localNotification({
  title: '列表通知',
  message: '这是一条列表通知',
  bigText: '项目 1\n项目 2\n项目 3',
});

4.3 通知分组

javascript
// 分组通知
PushNotification.localNotification({
  title: '分组通知 1',
  message: '这是分组通知的第一条',
  group: 'group-1',
  groupSummary: true,
});

PushNotification.localNotification({
  title: '分组通知 2',
  message: '这是分组通知的第二条',
  group: 'group-1',
});

5. 实际应用场景

5.1 消息通知

javascript
// 收到新消息时发送通知
const sendMessageNotification = (sender, message) => {
  PushNotification.localNotification({
    title: `新消息来自 ${sender}`,
    message: message,
    soundName: 'default',
    vibrate: true,
  });
};

5.2 提醒通知

javascript
// 日程提醒
const scheduleReminder = (title, time) => {
  PushNotification.localNotificationSchedule({
    title: '日程提醒',
    message: title,
    date: time,
    repeatType: 'none',
  });
};

5.3 促销通知

javascript
// 促销活动通知
const sendPromotionNotification = (offer) => {
  PushNotification.localNotification({
    title: '限时优惠',
    message: offer,
    actions: ['查看详情', '忽略'],
    vibrate: true,
    soundName: 'default',
  });
};

6. 最佳实践

  1. 权限处理

    • 仅在必要时请求通知权限
    • 解释为什么需要通知权限
    • 提供设置选项让用户控制通知
  2. 通知内容

    • 保持通知简洁明了
    • 提供有价值的信息
    • 避免发送过多通知
  3. 用户体验

    • 为不同类型的通知使用不同的声音和振动模式
    • 提供通知操作按钮
    • 确保通知在不同设备上显示一致
  4. 性能考虑

    • 避免在通知中包含过多数据
    • 合理安排通知的发送时间
    • 清理不再需要的通知
  5. 安全考虑

    • 不要在通知中包含敏感信息
    • 验证通知的来源
    • 保护设备令牌

7. 常见问题与解决方案

7.1 通知不显示

问题:发送通知后,设备上没有显示通知

解决方案

  • 检查应用是否有通知权限
  • 检查通知渠道配置(Android 8.0+)
  • 检查设备的通知设置
  • 检查应用是否在前台运行

7.2 远程通知接收失败

问题:服务器发送的远程通知没有收到

解决方案

  • 检查设备令牌是否正确
  • 检查 Firebase 配置是否正确
  • 检查网络连接
  • 检查通知 payload 格式是否正确

7.3 通知点击不响应

问题:点击通知后没有触发相应的操作

解决方案

  • 确保正确实现了通知点击监听器
  • 检查应用的导航逻辑
  • 确保应用能够处理通知数据

7.4 通知重复显示

问题:通知重复显示或多次触发

解决方案

  • 检查通知 ID 是否唯一
  • 确保没有重复调用发送通知的方法
  • 检查服务器是否重复发送通知

8. 扩展阅读

9. 完整示例

javascript
// App.js
import React, { useEffect, useState } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import PushNotification from 'react-native-push-notification';
import messaging from '@react-native-firebase/messaging';

const App = () => {
  const [notificationToken, setNotificationToken] = useState('');
  const [lastNotification, setLastNotification] = useState(null);

  useEffect(() => {
    // 配置本地通知
    PushNotification.configure({
      onNotification: function(notification) {
        console.log('NOTIFICATION:', notification);
        setLastNotification(notification);
      },
      requestPermissions: true,
    });

    // 配置 Android 通知渠道
    if (Platform.OS === 'android') {
      PushNotification.createChannel(
        {
          channelId: 'default',
          channelName: '默认通知',
          channelDescription: '默认通知渠道',
          importance: 4,
          vibrationPattern: [0, 250, 250, 250],
          lightColor: '#FF231F7C',
        },
        (created) => console.log(`通知渠道创建: ${created}`)
      );
    }

    // 获取 FCM 令牌
    const getToken = async () => {
      try {
        const token = await messaging().getToken();
        setNotificationToken(token);
        console.log('FCM 令牌:', token);
      } catch (error) {
        console.error('获取令牌失败:', error);
      }
    };

    getToken();

    // 监听前台通知
    const unsubscribe = messaging().onMessage(async remoteMessage => {
      console.log('收到前台通知:', remoteMessage);
      setLastNotification(remoteMessage);
    });

    return unsubscribe;
  }, []);

  const sendLocalNotification = () => {
    PushNotification.localNotification({
      channelId: 'default',
      title: '本地通知',
      message: '这是一条本地通知',
      bigText: '这是通知的详细内容,点击查看更多',
      subText: '来自 React Native',
      color: '#FF0000',
      vibrate: true,
      vibration: 300,
      playSound: true,
      soundName: 'default',
      actions: ['查看', '关闭'],
    });
  };

  const scheduleNotification = () => {
    PushNotification.localNotificationSchedule({
      channelId: 'default',
      title: '定时通知',
      message: '这是一条 10 秒后发送的通知',
      date: new Date(Date.now() + 10 * 1000),
    });
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>推送通知示例</Text>
      
      <Text style={styles.subtitle}>FCM 令牌:</Text>
      <Text style={styles.token}>{notificationToken || '获取中...'}</Text>
      
      <Text style={styles.subtitle}>最近的通知:</Text>
      <Text style={styles.notification}>
        {lastNotification ? JSON.stringify(lastNotification, null, 2) : '暂无通知'}
      </Text>
      
      <View style={styles.buttons}>
        <Button title="发送本地通知" onPress={sendLocalNotification} />
        <Button title="发送定时通知" onPress={scheduleNotification} />
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
    textAlign: 'center',
  },
  subtitle: {
    fontSize: 16,
    fontWeight: 'bold',
    marginTop: 20,
    marginBottom: 10,
  },
  token: {
    fontSize: 14,
    backgroundColor: '#fff',
    padding: 10,
    borderRadius: 5,
    marginBottom: 10,
  },
  notification: {
    fontSize: 14,
    backgroundColor: '#fff',
    padding: 10,
    borderRadius: 5,
    marginBottom: 20,
    height: 150,
    overflow: 'scroll',
  },
  buttons: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    marginTop: 20,
  },
});

export default App;

这个示例展示了如何实现本地通知和远程推送通知,包括通知权限请求、令牌获取、通知发送和接收等功能。

© 2026 编程马·菜鸟教程 版权所有