Expo应用:实现后台或关闭状态下推送通知触发时播放声音
Expo应用:实现后台或关闭状态下推送通知触发时播放声音
嘿,刚好我之前帮朋友做过类似的Expo商家订单提醒功能,后台/关闭状态下播放声音这个坑我踩过,给你梳理几个可行的方案和注意点:
一、先搞定最基础的:利用推送通知本身的声音配置
这是最可靠的方式,系统级通知的声音在后台/关闭状态下是原生支持的,不需要额外写复杂逻辑:
- 配置推送Payload:发送推送时,一定要在Payload里加上
sound字段。用默认系统声音就写"sound": "default",如果要用自定义声音,就填你的声音文件名(比如"sound": "order_alarm.wav")。示例Payload大概是这样:
{ to: "你的Expo推送Token", title: "新订单提醒", body: "有客户下单啦,快处理!", sound: "order_alarm.wav", // 或者用"default" data: { type: "new_order" } }
- 自定义声音的准备:把声音文件(iOS支持.wav/.aiff,Android支持.mp3/.wav,建议统一用.wav)放在项目的
assets/sounds目录下,然后在app.json里声明这个资源目录:
{ "expo": { "assets": ["./assets/sounds/"], // 其他配置... } }
二、针对不同平台的权限和配置优化
iOS端:
- 必须开启后台推送权限,在
app.json的iOS配置里加上:
"ios": { "infoPlist": { "UIBackgroundModes": ["remote-notification"] } }
- 自定义声音长度不能超过30秒,否则系统会忽略改用默认声音。
Android端:
- 创建专属的通知渠道,把声音绑定到渠道上,这样所有该渠道的通知都会用这个声音。在
app.json里配置:
"android": { "notificationChannelId": "order_alarm_channel", "notificationChannels": [ { "name": "订单提醒渠道", "description": "新订单到达时的专属提醒", "sound": "order_alarm.wav", "importance": 4, // 对应Android的通知重要性,4是高 "vibrationPattern": [0, 250, 250, 250], "lightColor": "#FF5500" } ] }
- Android 13及以上需要动态申请
POST_NOTIFICATIONS权限,用expo-notifications的requestPermissionsAsync方法就能搞定。
三、如果需要更复杂的播放逻辑(比如后台唤醒播放自定义音频)
如果系统通知的声音满足不了需求,比如要循环播放、或者播放更长的音频,那可以结合expo-task-manager和expo-av来做后台任务:
- 注册一个后台任务,用来处理推送到达时的音频播放:
import * as TaskManager from 'expo-task-manager'; import * as Notifications from 'expo-notifications'; import { Audio } from 'expo-av'; // 定义后台任务的唯一标识 const BACKGROUND_NOTIFICATION_TASK = 'order-alarm-task'; // 实现任务逻辑 TaskManager.defineTask(BACKGROUND_NOTIFICATION_TASK, async ({ data }) => { if (data?.notification?.request?.content?.data?.type === 'new_order') { // 加载并播放自定义声音 const { sound } = await Audio.Sound.createAsync( require('./assets/sounds/order_alarm.wav') ); await sound.playAsync(); } }); // 注册任务 Notifications.registerTaskAsync(BACKGROUND_NOTIFICATION_TASK);
- 推送Payload里要加上
contentAvailable: true(iOS)和priority: 'high'(Android),确保后台任务能被触发:
{ to: "你的推送Token", title: "新订单", body: "请及时处理", contentAvailable: true, priority: 'high', data: { type: "new_order" } }
四、避坑提醒
- AppState的局限性:AppState只能监听应用在前台/后台的切换状态,当应用完全关闭时,AppState根本不会运行,所以靠它实现关闭状态下的声音播放是行不通的。
- iOS关闭状态的限制:如果应用被用户完全关闭(划掉),iOS不会允许执行任何后台代码,这时候只能依赖系统通知自带的声音,没法自定义播放逻辑。
- Android厂商的后台限制:像小米、华为这些品牌有自己的电池优化策略,可能会杀死后台任务,建议在应用里引导用户把应用加入“白名单”或者关闭电池优化。
备注:内容来源于stack exchange,提问作者Sam Allen




