如何将自定义应用设置为Android默认电话APP?
Hey there! I’ve tackled default dialer replacement projects before, so let’s walk through exactly what you need to do to get your custom phone app recognized as the system’s default (no floating windows required) on Android 7.0 and above. Your current manifest has a few misconfigurations we’ll fix, plus we’ll cover the critical components the system needs to see your app as a valid dialer candidate.
First: Fix Your Manifest Configuration
Your existing manifest has some key errors (like using permissions as intent actions) that are preventing the system from recognizing your app as a dialer. Let’s correct those and add the required components:
1. Dialer Activity (Core Dialer Interface)
Your dialer activity needs the right intent filters to respond to dial actions, physical call button presses, and privileged calls (like emergency numbers). Update your MainDialerActivity to this:
<activity android:name=".MainDialerActivity" android:parentActivityName=".MainActivity"> <intent-filter> <!-- Respond to dial requests --> <action android:name="android.intent.action.DIAL" /> <!-- Trigger when physical call button is pressed --> <action android:name="android.intent.action.CALL_BUTTON" /> <!-- Handle emergency/privileged calls --> <action android:name="android.intent.action.CALL_PRIVILEGED" /> <!-- Handle regular outgoing calls (if needed) --> <action android:name="android.intent.action.CALL" /> <category android:name="android.intent.category.DEFAULT" /> <!-- Allow being launched from browsers/other apps --> <category android:name="android.intent.category.BROWSABLE" /> <!-- Support tel: and voip: schemes --> <data android:scheme="tel" /> <data android:scheme="voip" /> </intent-filter> </activity>
Important note: Don’t use permissions (like android.permission.CALL_PHONE) as intent actions—this is a mistake in your current manifest that won’t work.
2. Incoming Call Activity
For incoming calls, you need to handle both older and newer Android intent actions, plus configure the activity to show over the lock screen. Update your IncomingCallActivity:
<activity android:name=".IncomingCallActivity" android:configChanges="orientation|screenSize" android:theme="@style/IncomingCallTheme" <!-- Show over lock screen --> android:showOnLockScreen="true" <!-- Wake the screen when a call comes in --> android:turnScreenOn="true"> <!-- Older API incoming call action --> <intent-filter> <action android:name="android.intent.action.ANSWER" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <!-- API 26+ incoming call action (required for Android 8.0+) --> <intent-filter> <action android:name="android.telecom.action.SHOW_INCOMING_CALL" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
Android 8.0 (API 26) introduced the SHOW_INCOMING_CALL action, so you must include this to get incoming calls to trigger your custom interface.
3. Required Permissions
You already have most permissions, but add these to cover all dialer functionality:
<uses-permission android:name="android.permission.READ_CALL_LOG" /> <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" /> <!-- Bypass Do Not Disturb for calls -->
Second: Add Telecom Service (API 26+)
Starting with Android 8.0, the system requires a ConnectionService implementation to handle call connections. Without this, your app won’t show up in the default dialer selection list.
First, create the service class:
public class MyConnectionService extends ConnectionService { @Override public Connection onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) { // Add your logic to handle incoming call connections here return super.onCreateIncomingConnection(connectionManagerPhoneAccount, request); } @Override public Connection onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) { // Add your logic to handle outgoing call connections here return super.onCreateOutgoingConnection(connectionManagerPhoneAccount, request); } }
Then register it in your manifest:
<service android:name=".MyConnectionService" android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"> <intent-filter> <action android:name="android.telecom.ConnectionService" /> </intent-filter> </service>
Third: Register Your Phone Account
You need to register your app as a valid call provider with the system. Add this code to your app’s startup (like MainActivity’s onCreate):
private void registerPhoneAccount() { TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE); if (telecomManager == null) return; ComponentName serviceComponent = new ComponentName(this, MyConnectionService.class); PhoneAccountHandle accountHandle = new PhoneAccountHandle(serviceComponent, "MyCustomDialerAccount"); PhoneAccount phoneAccount = PhoneAccount.builder(accountHandle, "自定义电话应用") .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) .build(); telecomManager.registerPhoneAccount(phoneAccount); }
Don’t forget to check for permissions before calling this: use Manifest.permission.MANAGE_PHONE_ACCOUNTS for API 31+, or Manifest.permission.READ_PHONE_STATE for older versions.
Fourth: Guide Users to Set Your App as Default
You can directly open the system’s default dialer selection screen from your app with this code:
private void promptSetDefaultDialer() { TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE); if (telecomManager == null) return; String currentDefault = telecomManager.getDefaultDialerPackage(); if (!getPackageName().equals(currentDefault)) { Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER); intent.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, getPackageName()); startActivity(intent); } }
This takes users straight to the screen where they can select your app as the default dialer.
Quick Fixes for Your Current Manifest
- Remove permissions (like
android.permission.CALL_PHONE) from intent actions—they don’t belong there. - Split your
MainActivity’s intent filter: keep onlyMAINandLAUNCHERfor the app’s entry point, and move dialer-related actions toMainDialerActivity. - Clean up
CallActivity’s intent filter—remove the invalid permission actions, and configure it to handle your in-call UI needs instead.
内容的提问来源于stack exchange,提问作者Daniel André

