一、需求背景
客户在使用我公司的Flutter插件时,硬是要我们搞一个来电通知的功能,就很无语,我找了Flutter的一些插件,发现没有一个能实现这个功能的,最后只能通过Android来实现,我这个前端承受了不该承受的。
二、实现步骤
1. 添加权限
2. 创建一个类来继承BroadcastReceiver
3. 动态注册和注销广播
4. 检测电话状态,获取电话号码
5. 封装一个获取手机通讯录的方法
6. 判断通讯录中是否包含该电话号码,有就返回备注名称,否则返回电话号码
三、代码分享
1. 注册权限
在 AndroidManifest.xml 文件中添加权限,可能不需要这么多的权限,但是我为了以防万一还是加了这么多。
<!--监听电话状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.CALL_PHONE" />
2. 创建一个类来继承BroadcastReceiver
public class PhoneStateReceiver extends BroadcastReceiver {
private static final String PHONE_STATE_RECEIVED = "android.intent.action.PHONE_STATE";
private static int previousState = TelephonyManager.CALL_STATE_IDLE;
private static PhoneStateReceiver receiver = new PhoneStateReceiver();
/**
* 注册
*
* @param context
*/
public static void register(Context context) {
IntentFilter filter = new IntentFilter();
filter.setPriority(Integer.MAX_VALUE);
filter.addAction(PHONE_STATE_RECEIVED);
context.registerReceiver(receiver, filter);
}
/**
* 注销
*
* @param context
*/
public static void unregister(Context context) {
context.unregisterReceiver(receiver);
}
@Override
public void onReceive(final Context context, Intent intent) {
// 来电处理逻辑
}
}
3. 动态注册和注销广播
我这里是在 ActivityAware 的生命周期中注册的,你可以根据实际情况进行注册,只要在应用运行时注册就行。
public class MoyoungBlePlugin implements ActivityAware {
private Activity activity;
@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
activity = binding.getActivity();
// 注册广播
PhoneStateReceiver.register(activity);
}
@Override
public void onDetachedFromActivityForConfigChanges() {
}
@Override
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
}
@Override
public void onDetachedFromActivity() {
// 注销广播
PhoneStateReceiver.unregister(activity);
activity = null;
}
}
4. 检测电话状态,获取电话号码
public class PhoneStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
checkPhoneState(context, intent);
}
/**
* 检测电话状态
*
* @param context
* @param intent
*/
private synchronized void checkPhoneState(Context context, Intent intent) {
TelephonyManager telephonyManager = (TelephonyManager) context
.getSystemService(Service.TELEPHONY_SERVICE);
int callState = telephonyManager.getCallState();
Log.i(PhoneStateReceiver.class.getName(), "callState: " + callState);
switch (callState) {
case TelephonyManager.CALL_STATE_RINGING: // 电话进来时
// 获取电话号码
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
IncomingNumberManager.getInstance().sendIncomingNumber(context, incomingNumber);
break;
case TelephonyManager.CALL_STATE_OFFHOOK: // 接起电话时
Log.i("checkPhoneState", "接电话");
break;
case TelephonyManager.CALL_STATE_IDLE: //无任何状态时
Log.i("checkPhoneState", "无任何状态");
break;
}
}
}
5. 封装一个获取手机通讯录的方法
public class ContactUtils {
private ContactUtils() {
}
/**
* 通过号码查询联系人名字
*
* @param context
* @param number
* @return
*/
public static String getContactName(Context context, String number) {
// 判断是否有通讯录权限
if (!hasSelfPermissions(context, Manifest.permission.READ_CONTACTS)) {
return number;
}
if (TextUtils.isEmpty(number)) {
return null;
}
final ContentResolver resolver = context.getContentResolver();
Uri lookupUri;
String[] projection = new String[]{ContactsContract.PhoneLookup._ID,
ContactsContract.PhoneLookup.DISPLAY_NAME};
Cursor cursor = null;
try {
lookupUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(number));
cursor = resolver.query(lookupUri, projection, null, null, null);
} catch (Exception ex) {
ex.printStackTrace();
try {
lookupUri = Uri.withAppendedPath(
android.provider.Contacts.Phones.CONTENT_FILTER_URL,
Uri.encode(number));
cursor = resolver.query(lookupUri, projection, null, null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
String ret = null;
if (cursor != null && cursor.moveToFirst()) {
ret = cursor.getString(1);
cursor.close();
}
return ret;
}
public static boolean hasSelfPermissions(Context context, String... permissions) {
for (String permission : permissions) {
if (permissionExists(permission) && !hasSelfPermission(context, permission)) {
return false;
}
}
return true;
}
private static boolean permissionExists(String permission) {
// Check if the permission could potentially be missing on this device
Integer minVersion = MIN_SDK_PERMISSIONS.get(permission);
// If null was returned from the above call, there is no need for a device API level check for the permission;
// otherwise, we check if its minimum API level requirement is met
return minVersion == null || Build.VERSION.SDK_INT >= minVersion;
}
@SuppressLint("WrongConstant")
private static boolean hasSelfPermission(Context context, String permission) {
try {
if (permission.equals(PERMISSION_UPDATE_BAND_CONFIG[0])) {//android 11需要单独判断存储权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {//30 android 11
return Environment.isExternalStorageManager();
}
}
return PermissionChecker.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
} catch (RuntimeException t) {
return false;
}
}
}
6. 判断通讯录中是否包含该电话号码,有就返回备注名称,否则返回电话号码
public class IncomingNumberManager {
private IncomingNumberManager() {
}
public static IncomingNumberManager getInstance() {
return Holder.INSTANCE;
}
private static class Holder {
private static final IncomingNumberManager INSTANCE = new IncomingNumberManager();
}
/**
* 来电号码
*
* @param context
* @param number
*/
public void sendIncomingNumber(Context context, final String number) {
if (TextUtils.isEmpty(number)) {
return;
}
String contactName = null;
try {
contactName = ContactUtils.getContactName(context, number);
} catch (Exception e) {
e.printStackTrace();
}
if (!TextUtils.isEmpty(contactName)) {
// 如果通讯录中有该电话号码的逻辑
} else {
// 如果没有该电话号码的逻辑
}
}
/**
* 挂断电话
*/
public void endCall() {
// 挂断电话的逻辑
}
}
注意:在使用时,必须要开启应用的电话、 联系人和通话记录权限,否则监听不到。
四、参考文案
android 拨打电话、 监听来电、监听呼出电话的功能实现_安卓 监控拨号呼出_Mars-xq的博客-CSDN博客
Android读取联系人的姓名及电话号码_android上述系统联系人数据库的相关信息,编写一个程序,用于读取系统联系人的姓名_NULL____的博客-CSDN博客文章来源:https://www.toymoban.com/news/detail-779741.html
Android获取通讯录 - 简书文章来源地址https://www.toymoban.com/news/detail-779741.html
到了这里,关于Android 使用BroadcastReceiver来监听手机来电的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!