Android 各版本挂断电话方法演进及最佳实践
文章目录
一、背景介绍
Android系统中挂断电话的方法随着版本的演进发生了多次变化。本文将详细介绍从Android 8.0到最新版本的实现方法,以及各个版本的兼容性处理方案。
二、Android 10之前的实现方式
2.1 源码分析
在Android 8.0和9.0中,ITelephony.aidl
提供了endCall()
接口:
而在Android 10源码中,已经移除了endCall()
接口。
2.2 实现代码
// Android 10之前的实现方式
public void endCall() {
try {
// 1. 通过类加载器加载相应类
Class<?> loadClass = getClassLoader().loadClass("android.os.ServiceManager");
// 2. 获取getService方法
Method method = loadClass.getDeclaredMethod("getService", String.class);
// 3. 执行方法获取IBinder对象
IBinder invoke = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE);
// 4. 转换为ITelephony接口并调用endCall方法
ITelephony iTelephony = ITelephony.Stub.asInterface(invoke);
iTelephony.endCall();
} catch (Exception e) {
e.printStackTrace();
// 建议添加日志记录,方便问题排查
Log.e("EndCall", "Failed to end call using ITelephony", e);
}
}
三、Android 10的实现方式
3.1 源码变更
在Android 10中,TelephonyManager
类的endCall()
方法被标记为@Deprecated
,并建议使用TelecomManager
的endCall()
方法:
// TelephonyManager.java in Android 10
@Deprecated
@SystemApi
@RequiresPermission(android.Manifest.permission.CALL_PHONE)
public boolean endCall() {
return false;
}
3.2 新的实现方式
// AndroidManifest.xml 权限配置
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
// 代码实现
private fun endCallAction() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Android 9.0(API 28)及以上版本使用TelecomManager
val tcm = context.getSystemService(Context.TELECOM_SERVICE) as? TelecomManager
tcm?.let {
// 检查权限
if (checkSelfPermission(Manifest.permission.ANSWER_PHONE_CALLS) ==
PackageManager.PERMISSION_GRANTED) {
it.endCall()
} else {
// 请求权限
requestPermissions(arrayOf(Manifest.permission.ANSWER_PHONE_CALLS),
REQUEST_CODE_ANSWER_PHONE_CALLS)
}
}
} else {
// Android 9.0以下版本使用反射调用ITelephony
val loadClass: Class<*> = javaClass.classLoader?.loadClass("android.os.ServiceManager")
?: throw ClassNotFoundException("ServiceManager class not found")
val method: Method = loadClass.getDeclaredMethod("getService", String::class.java)
val invoke: IBinder = method.invoke(null, Context.TELEPHONY_SERVICE) as IBinder
val iTelephony: ITelephony = ITelephony.Stub.asInterface(invoke)
iTelephony.endCall()
}
} catch (e: Exception) {
e.printStackTrace()
Log.e("EndCall", "Failed to end call", e)
// 可以在这里添加错误提示或其他处理逻辑
}
}
四、未来发展趋势
4.1 TelecomManager的废弃警告
值得注意的是,在最新版本中TelecomManager
的endCall()
方法也被标记为@Deprecated
:
/**
* @deprecated Companion apps for wearable devices should use the {@link InCallService} API
* instead. Apps performing call screening should use the {@link CallScreeningService} API instead.
*/
@RequiresPermission(Manifest.permission.ANSWER_PHONE_CALLS)
@Deprecated
public boolean endCall() { ... }
4.2 未来的替代方案
根据官方建议,未来的实现方向将分为两类:
- 可穿戴设备应用:使用
InCallService
API - 电话拦截应用:使用
CallScreeningService
API
具体实现可参考:
五、总结
Android系统挂断电话的实现方式经历了从ITelephony.aidl
到TelecomManager
,再到InCallService
/CallScreeningService
的演变。在实际开发中,需要注意以下几点:
- 根据目标Android版本选择合适的实现方式
- 做好权限管理和异常处理
- 关注API的更新和变化
- 保持代码的可维护性和兼容性
通过合理的实现方式和完善的异常处理,可以确保应用在各个Android版本上都能稳定地实现挂断电话的功能。