管理系统音量的 React Native 模块,支持 iOS/Android
| Files | Last commit | Last update |
|---|---|---|
| 19 days ago | ||
| 19 days ago | ||
| 19 days ago | ||
| 1 month ago | ||
| 1 month ago | ||
| 19 days ago | ||
| 19 days ago | ||
| 19 days ago | ||
| 1 month ago | ||
| 19 days ago | ||
| 1 month ago |
react-native-volume-manager
本项目基于 react-native-volume-manager开发。如果在使用过程中有任何问题,欢迎在AtomGit提交Issue,会及时跟进。
项目介绍
@hxa-rn/react-native-volume-manager 是 react-native-volume-manager 2.0.8 的 HarmonyOS 适配包,面向 React Native for OpenHarmony 应用提供系统音量读取、音量变化监听、铃声模式读取与监听、设备静音状态查询等能力。
本包包含 TurboModule 原生实现,通过 @kit.AudioKit 访问 HarmonyOS 音频能力。音频会话、静音兼容及前台媒体音量写入采用明确的近似映射;铃声模式写入、DND 授权等能力继续受控降级。
集成指南
npm install @hxa-rn/react-native-volume-manager
peerDependencies:react、react-native(>= 0.72)。
包内声明了 harmony.alias: "react-native-volume-manager"。业务代码继续从原包名导入:
import { VolumeManager, getVolume } from 'react-native-volume-manager';
工程支持 RNOH Autolinking 时无需手工注册。若项目未启用 Autolinking,需要将包内 volume_manager.har 接入 Harmony 工程,并在 C++ 与 ArkTS 两侧注册 VolumeManagerPackage。
如需使用 HarmonyOS 的 setVolume / showNativeVolumeUI 近似能力,还必须在应用 ArkUI 页面挂载宿主:
// ArkTS(与 RNApp 同级)
import { VolumePanelHost } from '@hxa-rn/react-native-volume-manager';
VolumePanelHost()
宿主必须挂载。默认关闭系统音量条,并挂 (-1,-1) 抑制硬件键系统条。setVolume(..., { showUI: true }) 只让本次写入弹出官方条(不传 position)。showNativeVolumeUI({ enabled }) 不改音量、也不立刻出条,只决定之后按硬件音量键是否出条。
使用说明
import React, { useEffect, useState } from 'react';
import { Button, Text, View } from 'react-native';
import {
addVolumeListener,
getRingerMode,
getVolume,
isAndroidDeviceSilent,
} from 'react-native-volume-manager';
export default function VolumeExample() {
const [message, setMessage] = useState('待读取');
useEffect(() => {
const subscription = addVolumeListener((event) => {
setMessage(`音量事件:${event.volume} / ${event.type ?? 'unknown'}`);
});
return () => subscription.remove();
}, []);
const readStatus = async () => {
try {
const volume = await getVolume();
const ringerMode = await getRingerMode();
const silent = await isAndroidDeviceSilent();
setMessage(
`音量=${volume.volume.toFixed(2)},铃声模式=${ringerMode},静音=${silent}`
);
} catch (error) {
setMessage(`读取失败:${String(error)}`);
}
};
return (
<View>
<Button title="读取音频状态" onPress={readStatus} />
<Text>{message}</Text>
</View>
);
}
import { VolumeManager } from 'react-native-volume-manager';
export async function adjustMediaVolume(value: number, showUI: boolean) {
await VolumeManager.setVolume(value, { showUI });
return VolumeManager.getVolume();
}
export async function allowHardwareVolumeHud(enabled: boolean) {
await VolumeManager.showNativeVolumeUI({ enabled });
}
铃声模式监听必须成对释放:
import {
addRingerListener,
removeRingerListener,
} from 'react-native-volume-manager';
const subscription = addRingerListener((event) => {
console.log(event.status, event.mode);
});
removeRingerListener(subscription);
import React from 'react';
import { View, Text, Button } from 'react-native';
import {
useRingerMode,
RINGER_MODE,
} from 'react-native-volume-manager';
const modeText = {
[RINGER_MODE.silent]: 'Silent',
[RINGER_MODE.normal]: 'Normal',
[RINGER_MODE.vibrate]: 'Vibrate',
};
export default function RingerExample() {
const { mode, error, setMode } = useRingerMode();
return (
<View>
<Text>Ringer Mode: {mode !== undefined ? modeText[mode] : null}</Text>
<Button title="Silent" onPress={() => setMode(RINGER_MODE.silent)} />
<Button title="Normal" onPress={() => setMode(RINGER_MODE.normal)} />
<Button title="Vibrate" onPress={() => setMode(RINGER_MODE.vibrate)} />
<Text>{error?.message}</Text>
</View>
);
}
import React from 'react';
import { View, Text } from 'react-native';
import { useSilentSwitch } from 'react-native-volume-manager';
export default function SilentSwitchExample() {
const status = useSilentSwitch();
return (
<View>
{status ? (
<View>
<Text>Is Muted: {status.isMuted ? 'YES' : 'NO'}</Text>
<Text>Is Initial Query: {status.initialQuery ? 'YES' : 'NO'}</Text>
</View>
) : (
<Text>Fetching...</Text>
)}
</View>
);
}
接口文档
读取与监听
| 接口 | 参数 | 返回值 | HarmonyOS 说明 |
|---|---|---|---|
getVolume() |
无 | Promise<VolumeResult> |
返回主音量及可用音频流的归一化值 |
addVolumeListener(callback) |
音量事件回调 | EmitterSubscription |
监听 RNVMEventVolume |
getRingerMode() |
无 | Promise<0 | 1 | 2 | undefined> |
0 静音、1 振动、2 正常 |
isAndroidDeviceSilent() |
无 | Promise<boolean | null> |
基于铃声模式和媒体音量判断 |
addRingerListener(callback) |
铃声事件回调 | 订阅对象 | 监听 RNVMSilentEvent;鸿蒙事件 mode 为 SILENT / VIBRATE / NORMAL,不含 MUTED |
removeRingerListener(subscription) |
订阅对象 | void |
停止铃声事件转发并移除 JS 订阅 |
写入与平台专属接口
| 接口 | 参数 | 返回值 | HarmonyOS 说明 |
|---|---|---|---|
setVolume(value, config?) |
value: 0–1,config: {playSound?, type?, showUI?} |
Promise<void> |
要求挂载 Host;映射到前台 MEDIA 原始音量等级;showUI 只控制本次写入是否弹出官方音量条 |
setRingerMode(mode) |
0 | 1 | 2 |
Promise<0 | 1 | 2 | undefined> |
受控降级,返回请求值 |
checkDndAccess() |
无 | Promise<boolean | undefined> |
返回 false |
requestDndAccess() |
无 | Promise<boolean | undefined> |
返回 false,不跳转 |
showNativeVolumeUI(config) |
{enabled: boolean} |
Promise<void> |
不改音量、不立刻出条;enabled=true 拆掉 (-1,-1) 抑制器,之后按音量键能出系统条;enabled=false 再挂抑制器 |
enable(enabled?, async?) |
布尔值 | Promise<void> |
近似映射音频会话激活/停用;启用采用混音策略 |
setActive(value?, async?) |
布尔值 | Promise<void> |
近似映射 activateAudioSession / deactivateAudioSession |
setCategory(value, mixWithOthers?) |
音频会话类别 | Promise<void> |
近似映射 DEFAULT / MIX_WITH_OTHERS / PAUSE_OTHERS 并发策略 |
setMode(value) |
音频会话模式 | Promise<void> |
API20 映射 MEDIA / GAME / VOICE_COMMUNICATION 场景 |
enableInSilenceMode(enabled?) |
布尔值 | Promise<void> |
iOS 专属,受控降级 |
addSilentListener(callback) |
静音开关回调 | 订阅对象 | 返回铃声/媒体静音兼容事件 {isMuted, initialQuery} |
setNativeSilenceCheckInterval(value) |
毫秒数 | void |
事件驱动,无轮询需求,受控降级 |
Hooks、常量与类型
| 名称 | 说明 |
|---|---|
useRingerMode() |
读取铃声模式并提供设置函数;HarmonyOS 设置操作为受控降级 |
useSilentSwitch(interval?) |
iOS 为物理静音开关;HarmonyOS 返回铃声/媒体静音兼容状态 |
RINGER_MODE |
{ silent: 0, vibrate: 1, normal: 2 } |
AndroidVolumeTypes |
music / call / system / ring / alarm / notification |
VolumeResult |
至少包含 volume,音量事件可包含 type |
Mode |
上游类型含 SILENT / VIBRATE / NORMAL / MUTED;鸿蒙铃声事件不写 MUTED |
快速验证(运行 Example)
前置条件
| 依赖 | 版本要求 |
|---|---|
| Node.js | >= 18 |
| DevEco Studio | 5.0+ / 6.0+ |
| HarmonyOS SDK | API 12+ |
运行步骤
1. 克隆仓库
git clone https://gitcode.com/hxa-rn/react-native-volume-manager.git
cd react-native-volume-manager
git checkout main
2. 安装仓库开发依赖
npm install --legacy-peer-deps
Example 已改为从 npm 公仓安装 @hxa-rn/react-native-volume-manager@2.0.11,不再使用本地 file:../xxx.tgz,运行 Example 不必再执行 npm pack。
3. 进入 example 目录,安装依赖
cd example
npm install --legacy-peer-deps
4. 生成 JS Bundle
npm run dev
产物:harmony/entry/src/main/resources/rawfile/bundle.harmony.js
5. 用 DevEco Studio 打开鸿蒙工程
- 打开 DevEco Studio
- 选择
example/harmony目录 - 等待 Sync 完成
6. 编译并运行 HAP
在 DevEco Studio 中点击运行按钮,将 HAP 安装到设备/模拟器。
注意:Example 中已预置插件依赖和 Package 注册,无需手动配置 Link。
约束与限制
| 项目 | 要求或限制 |
|---|---|
| 包版本 | 2.0.11 |
| React Native | >= 0.72 |
| Node.js | >= 18 |
| HarmonyOS SDK | compatibleSdkVersion 6.0.0(20),API 20+ |
| 权限 | 无额外系统权限 |
| 能力 | HarmonyOS 行为 |
|---|---|
getVolume、addVolumeListener |
原生实现;返回 0–1 归一化音量 |
getRingerMode、addRingerListener、isAndroidDeviceSilent |
原生实现 |
setVolume |
通过已挂载的 VolumePanelHost 近似调节前台 MEDIA 音量;showUI 只控制本次是否弹出官方音量条 |
setRingerMode |
受控降级;第三方应用不能直接设置铃声模式 |
checkDndAccess、requestDndAccess |
无等价公开 API,返回 false,不跳转设置页 |
showNativeVolumeUI |
只记后续硬件键策略,不改音量、不立刻出条;enabled=false 用 (-1,-1) 抑制硬件键系统条 |
enable、setActive、setCategory、setMode |
映射 HarmonyOS AudioSessionManager,属于近似实现 |
addSilentListener、useSilentSwitch |
以铃声模式与媒体静音状态模拟,不代表物理静音开关 |
enableInSilenceMode、setNativeSilenceCheckInterval |
无等价语义,安全 no-op |
system 与 notification 没有独立的 HarmonyOS 音量类型,当前映射到最接近的 RINGTONE 流。API20 下音量与铃声监听均可在订阅移除时真实注销;应用仍应在 React 组件卸载时释放 JS 订阅。
HarmonyOS 不允许三方应用通过命令式 API 静默改系统音量。本包使用官方 AVVolumePanel:Host 保持挂载,默认挂 (-1,-1) 抑制器。setVolume(..., { showUI: true }) 本次出官方条(不传 position,通常在右上角);showNativeVolumeUI 不立刻出条,只决定之后硬件键是否出条。该方案仅支持前台 MEDIA 音量,非 music 类型会映射到 MEDIA;后台调节和按流精确写入仍不可用。官方条显示时可能吞掉部分点击。
开源license
本项目基于 MIT 协议,详见 LICENSE 文件。
问题反馈渠道
欢迎在 AtomGit 提交 Issue。也可通过以下地址反馈: