Android 使用BroadcastReceiver来监听手机来电

一、需求背景

客户在使用我公司的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博客

Android获取通讯录 - 简书

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,下面是使用BroadcastReceiver实时监听电量的Android源码: 1. 在AndroidManifest.xml文件中添加以下权限和广播接收器: ```xml <uses-permission android:name="android.permission.BATTERY_CHANGED" /> <receiver android:name=".BatteryReceiver"> <intent-filter> <action android:name="android.intent.action.BATTERY_CHANGED" /> </intent-filter> </receiver> ``` 2. 创建BatteryReceiver类实现BroadcastReceiver接口,重写onReceive()方法: ```java public class BatteryReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); float batteryLevel = level / (float) scale; Log.d("BatteryLevel", batteryLevel * 100 + "%"); } } ``` 3. 在MainActivity中注册广播接收器: ```java public class MainActivity extends AppCompatActivity { private BatteryReceiver batteryReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 注册广播接收器 batteryReceiver = new BatteryReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); registerReceiver(batteryReceiver, intentFilter); } @Override protected void onDestroy() { super.onDestroy(); // 取消注册广播接收器 unregisterReceiver(batteryReceiver); } } ``` 这样就可以实时监听电量了。当电量发生变化时,会在Logcat中输出当前电量百分比。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值