Android系统提供了多种实现通话功能的方式,核心涉及TelecomManager和隐式Intent,以下是具体实现方案:

权限声明
在AndroidManifest.xml添加必要权限:
<uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
动态权限请求(Android 6.0+)
private void requestCallPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.CALL_PHONE},
REQUEST_CALL_PERMISSION
);
} else {
makePhoneCall("13800138000"); // 已有权限直接拨号
}
}
@Override
public void onRequestPermissionsResult(int code, String[] permissions, int[] results) {
if (code == REQUEST_CALL_PERMISSION && results.length > 0
&& results[0] == PackageManager.PERMISSION_GRANTED) {
makePhoneCall("13800138000");
}
}
显式拨号界面
使用ACTION_DIAL打开拨号盘预填充号码:
public void openDialPad(String phoneNumber) {
Intent dialIntent = new Intent(Intent.ACTION_DIAL);
dialIntent.setData(Uri.parse("tel:" + phoneNumber));
startActivity(dialIntent);
}
直接拨打电话(需CALL_PHONE权限)
通过ACTION_CALL直接发起通话:
public void makePhoneCall(String phoneNumber) {
try {
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:" + phoneNumber));
// 检查双卡设备(API 22+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
TelecomManager tm = (TelecomManager) getSystemService(TELECOM_SERVICE);
if (tm.getCallCapablePhoneAccounts().size() > 1) {
callIntent.putExtra("android.telecom.extra.PREFERRED_PHONE_ACCOUNT",
tm.getCallCapablePhoneAccounts().get(0));
}
}
startActivity(callIntent);
} catch (SecurityException e) {
Log.e("CallError", "Permission denied: " + e.getMessage());
}
}
监听通话状态
public class CallStateMonitor extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String number) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
Log.d("CallState", "来电中: " + number);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.d("CallState", "通话中");
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.d("CallState", "挂断状态");
break;
}
}
}
// 注册监听器
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
tm.listen(new CallStateMonitor(), PhoneStateListener.LISTEN_CALL_STATE);
特殊号码处理
// 拨打分机号
Uri uri = Uri.parse("tel:10800" + Uri.encode("#") + "123456" + Uri.encode("#"));
// 发送USSD代码
startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:123%23")));
// 语音信箱
startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("voicemail:")));
通话管理高级技巧
-
自定义通话界面:
实现ConnectionService重写onCreateOutgoingConnection
public class MyConnectionService extends ConnectionService { @Override public Connection onCreateOutgoingConnection( PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) { Connection connection = new Connection() { @Override public void onAnswer() { / 接听逻辑 / } @Override public void onDisconnect() { / 挂断逻辑 / } }; connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED); return connection; } } -
通话录音实现(需特殊权限):
MediaRecorder recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL); recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); recorder.setOutputFile("/sdcard/call_record.3gp"); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.prepare(); recorder.start(); // 需在通话建立后启动
关键问题解决方案:
-
双卡拨号选择:
使用PhoneAccount创建选择对话框:TelecomManager tm = (TelecomManager) getSystemService(TELECOM_SERVICE); List<PhoneAccountHandle> accounts = tm.getCallCapablePhoneAccounts(); Intent intent = new Intent(Intent.ACTION_CALL) .setData(Uri.parse("tel:13800138000")) .putExtra("android.telecom.extra.PHONE_ACCOUNT_HANDLE", accounts.get(0)); -
权限拒绝处理:
引导用户跳转设置页:
Intent settingsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); settingsIntent.setData(Uri.parse("package:" + getPackageName())); startActivity(settingsIntent);
技术思考:
随着VoIP技术发展,传统通话功能正与互联网通信融合,建议开发者关注:
ConnectionServiceAPI实现跨平台通话控制- WebRTC与原生通话的集成方案
- 5G网络下实时音视频通话的QoS保障
您在开发中是否遇到过双卡设备拨号选择异常的问题?或者有定制通话界面的需求?欢迎分享您的具体场景,我将为您提供针对性优化建议。
原创文章,作者:世雄 - 原生数据库架构专家,如若转载,请注明出处:https://idctop.com/article/26592.html