在 Expo 应用中添加声音和振动通知

在 Expo 应用中添加声音和振动通知

本文档旨在指导开发者如何在 Expo 应用中集成声音和振动通知。我们将探讨如何利用 expo-av 播放声音以及使用 react-native 的 Vibration API 实现振动效果,并着重解决在特定时间触发通知的问题。同时,我们也关注权限处理,这是实现通知功能的关键环节。

集成声音通知

首先,确保你已经安装了 expo-av 依赖:

npx expo install expo-av

以下代码展示了如何播放声音:

import { useEffect, useState } from "react"; import { Audio } from 'expo-av'; import * as Notifications from 'expo-notifications'; import { Platform } from 'react-native';  async function schedulePushNotification() {   await Notifications.scheduleNotificationAsync({     content: {       title: "Reminder!",       body: 'It's time!',       sound: 'default', // Use 'default' for the default notification sound       data: { data: 'goes here' },     },     trigger: { seconds: 5, repeats: false }, // Schedule for 5 seconds from now   }); }  const useSound = () => {   const [sound, setSound] = useState(null);    useEffect(() => {     async function loadSound() {       try {         const { sound: soundObject } = await Audio.Sound.createAsync(           require('./assets/notification.mp3'), // 替换为你的音频文件路径           { shouldPlay: false } // 初始时不播放         );         setSound(soundObject);         console.log('Sound loaded successfully');          // Set audio mode to allow playing sound in silent mode (ios)         await Audio.setAudioModeAsync({           playsInSilentModeIOS: true,           staysActiveInBackground: true,           interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,           interruptionModeandroid: Audio.INTERRUPTION_MODE_ANDROID_DUCK_OTHERS,           shouldDuckAndroid: false,         });       } catch (error) {         console.error("Failed to load the sound", error);       }     }      loadSound();      return () => {       if (sound) {         sound.unloadAsync();       }     };   }, []);    const playSound = async () => {     if (sound) {       try {         await sound.replayAsync(); // Use replayAsync to play from the beginning         console.log('Playing Sound');       } catch (error) {         console.error("Failed to play the sound", error);       }     }   };    return { playSound }; };  export default function App() {   const { playSound } = useSound();    useEffect(() => {     // Schedule notification     schedulePushNotification();      // Configure notifications     async function configurePushNotifications() {       const { status } = await Notifications.getPermissionsAsync();       let finalStatus = status;        if (finalStatus !== 'granted') {         const { status } = await Notifications.requestPermissionsAsync();         finalStatus = status;       }        if (finalStatus !== 'granted') {         alert('Failed to get push token for push notification!');         return;       }        if (Platform.OS === 'android') {         Notifications.setNotificationChannelAsync('default', {           name: 'default',           importance: Notifications.AndroidImportance.MAX,           vibrationPattern: [0, 250, 250, 250],           lightColor: '#FF231F7C',         });       }     }      configurePushNotifications();   }, []);    useEffect(() => {     const subscription = Notifications.addNotificationReceivedListener(notification => {       console.log('Notification Received', notification);       playSound();     });      const responseListener = Notifications.addNotificationResponseReceivedListener(response => {       console.log('Notification Response', response);     });      return () => {       subscription.remove();       responseListener.remove();     };   }, [playSound]);    return (     // Your UI components here     null   ); }

关键点:

  • 使用 Audio.Sound.createAsync 加载音频文件。确保文件路径正确。
  • 使用 sound.playAsync() 播放声音。
  • 在组件卸载时,使用 sound.unloadAsync() 释放资源。
  • Notifications.setNotificationHandler 设置通知处理程序,允许播放声音。

注意: 音频文件需要放置在你的项目中,例如 assets 目录下。你需要替换 require(‘../assets/sonido.mp3’) 为你的实际文件路径。

集成振动通知

要添加振动效果,你需要从 react-native 导入 Vibration API:

import { Vibration } from 'react-native';

然后,你可以使用 Vibration.vibrate() 方法触发振动。你可以传递一个数字(毫秒)来指定振动持续时间,或者传递一个模式数组来定义振动和暂停的序列:

import { Vibration } from 'react-native';  const vibrate = () => {   Vibration.vibrate(); // 默认振动   //Vibration.vibrate(1000); // 振动 1 秒   //Vibration.vibrate([0, 500, 200, 500], true); // 自定义模式 (启动, 振动500ms, 暂停200ms, 振动500ms, 循环) };

关键点:

  • Vibration.vibrate() 触发振动。
  • 可以传递一个数字指定振动时长。
  • 可以传递一个数组定义振动模式。

将振动集成到你的通知处理程序中:

import { useEffect } from "react"; import * as Notifications from "expo-notifications"; import { Alert, Vibration } from "react-native"; import React from "react"; import { useNavigation } from "@react-navigation/native"; import { Audio } from 'expo-av';  Notifications.setNotificationHandler({   handleNotification: async () => {     return {       shouldPlaySound: true,       shouldSetBadge: false,       shouldShowAlert: true,     };   }, });  const HandleNotifications = () => {   const navigation = useNavigation();    useEffect(() => {     async function configurePushNotifications() {       const { status } = await Notifications.getPermissionsAsync();       let finalStatus = status;       if (finalStatus !== "granted") {         const { status } = await Notifications.requestPermissionsAsync();         finalStatus = status;       }       if (finalStatus !== "granted") {         Alert.alert(           "Permiso requerido",           "Se requieren notificaciones locales para recibir alertas cuando vencen los recordatorios."         );         return;       }     }      configurePushNotifications();   }, []);    useEffect(() => {     const subscription = Notifications.addNotificationResponseReceivedListener(       (response) => {         console.log("RESPONSE", response);         const reminderId = response.notification.request.content.data.reminderId;         if (reminderId) {           navigation.navigate("ModifyReminder", { reminderId });         }       }     );      return () => subscription.remove();   }, []);    useEffect(() => {     let soundObject = null;      async function playSound() {       soundObject = new Audio.Sound();       try {         await soundObject.loadAsync(require('../assets/sonido.mp3'));         await soundObject.playAsync();       } catch (error) {         console.log(error);       }     }      playSound();      return () => {       if (soundObject) {         soundObject.stopAsync();         soundObject.unloadAsync();       }     };   }, []);    useEffect(() => {     const appFocusSubscription = Notifications.addNotificationResponseReceivedListener(() => {       Vibration.cancel();       Audio.setIsEnabledAsync(false);     });      const appBlurSubscription = Notifications.addNotificationResponseReceivedListener(() => {       Audio.setIsEnabledAsync(true);     });      return () => {       appFocusSubscription.remove();       appBlurSubscription.remove();     };   }, []);    useEffect(() => {     const subscription = Notifications.addNotificationReceivedListener(() => {       Vibration.vibrate([0, 500, 200, 500], true);     });      return () => {       subscription.remove();       Vibration.cancel();     };   }, []);     return <React.Fragment />; };  export default HandleNotifications;

注意: Vibration.cancel() 可以停止振动。

处理权限

在 Android 和 iOS 上,你需要请求用户授权才能发送通知。 Expo 提供 Notifications.requestPermissionsAsync() 方法来处理权限请求。

import * as Notifications from 'expo-notifications'; import { Alert } from 'react-native';  async function configurePushNotifications() {   const { status } = await Notifications.getPermissionsAsync();   let finalStatus = status;    if (finalStatus !== 'granted') {     const { status } = await Notifications.requestPermissionsAsync();     finalStatus = status;   }    if (finalStatus !== 'granted') {     Alert.alert(       "Permiso requerido",       "Se requieren notificaciones locales para recibir alertas cuando vencen los recordatorios."     );     return;   } }

确保在组件挂载时调用 configurePushNotifications()。

在特定时间触发通知

要实现在特定时间触发通知,你需要使用 Notifications.scheduleNotificationAsync() 方法,并设置 trigger 属性。trigger 属性可以是一个 date 对象,也可以是一个包含 seconds 属性的对象,表示从现在开始的秒数。

import * as Notifications from 'expo-notifications';  async function schedulePushNotification() {   await Notifications.scheduleNotificationAsync({     content: {       title: "Reminder!",       body: 'It's time!',       sound: 'default',       data: { data: 'goes here' },     },     trigger: { seconds: 5, repeats: false }, // Schedule for 5 seconds from now   }); }

关键点:

  • 使用 Notifications.scheduleNotificationAsync() 安排通知。
  • trigger 属性控制通知触发时间。

总结

通过结合 expo-av 和 react-native 的 Vibration API,你可以轻松地在 Expo 应用中添加声音和振动通知。 确保正确处理权限,并使用 Notifications.scheduleNotificationAsync() 方法在特定时间触发通知。 记住,用户体验至关重要,合理使用通知可以提升应用的用户满意度。

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享