在 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 ;};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() 方法在特定时间触发通知。 记住,用户体验至关重要,合理使用通知可以提升应用的用户满意度。

以上就是在 Expo 应用中添加声音和振动通知的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1517127.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 10:32:26
下一篇 2025年12月20日 10:32:41

相关推荐

  • 什么是GraphQL?GraphQL的查询

    GraphQL是一种更高效、灵活的API设计方式,核心是客户端按需精确请求数据,解决REST的过度和不足获取问题。它通过单一端点和强类型Schema,支持声明式查询、变动(Mutation)修改数据、订阅(Subscription)实现实时通信,提升前后端协作与开发效率,适合复杂、多变的前端需求场景…

    2025年12月20日
    000
  • JavaScript中异步编程的调试技巧

    调试javascript异步代码的关键在于理解异步执行机制并善用调试工具。1. 使用浏览器异步断点功能,chrome devtools勾选”async”选项可追踪异步流程;2. 插入debugger语句实现代码中断;3. 利用console.log和console.trace…

    2025年12月20日 好文分享
    000
  • js 怎么生成二维码

    答案是使用JS库如qrcode.js或qrious可轻松生成二维码,通过设置数据、颜色、大小、容错率等参数生成图像,支持浏览器和Node.js环境,添加Logo需注意遮挡问题,若无法扫描需检查数据、尺寸、对比度、容错率等因素。 生成二维码,简单来说,就是把信息编码成一种图形,方便手机扫一扫就能读取。…

    2025年12月20日
    000
  • 使用 Cypress 自定义命令动态添加链式操作

    本文将介绍如何使用 Cypress 自定义命令,根据用户传入的参数动态地为元素添加链式操作。重点在于利用 expect 包装器处理断言,并讨论了动态添加 Cypress 命令的可能性和局限性。通过学习本文,你将能够更灵活地编写 Cypress 测试,并更好地理解 Cypress 的工作原理。 动态添…

    2025年12月20日
    000
  • js怎么获取原型链上的getter方法

    要获取javascript原型链上的getter方法,必须沿原型链向上查找,使用object.getprototypeof和object.getownpropertydescriptor;对于symbol类型,需通过object.getownpropertysymbols遍历symbol属性匹配目标…

    2025年12月20日 好文分享
    000
  • js怎么判断原型是否被修改过

    无法直接判断原型过去是否被修改,但可通过对比当前状态与初始快照来检测差异;2. 检测的核心是建立基准,如在代码早期保存object.prototype和array.prototype的属性列表;3. 使用object.freeze()或object.seal()可防止关键对象被修改,提升安全性;4.…

    2025年12月20日 好文分享
    000
  • js如何实现轮播图效果

    轮播图卡顿的解决方法包括:使用transform代替left属性以利用gpu加速;优化图片大小并采用懒加载或预加载;避免js频繁操作dom,合理使用节流、防抖和requestanimationframe;确保css过渡属性设置合理。2. 实现响应式与触摸滑动的方法:使用百分比宽度、flex-shri…

    2025年12月20日 好文分享
    000
  • js如何检测原型链上的符号属性

    检测原型链上的符号属性需沿原型链遍历,使用object.getownpropertysymbols()和object.getprototypeof()逐层查找;2. 判断对象是否具有指定符号属性应通过循环遍历原型链并用object.getownpropertysymbols()检查每一层是否包含该符…

    2025年12月20日 好文分享
    000
  • JS如何实现请求合并

    请求合并的核心是通过延迟和聚合机制将多个相似请求整合为一次通信,以提升性能和用户体验;2. 实现方式包括构建缓冲队列、设置定时器调度、聚合请求数据并分发响应结果;3. 适用场景有列表批量操作、组件数据依赖聚合、实时搜索、埋点上报和数据预加载;4. 主要挑战在于状态管理、错误处理粒度、请求兼容性、后端…

    2025年12月20日
    000
  • js如何操作nfc

    javascript操作nfc主要通过web nfc api实现,需在https安全上下文下由用户手势触发,使用ndefreader对象读写ndef格式数据;2. 读取标签需创建ndefreader实例,监听onreading事件并调用scan()方法;3. 写入数据通过write()方法将包含文本…

    2025年12月20日 好文分享
    000
  • 如何理解递归?递归在数据结构中的应用

    递归通过函数调用自身将问题分解为更小的子问题,直至达到可直接求解的基本情况。核心包含两部分:基本情况(Base Case)确保递归终止,防止无限循环;递归步骤(Recursive Step)将原问题拆解为更小的同类子问题。以阶乘为例,n == 0 为基本情况,n * factorial(n-1) 为…

    2025年12月20日
    000
  • 利用超链接优雅地提交HTML表单

    本文详细介绍了如何将传统的HTML表单提交按钮替换为自定义的超链接,同时保持其提交表单的功能。通过在超链接的onclick事件中嵌入JavaScript代码,我们可以模拟点击隐藏的提交按钮,从而实现表单的正常提交流程。这种方法适用于需要高度定制表单提交外观的场景。 定制化表单提交的需求与挑战 在现代…

    2025年12月20日
    000
  • javascript闭包怎么绑定事件处理器

    使用 var 在循环中绑定事件处理器会因共享变量导致所有处理器引用最终值;2. 用 let 可创建块级作用域,使每次迭代产生独立变量供闭包捕获;3. 使用 iife 可显式创建新作用域,将当前循环变量值作为参数传递并被闭包保留;4. 闭包在事件处理中还可实现防抖、节流和私有状态管理,确保函数能记住并…

    2025年12月20日 好文分享
    000
  • js 如何压缩字符串

    使用现代浏览器内置的 compressionstream api 是最优雅高效的字符串压缩方式,适用于较新浏览器环境;它通过 textencoder 将字符串转为 uint8array,利用 readablestream 和 compressionstream 进行 gzip 压缩,再将压缩结果转为…

    2025年12月20日
    000
  • JS如何实现第三方登录

    JS实现第三方登录,本质上是利用第三方平台的授权机制,让用户在第三方平台完成身份验证后,将用户信息传递给你的应用。关键在于理解OAuth 2.0协议流程。 解决方案 选择第三方平台: 确定你要支持的第三方登录平台,例如Google、Facebook、GitHub等。每个平台都有自己的开发者文档和AP…

    2025年12月20日
    000
  • Promise的基本用法是什么

    Promise 是异步操作的解决方案,提供 Pending、Fulfilled、Rejected 三种状态,通过 resolve 和 reject 控制结果,使用 then、catch、finally 处理状态,支持链式调用,结合 async/await 可写同步风格代码,相比回调函数避免了回调地狱…

    2025年12月20日
    000
  • JS如何实现Promise?Promise的原理

    promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),状态只能从pending变为fulfilled或rejected,且一旦改变不可逆转;当调用resolve时,状态由pending转为fulfilled,调用reject时转为rejecte…

    2025年12月20日
    000
  • js 怎么深拷贝一个对象

    json.parse(json.stringify(obj)) 不能深拷贝一切,它会丢失或转换函数、undefined、symbol、regexp、date等类型,且不支持循环引用;2. 实现真正深拷贝的推荐方法是使用 structuredclone(),它能处理大多数内置对象和循环引用,但不支持函…

    2025年12月20日
    000
  • JS如何实现下拉菜单

    答案:通过JavaScript控制显示隐藏、ARIA属性提升无障碍访问、监听点击与键盘事件实现用户交互。具体包括用aria-expanded同步菜单状态,点击外部或按Esc关闭菜单,确保焦点管理正确,支持键盘导航,并通过CSS过渡优化视觉体验,提升可用性与性能。 JavaScript实现下拉菜单,核…

    2025年12月20日
    000
  • 什么是尾调用优化?尾调用的条件

    尾调用优化通过复用栈帧避免递归导致的栈溢出,其核心是函数最后一步调用另一函数且无额外操作,满足条件时编译器将当前栈帧直接替换为被调用函数的执行上下文,从而实现常数空间复杂度。 尾调用优化(Tail Call Optimization,简称TCO)是一种编译器或解释器层面的优化技术,它主要针对函数调用…

    2025年12月20日
    000

发表回复

登录后才能评论
关注微信