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

Unity开发中如何实现iOS(iPhone)设备系统音量调节

Unity 实现iOS端系统音量调节方案

首先明确iOS平台的规则限制:苹果没有开放直接修改系统全局音量的公开API,你在安卓端通过AudioManager.setStreamVolume直接修改音量的逻辑无法直接照搬,所有通过私有API强行修改系统音量的实现都会在App Store审核阶段被拒。

合规可过审的实现方案是使用苹果官方提供的MPVolumeView组件,最终实现的效果和你现有安卓代码完全一致:支持获取/设置0~1区间的媒体音量(对应安卓的STREAM_MUSIC流),调节时可弹出系统原生音量提示UI。


具体实现步骤

  • 补全C#侧跨平台调用逻辑,通过条件编译区分安卓、iOS平台实现
  • 编写iOS原生插件,封装MPVolumeView的音量读写逻辑,放到Unity指定的插件目录下

1. 补全后的C#跨平台音量控制代码

直接替换你原有的SmartphoneVolumeController类即可,原有安卓逻辑完全保留,新增iOS平台调用逻辑:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_IOS
using System.Runtime.InteropServices;
#endif

public class SmartphoneVolumeController : MonoBehaviour
{
    public static SmartphoneVolumeController Instance;
    private AndroidNativeVolumeService androidService;

    private void Awake()
    {
        if (Instance == null) Instance = this;
        else Destroy(gameObject);
    }

#if UNITY_IOS
    [DllImport("__Internal")]
    private static extern float iOS_GetSystemVolume();
    [DllImport("__Internal")]
    private static extern void iOS_SetSystemVolume(float volume);
#endif

    /// <summary>
    /// 获取当前系统媒体音量,返回值范围0~1
    /// </summary>
    public float GetSystemVolume()
    {
#if UNITY_ANDROID
        if (androidService == null) androidService = new AndroidNativeVolumeService();
        return androidService.GetSystemVolume();
#elif UNITY_IOS
        return iOS_GetSystemVolume();
#else
        return 1f;
#endif
    }

    /// <summary>
    /// 设置系统媒体音量,传入值范围0~1
    /// </summary>
    public void SetSystemVolume(float volumeValue)
    {
        volumeValue = Mathf.Clamp01(volumeValue);
#if UNITY_ANDROID
        if (androidService == null) androidService = new AndroidNativeVolumeService();
        androidService.SetSystemVolume(volumeValue);
#elif UNITY_IOS
        iOS_SetSystemVolume(volumeValue);
#endif
    }

    // 原有安卓音量服务实现保持不变
    public class AndroidNativeVolumeService
    {
        static int STREAMMUSIC;
        static int FLAGSHOWUI = 1;
        private static AndroidJavaObject audioManager;
        private static AndroidJavaObject deviceAudio
        {
            get
            {
                if (audioManager == null)
                {
                    AndroidJavaClass unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
                    AndroidJavaObject currentActivity = unityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
                    AndroidJavaObject context = currentActivity.Call<AndroidJavaObject>("getApplicationContext");
                    AndroidJavaClass audioManagerClass = new AndroidJavaClass("android.media.AudioManager");
                    AndroidJavaClass contextClass = new AndroidJavaClass("android.content.Context");
                    STREAMMUSIC = audioManagerClass.GetStatic<int>("STREAM_MUSIC");
                    string Context_AUDIO_SERVICE = contextClass.GetStatic<string>("AUDIO_SERVICE");
                    audioManager = context.Call<AndroidJavaObject>("getSystemService", Context_AUDIO_SERVICE);
                    if (audioManager != null)
                        Debug.Log("[AndroidNativeVolumeService] Android Audio Manager successfully set up");
                    else
                        Debug.Log("[AndroidNativeVolumeService] Could not read Audio Manager");
                }
                return audioManager;
            }
        }
        private static int GetDeviceMaxVolume()
        {
            return deviceAudio.Call<int>("getStreamMaxVolume", STREAMMUSIC);
        }
        public float GetSystemVolume()
        {
            int deviceVolume = deviceAudio.Call<int>("getStreamVolume", STREAMMUSIC);
            float scaledVolume = (float)(deviceVolume / (float)GetDeviceMaxVolume());
            return scaledVolume;
        }
        public void SetSystemVolume(float volumeValue)
        {
            int scaledVolume = (int)(volumeValue * (float)GetDeviceMaxVolume());
            deviceAudio.Call("setStreamVolume", STREAMMUSIC, scaledVolume, FLAGSHOWUI);
        }
    }
}

2. iOS原生插件代码

新建名为iOSVolumeController.mm的文件,放到Unity项目的Assets/Plugins/iOS目录下,代码内容如下:

#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>

static MPVolumeView *volumeView = nil;
static UISlider *volumeSlider = nil;

void SetupVolumeView()
{
    if (volumeView != nil) return;
    // 初始化音频会话,保证音量控制在应用前后台都正常生效
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    [[AVAudioSession sharedInstance] setActive:YES error:nil];
    
    // 若不需要显示系统音量弹窗,将frame改为CGRectMake(-100, -100, 10, 10)放到屏幕外即可
    volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(0, [UIScreen mainScreen].bounds.size.height - 10, [UIScreen mainScreen].bounds.size.width, 10)];
    volumeView.showsVolumeSlider = YES;
    [[[UIApplication sharedApplication] keyWindow] addSubview:volumeView];
    
    // 查找MPVolumeView内置的音量滑块控件
    for (UIView *view in volumeView.subviews) {
        if ([view isKindOfClass:[UISlider class]]) {
            volumeSlider = (UISlider *)view;
            break;
        }
    }
}

extern "C" float iOS_GetSystemVolume()
{
    SetupVolumeView();
    if (volumeSlider == nil) return 1.0f;
    return volumeSlider.value;
}

extern "C" void iOS_SetSystemVolume(float volume)
{
    SetupVolumeView();
    if (volumeSlider == nil) return;
    volume = fmaxf(0.0f, fminf(1.0f, volume));
    [volumeSlider setValue:volume animated:NO];
    // 触发滑块值变更事件,生效系统音量修改
    [volumeSlider sendActionsForControlEvents:UIControlEventTouchUpInside];
}

注意事项

  • 该方案使用苹果官方公开API实现,不会触发App Store审核拒审,接口返回/传入的音量值和安卓端保持一致,都是0~1的浮点数,上层调用不需要做额外适配
  • 不要尝试直接修改AVAudioSession的outputVolume属性,该属性为只读,强行调用私有API修改会直接被审核打回
  • 打包Xcode工程时,Unity会自动引入MediaPlayer、AVFoundation、UIKit等依赖框架,不需要手动在Xcode中额外配置
  • 若应用切换场景后音量滑块失效,可在场景加载完成后重新调用一次SetupVolumeView逻辑(也可将MPVolumeView实例绑定到不销毁的根节点上保证全局存活)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 08:48:25