You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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-notificationsrequestPermissionsAsync方法就能搞定。

三、如果需要更复杂的播放逻辑(比如后台唤醒播放自定义音频)

如果系统通知的声音满足不了需求,比如要循环播放、或者播放更长的音频,那可以结合expo-task-managerexpo-av来做后台任务:

  1. 注册一个后台任务,用来处理推送到达时的音频播放:
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);
  1. 推送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

火山引擎 最新活动