安卓监听打电话(去电)

作者: 171Arios | 来源:发表于2018-03-25 13:04 被阅读0次

    最近公司接到一个需求:需要安卓端监听用户打出去的电话,并记录在自己的数据库中,也就是说不能查询通话记录。现在网上的东西千篇一律,所以写点自己的理解。


    需要用到的工具:

    TelephonyManager
    PhoneStateListener
    BroadcastReceiver
    Intent.ACTION_NEW_OUTGOING_CALL
    android.permission.PROCESS_OUTGOING_CALLS
    android.permission.READ_PHONE_STATE

    实现方案

    首先注册广播接收者去电监听,用TelephonyManager监听电话状态

    广播接收者代码

    logger工具com.orhanobut:logger

    public class PhoneReceiver extends BroadcastReceiver {
        private boolean isListen = false;
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (!isListen) {
                TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
                if (tm != null) {
                    tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
                    isListen = true;
                }
            }
            Logger.t("xxxx").d(intent.getAction());
            //去电
            if (Objects.equals(intent.getAction(), Intent.ACTION_NEW_OUTGOING_CALL)) {
                String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
                //这个地方只有你拨号的瞬间会调用
                Logger.t("xxxx").d("call OUT:" + phoneNumber);
            }
        }
    
        PhoneStateListener listener = new PhoneStateListener() {
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                switch (state) {
                    case TelephonyManager.CALL_STATE_IDLE:
                        //不管是去电还是来电通话结束都会调用,不管是不是你挂的
                        Logger.t("xxxx").d("挂断" + incomingNumber);
                        break;
                    case TelephonyManager.CALL_STATE_OFFHOOK:
                        //如果是来电,这个必须点击接听按钮才会调用
                        //如果是拨打,那么一开始就会调用,并不是打通了之后才会调用
                        Logger.t("xxxx").d("摘机状态,接听或者拨打" + incomingNumber);
                        break;
                    case TelephonyManager.CALL_STATE_RINGING:
                        //只有来电的时候会调用
                        Logger.t("xxxx").d("响铃:来电号码:" + incomingNumber);
                        break;
                }
            }
        };
    }
    

    activity中的注册代码

        private PhoneReceiver receiver;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ...
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
            receiver = new PhoneReceiver();
            registerReceiver(receiver, filter);
        }
        
        @Override
        protected void onDestroy() {
            super.onDestroy();
            ...
            unregisterReceiver(receiver);
        }
    

    权限

    Manifest中

    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    

    权限我用的RxPermissions

    RxPermissions rxPermissions = new RxPermissions(this); 
    rxPermissions.request(
        Manifest.permission.PROCESS_OUTGOING_CALLS,
        Manifest.permission.READ_PHONE_STATE,) //权限名称,多个权限之间逗号分隔开
                    .subscribe(granted -> {
                        // 在android 6.0之前会默认返回true
                        if (granted) {
                            //权限通过后,检查APP是否需要更新,并且直接登陆
                            goLogin();
                        } else {
                            // 权限未通过
                            AlertDialog alertDialog = new AlertDialog.Builder(this)
                                    .setTitle("您没有授权该权限,请在设置中打开授权,重新进入APP登录")
                                    .setPositiveButton("确定", (dialog, which) -> {
                                        Uri packageURI = Uri.parse("package:" + BuildConfig.APPLICATION_ID);
                                        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
                                        startActivity(intent);
                                        HomeApp.exitApp();
                                    })
                                    .setNegativeButton("取消", (dialog, which) -> MyApplication.exitApp()).create();
                            alertDialog.setCanceledOnTouchOutside(false);
                            alertDialog.setOnKeyListener((dialog, keyCode, event) -> keyCode == KeyEvent.KEYCODE_BACK);
                            alertDialog.show();
                        }
                    });
    

    坑点

    1.TelephonyManager

    首先来讲一下TelephonyManager,这个东西有点坑

    public void listen(PhoneStateListener listener, int events)
    

    实测,TelephonyManager如果是在activity中获取的,上面这个方法在你调用过后
    PhoneStateListener 的

    public void onCallStateChanged(int state, String incomingNumber)
    

    这个方法只会被调用一次,而如果TelephonyManager是通过BroadcastReceiver中onReceive的Context获取的那么就会多次调用。

    TelephonyManager的第二个坑爹的地方是没有办法注销listener。经过实验发现注册这个广播的activity挂了之后onCallStateChanged方法也只会被调用一次了,所以并不用担心注册了之后需要注销。所以尽量不要静态注册这个广播接收者。
    <font color="red">错误示范</font>

    <receiver android:name=".PhoneReceiver">   
        <intent-filter>   
            <action android:name="android.intent.action.PHONE_STATE"/>   
            <action android:name="android.intent.action.NEW_OUTGOING_CALL" />   
        </intent-filter>   
    </receiver>   
    

    2.PhoneStateListener

    <font color="red">错误示范</font>

    //注意,方法必须写在super方法后面,否则incomingNumber无法获取到值。
    super.onCallStateChanged(state, incomingNumber);
    

    首先这行代码并不需要调用,源码父类都是空实现,上面的注解更是无稽之谈

    3.BroadcastReceiver

    第一:这个玩意里面你才能够用TelephonyManager
    第二:这个尽量动态注册
    第三:

    <action android:name="android.intent.action.PHONE_STATE"/>
    

    这个可以不需要,你不需要用这个action让Receiver每次都收到电话状态的变化。因为PhoneStateListener已经跟你监听了,除非你想自己用Receiver写而不用PhoneStateListener监听。**
    第四:去电监听只会在你拨打电话号码得时候才会被回掉,如果你想监听来电请不要像我这样写你还是需要注册PHONE_STATE这个action来初始化PhoneStateListener

    总结

    网上抄手多,想要弄清楚要么自己试,要么看文档。以上算是我记录一些坑点,毕竟文档也写得很粗糙。

    相关文章

      网友评论

        本文标题:安卓监听打电话(去电)

        本文链接:https://www.haomeiwen.com/subject/fgmhcftx.html