Android 13系统下如何开启外拨电话的扬声器?
Xamarin.Forms 实现Android扬声器控制的适配方案
针对新Android版本中旧AudioManager方法失效的问题,这里提供一套完整的适配方案,核心是通过DependencyService调用原生API并处理版本权限差异:
1. 定义跨平台音频服务接口
在共享项目中创建统一接口,方便跨平台调用:
public interface IAudioService { bool TurnOnSpeaker(); bool TurnOffSpeaker(); bool IsSpeakerActive(); }
2. Android端原生实现
配置Manifest权限
先在Android项目的AndroidManifest.xml中添加必要权限:
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <!-- 涉及音频录制/通话场景时需要,Android 6.0+需动态申请 --> <uses-permission android:name="android.permission.RECORD_AUDIO" />
实现服务类
[assembly: Dependency(typeof(AndroidAudioService))] namespace YourApp.Droid { public class AndroidAudioService : IAudioService { public bool TurnOnSpeaker() { try { var audioManager = (AudioManager)Android.App.Application.Context.GetSystemService(Context.AudioService); // Android 10+ 必须通过AudioFocusRequest申请音频焦点 if (Build.VERSION.SdkInt >= BuildVersionCodes.Q) { var focusRequest = new AudioFocusRequest.Builder(AudioFocus.GainTransient) .SetAudioAttributes(new AudioAttributes.Builder() .SetUsage(AudioUsageKind.VoiceCommunication) .SetContentType(AudioContentType.Speech) .Build()) .Build(); if (audioManager.RequestAudioFocus(focusRequest) != AudioFocusRequestResult.Granted) { return false; } } else { // 旧版本直接请求音频焦点 if (audioManager.RequestAudioFocus(null, Stream.VoiceCall, AudioFocus.Gain) != AudioFocusRequestResult.Granted) { return false; } } // 设置音频模式并开启扬声器 audioManager.Mode = Mode.InCall; audioManager.SetSpeakerphoneOn(true); return true; } catch (Exception ex) { Console.WriteLine($"开启扬声器失败: {ex.Message}"); return false; } } public bool TurnOffSpeaker() { try { var audioManager = (AudioManager)Android.App.Application.Context.GetSystemService(Context.AudioService); audioManager.SetSpeakerphoneOn(false); // 释放音频焦点 if (Build.VERSION.SdkInt >= BuildVersionCodes.Q) { var focusRequest = new AudioFocusRequest.Builder(AudioFocus.GainTransient) .SetAudioAttributes(new AudioAttributes.Builder() .SetUsage(AudioUsageKind.VoiceCommunication) .SetContentType(AudioContentType.Speech) .Build()) .Build(); audioManager.AbandonAudioFocusRequest(focusRequest); } else { audioManager.AbandonAudioFocus(null); } return true; } catch (Exception ex) { Console.WriteLine($"关闭扬声器失败: {ex.Message}"); return false; } } public bool IsSpeakerActive() { var audioManager = (AudioManager)Android.App.Application.Context.GetSystemService(Context.AudioService); return audioManager.IsSpeakerphoneOn; } } }
3. 动态申请权限(Android 6.0+)
RECORD_AUDIO属于危险权限,必须在运行时申请,可在页面初始化或按钮点击前处理:
private async Task CheckAndRequestPermissions() { var micStatus = await Permissions.CheckStatusAsync<Permissions.Microphone>(); if (micStatus != PermissionStatus.Granted) { var result = await Permissions.RequestAsync<Permissions.Microphone>(); if (result != PermissionStatus.Granted) { await DisplayAlert("提示", "需要麦克风权限才能控制扬声器", "确定"); } } }
4. 在Xamarin.Forms页面调用
通过DependencyService获取服务实例并使用:
private async void EnableSpeakerBtn_Clicked(object sender, EventArgs e) { await CheckAndRequestPermissions(); var audioService = DependencyService.Get<IAudioService>(); if (audioService != null) { var success = audioService.TurnOnSpeaker(); await DisplayAlert("结果", success ? "扬声器已开启" : "开启失败", "确定"); } }
关键适配点
- 音频焦点:Android 10(API 29)之后必须通过
AudioFocusRequest申请焦点,否则SetSpeakerphoneOn会失效。 - 音频模式:根据场景选择
Mode.InCall(通话)或Mode.Normal(媒体),模式不对也可能导致扬声器无法开启。 - 权限区分:
MODIFY_AUDIO_SETTINGS是正常权限,只需Manifest声明;RECORD_AUDIO需要动态申请。
内容的提问来源于stack exchange,提问作者MomMan
相关产品推荐
相关产品推荐

