最近公司接到一个需求:需要安卓端监听用户打出去的电话,并记录在自己的数据库中,也就是说不能查询通话记录。现在网上的东西千篇一律,所以写点自己的理解。
需要用到的工具:
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
总结
网上抄手多,想要弄清楚要么自己试,要么看文档。以上算是我记录一些坑点,毕竟文档也写得很粗糙。
网友评论