You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何停止Expo推送通知音效?及后台通话音效实现方案咨询

Expo环境下实现类WhatsApp通话音效的可靠方案

一、解决前台音效无法停止的问题

核心是确保音效实例全局可访问,绑定正确的事件回调:

  1. 全局维护音效实例
    不要在组件内部创建Sound实例,在App根组件或全局状态中初始化,避免组件卸载导致引用丢失:
// App.js 全局初始化
import { Audio } from 'expo-av';
let callRingtone = null;

export async function initCallRingtone() {
  callRingtone = new Audio.Sound();
  try {
    await callRingtone.loadAsync(require('./assets/call_ringtone.mp3'));
    await callRingtone.setIsLoopingAsync(true);
  } catch (error) {
    console.error('加载铃声失败:', error);
  }
}

// 全局停止方法
export async function stopCallRingtone() {
  if (callRingtone) {
    await callRingtone.stopAsync();
    await callRingtone.unloadAsync();
    callRingtone = null;
  }
}
  1. 绑定通知响应回调
    通过Expo Notifications的响应监听,在用户点击接听/拒接按钮时直接触发停止操作:
import * as Notifications from 'expo-notifications';

Notifications.addNotificationResponseReceivedListener(response => {
  const actionIdentifier = response.actionIdentifier;
  if (actionIdentifier === 'ACCEPT_CALL' || actionIdentifier === 'REJECT_CALL') {
    stopCallRingtone();
  }
});
  1. 监听AppState切换
    防止应用前后台切换时音效失控:
import { AppState } from 'react-native';

AppState.addEventListener('change', async nextAppState => {
  if (nextAppState === 'active') {
    // 回到前台时可重置音效实例
  } else if (nextAppState === 'background' && callRingtone) {
    // 后台时确保音效按预期播放(结合后台音频配置)
  }
});

二、实现后台可靠通话音效播放

Expo JS线程在后台受限,需结合后台音频权限配置和TaskManager后台任务实现:

  1. 配置app.json权限
    添加后台音频所需的系统权限:
{
  "expo": {
    "ios": {
      "infoPlist": {
        "UIBackgroundModes": ["audio", "remote-notification"]
      }
    },
    "android": {
      "permissions": [
        "FOREGROUND_SERVICE_AUDIO",
        "POST_NOTIFICATIONS"
      ],
      "useNextNotificationsApi": true
    }
  }
}
  1. 初始化后台音频模式
    设置Audio模块允许后台播放、静音模式下播放:
await Audio.setAudioModeAsync({
  allowsRecordingIOS: false,
  playsInSilentModeIOS: true,
  staysActiveInBackground: true,
  shouldDuckAndroid: false,
  playThroughEarpieceAndroid: false,
});
  1. 用TaskManager处理后台音效触发
    注册后台任务,在收到通话推送时启动或停止音效:
import * as TaskManager from 'expo-task-manager';
import * as Notifications from 'expo-notifications';

const CALL_RINGTONE_TASK = 'CALL_RINGTONE_TASK';

// 注册后台任务
TaskManager.defineTask(CALL_RINGTONE_TASK, async ({ data, error }) => {
  if (error) {
    console.error('后台任务出错:', error);
    return;
  }
  if (data.type === 'START_RINGTONE') {
    await initCallRingtone();
    await callRingtone.playAsync();
  } else if (data.type === 'STOP_RINGTONE') {
    await stopCallRingtone();
  }
});

// 关联推送通知到后台任务
Notifications.registerTaskAsync(CALL_RINGTONE_TASK);
  1. Android前台服务适配
    Android后台音频播放需要前台服务保活,结合Expo ForegroundService实现:
import * as ForegroundService from 'expo-foreground-service';

async function startForegroundService() {
  await ForegroundService.startAsync({
    id: 1,
    title: '通话请求',
    body: '正在接听来电',
    icon: require('./assets/icon.png'),
  });
}

// 播放后台音效前启动前台服务
await startForegroundService();
await callRingtone.playAsync();

三、关键注意事项

  • iOS上,后台音频播放必须是连续的音频流,确保铃声设置为循环播放,避免系统中断。
  • 所有后台操作需遵循Expo的后台任务限制,避免执行耗时操作。
  • 测试时需使用真机,模拟器的后台行为与真机存在差异。

内容的提问来源于stack exchange,提问作者Sonet Adhikary

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 17:23:12