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

Android 13通话时开启扬声器的Kotlin代码失效,求修复方案

Android 13 通话中开启扬声器的适配修改方案

你的代码在Android 13中失效主要是因为系统对音频权限、通话状态监听方式以及音频通道时机的限制变严格了,以下是具体修改步骤和代码:

1. 权限适配

首先在AndroidManifest.xml中声明必要权限:

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 若应用需在后台操作,需添加前台服务权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE" />

其中READ_PHONE_STATE是危险权限,需要在代码中动态申请,确保用户授权后再执行后续逻辑。

2. 替换通话状态监听方式

Android 12(API 31)起弃用了旧的TelephonyManager.listen()方法,Android 13需使用registerPhoneStateListener来监听通话状态:

val telephonyManager = applicationContext.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
val phoneStateListener = object : PhoneStateListener(Looper.getMainLooper()) {
    override fun onCallStateChanged(state: Int, phoneNumber: String?) {
        super.onCallStateChanged(state, phoneNumber)
        when (state) {
            TelephonyManager.CALL_STATE_OFFHOOK -> {
                Timber.d("onPhoneState: CALL_STATE_OFFHOOK")
                // 延迟1秒执行,确保通话音频通道完全建立
                Handler(Looper.getMainLooper()).postDelayed({
                    turnOnSpeaker()
                }, 1000)
            }
        }
    }
}

// 注册监听
telephonyManager.registerPhoneStateListener(
    applicationContext,
    PhoneStateListener.LISTEN_CALL_STATE,
    phoneStateListener
)

3. 修正扬声器开启逻辑

Android 13要求修改音频状态前需先获取音频焦点,同时要避免直接在Activity未前台时调用相关方法,改用ApplicationContext获取服务:

private fun turnOnSpeaker() {
    val audioManager = applicationContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
    
    // 构建音频焦点请求
    val audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
        .setAudioAttributes(
            AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
                .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                .build()
        )
        .build()

    // 请求音频焦点
    val focusResult = audioManager.requestAudioFocus(audioFocusRequest)
    if (focusResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
        try {
            // 设置音频模式为通话模式
            audioManager.mode = AudioManager.MODE_IN_CALL
            // 开启扬声器
            audioManager.isSpeakerphoneOn = true
        } catch (e: SecurityException) {
            Timber.e(e, "开启扬声器失败:权限不足")
        }
    } else {
        Timber.d("获取音频焦点失败,无法开启扬声器")
    }
}

关键注意点

  • 时机问题:CALL_STATE_OFFHOOK触发时通话音频通道可能尚未完全初始化,延迟执行可避免设置失效
  • 前台要求:Android 13限制后台应用修改音频设置,若需在后台操作,需将应用转为前台服务
  • 权限检查:每次执行扬声器开启逻辑前,最好再次检查MODIFY_AUDIO_SETTINGS权限是否已授权

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:23:23