如何让我的 BroadcastReceiver 保持活力
How to keep alive my BroadcastReceiver
目前我正在开发像 Truecaller 这样的呼叫拦截器应用程序。
我需要的
I want to detect the incoming calls even my app is removed from the
recent apps list.
Manifest.xml代码
<receiver android:name=".PhoneStateReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
我的广播接收器代码
@Override
public void onReceive(Context context, Intent intent) {
//my call blocking code
}
我的问题
My BroadcastReceiver wont work in the background as if I removed from
the recent apps list.
我的完整清单代码在这里
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ranjith.callblocker">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.GET_TASKS" />
<application
android:allowBackup="true"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver
android:name=".PhoneStateReceiver"
android:enabled="true"
android:exported="true"
android:process=":anotherProcess">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
我应该使用服务还是其他什么?
更新:
有了 Suraj 的回答,我在我的接收器中尝试了这个标签
android:enabled="true"
android:exported="true"
android:process=":anotherProcess"
它适用于 kitkat..但不适用于棒棒糖..
更新问题:
Incase 如果无法使广播接收器保持活动状态,即使我的应用已关闭,我如何检测来电?
哪位大侠给个详细的回答..
这里我们从服务通知接收者。
所以做一个服务class作为
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new CountDownTimer(100000,4000)
{
@Override
public void onTick(long millisUntilFinished) {
sendBroadcast(new Intent("fromservice"));
}
@Override
public void onFinish() {
}
}.start();
return START_STICKY;
}
}
现在将接收器设置为
public class MyReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
Toast.makeText(context, "inside receiver", Toast.LENGTH_SHORT).show();
}
}
现在从 main 启动服务 activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this,MyService.class));
}
}
在manifest中声明receiver和service如下
<receiver android:name=".MyReceiver"
android:process=":jk"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="fromservice"/>
</intent-filter>
</receiver>
<service android:name=".MyService"
android:process=":ff"
android:enabled="true"
android:exported="true" />
将以下权限添加到您的清单中。
这用于防止 cpu 睡眠。
<uses-permission android:name="android.permission.WAKE_LOCK"/>
什么是倒计时?
倒计时计时器可以理解为必须方法的迭代
onTick() 和 onFinish()
在 CountDownTimer 构造函数中给定的间隔(持续时间)后多次调用 onTick()。
onFinish() 最后(仅一次)在 longTimeInFuture 到达时被调用。
您必须从清单中添加权限,
<uses-permission android:name="android.permission.READ_PHONE_STATE" >
并且接收方必须声明以下属性,声明名称时也总是尽量使用完整的包名。
<receiver
android:name="ranjith.callblocker.PhoneStateReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.READ_PHONE_STATE">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
然后尝试在接收块中放置一个日志,
@Override
public void onReceive(Context context, Intent intent) {
Log.i("TAG", "Receiver is called but might not block call for other reason!");
}
确保您没有通过任何 onPause、onStop、onDestroy 方法按名称注销接收器
这是我的食谱,它实际上适用于 4.4 到 6.0
清单:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<application>
<receiver android:name=".utils.PhoneReceiver">
<intent-filter android:priority="999">
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
</application>
然后在 PhoneReceiver.class
public class PhoneReceiver extends BroadcastReceiver
{
public void onReceive(Context thecontext, Intent intent)
{
if ("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction()))
{
// handle SMS received
}
else if ("android.intent.action.NEW_OUTGOING_CALL".equals(intent.getAction()))
{
// handle outgoing call
}
else if (intent.getAction().equals("android.intent.action.PHONE_STATE"))
{
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
/* from there do your stuff... */
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
/* etc. etc. */
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.phonestatelistener">
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.android.receiver.PhoneStateListener" android:exported="true" >
<intent-filter >
<action android:name="android.intent.action.PHONE_STATE"/>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
public class PhoneStateListener extends BroadcastReceiver {
public static String TAG="PhoneStateListener";
public static String ACTION_PHONE_STATE = "android.intent.action.PHONE_STATE";
public static String ACTION_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
public static String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_PHONE_STATE)) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
Toast.makeText(context, "Incoming call", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Incoming call");
}
} else if (intent.getAction().equals(ACTION_OUTGOING_CALL)) {
Toast.makeText(context, "Outgoing call", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Outgoing call");
} else if (intent.getAction().equals(ACTION_SMS_RECEIVED)) {
Toast.makeText(context, "Incoming message", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Incoming message");
}
}
}
试试这个。它会一直工作,直到您强制关闭应用程序
您可以尝试在 activity 的 onCreate() 中注册广播接收器。
这是代码它对我来说很好用:
在清单中添加权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
后续步骤创建一个 Service
在启动 App 时启动(可能 MainActivity
)
在 Service
的方法 onCreate
中调用此代码
Code
((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(new PhoneStateListener.PhoneCallListener() {
@Override
public void PhoneCall() {
// Do something
}
@Override
public void PhoneOff() {
// Do something
}
@Override
public void MissCall() {
// Do something
}
}), PhoneStateListener.LISTEN_CALL_STATE);
PhoneStateListener.java
import android.telephony.TelephonyManager;
/**
* PhoneStateListener.
*
* @author DaoLQ
*/
public class PhoneStateListener extends android.telephony.PhoneStateListener {
public interface PhoneCallListener {
void PhoneCall();
void PhoneOff();
void MissCall();
}
private PhoneCallListener mPhoneCallListener;
private boolean ring = false;
private boolean callReceived = false;
public PhoneStateListener(PhoneCallListener listener) {
mPhoneCallListener = listener;
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
mPhoneCallListener.PhoneOff();
if (ring && !callReceived) {
mPhoneCallListener.MissCall();
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// CALL_STATE_OFFHOOK;
callReceived = true;
mPhoneCallListener.PhoneCall();
break;
case TelephonyManager.CALL_STATE_RINGING:
ring = true;
mPhoneCallListener.PhoneCall();
break;
default:
break;
}
}
}
您需要创建一个 Service
并在清单中注册它。之后你应该在服务中注册你的 BroadcastReceiver
而不是清单。
A Service
不会停止,当应用程序从最近的应用程序中删除时,因此您的接收器也将继续工作。当应用程序从最近的应用程序中删除时,您甚至还会通过 Service#onTaskRemoved
收到回调。
虽然您还需要处理其他一些情况,但可以停止 Service
。
一种情况是当系统内存不足时 android 可以停止您的服务,您可以通过从 onStartCommand
方法返回 START_STICKY
来修复它。
另一种情况是当设备重启时,您需要在 mnifest 中为 ACTION_BOOT_COMPLETED
注册一个广播接收器来解决这个问题。您可以在其 onReceive
方法中重新启动您的服务。
希望下面的示例代码对您有所帮助-
private BroadcastReceiver mReceiver;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.v(LOG_TAG, "worked");
}
};
registerReceiver(mReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
return START_STICKY;
}
@Override
public void onDestroy() {
unregisterReceiver(mReceiver);
super.onDestroy()
}
目前我正在开发像 Truecaller 这样的呼叫拦截器应用程序。
我需要的
I want to detect the incoming calls even my app is removed from the recent apps list.
Manifest.xml代码
<receiver android:name=".PhoneStateReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
我的广播接收器代码
@Override
public void onReceive(Context context, Intent intent) {
//my call blocking code
}
我的问题
My BroadcastReceiver wont work in the background as if I removed from the recent apps list.
我的完整清单代码在这里
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ranjith.callblocker">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.GET_TASKS" />
<application
android:allowBackup="true"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver
android:name=".PhoneStateReceiver"
android:enabled="true"
android:exported="true"
android:process=":anotherProcess">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
我应该使用服务还是其他什么?
更新:
有了 Suraj 的回答,我在我的接收器中尝试了这个标签
android:enabled="true"
android:exported="true"
android:process=":anotherProcess"
它适用于 kitkat..但不适用于棒棒糖..
更新问题:
Incase 如果无法使广播接收器保持活动状态,即使我的应用已关闭,我如何检测来电?
哪位大侠给个详细的回答..
这里我们从服务通知接收者。
所以做一个服务class作为
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new CountDownTimer(100000,4000)
{
@Override
public void onTick(long millisUntilFinished) {
sendBroadcast(new Intent("fromservice"));
}
@Override
public void onFinish() {
}
}.start();
return START_STICKY;
}
}
现在将接收器设置为
public class MyReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
Toast.makeText(context, "inside receiver", Toast.LENGTH_SHORT).show();
}
}
现在从 main 启动服务 activity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this,MyService.class));
}
}
在manifest中声明receiver和service如下
<receiver android:name=".MyReceiver"
android:process=":jk"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="fromservice"/>
</intent-filter>
</receiver>
<service android:name=".MyService"
android:process=":ff"
android:enabled="true"
android:exported="true" />
将以下权限添加到您的清单中。 这用于防止 cpu 睡眠。
<uses-permission android:name="android.permission.WAKE_LOCK"/>
什么是倒计时?
倒计时计时器可以理解为必须方法的迭代
onTick() 和 onFinish()
在 CountDownTimer 构造函数中给定的间隔(持续时间)后多次调用 onTick()。
onFinish() 最后(仅一次)在 longTimeInFuture 到达时被调用。
您必须从清单中添加权限,
<uses-permission android:name="android.permission.READ_PHONE_STATE" >
并且接收方必须声明以下属性,声明名称时也总是尽量使用完整的包名。
<receiver
android:name="ranjith.callblocker.PhoneStateReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.READ_PHONE_STATE">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
然后尝试在接收块中放置一个日志,
@Override
public void onReceive(Context context, Intent intent) {
Log.i("TAG", "Receiver is called but might not block call for other reason!");
}
确保您没有通过任何 onPause、onStop、onDestroy 方法按名称注销接收器
这是我的食谱,它实际上适用于 4.4 到 6.0
清单:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<application>
<receiver android:name=".utils.PhoneReceiver">
<intent-filter android:priority="999">
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
</application>
然后在 PhoneReceiver.class
public class PhoneReceiver extends BroadcastReceiver
{
public void onReceive(Context thecontext, Intent intent)
{
if ("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction()))
{
// handle SMS received
}
else if ("android.intent.action.NEW_OUTGOING_CALL".equals(intent.getAction()))
{
// handle outgoing call
}
else if (intent.getAction().equals("android.intent.action.PHONE_STATE"))
{
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
/* from there do your stuff... */
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
/* etc. etc. */
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.phonestatelistener">
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.android.receiver.PhoneStateListener" android:exported="true" >
<intent-filter >
<action android:name="android.intent.action.PHONE_STATE"/>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
public class PhoneStateListener extends BroadcastReceiver {
public static String TAG="PhoneStateListener";
public static String ACTION_PHONE_STATE = "android.intent.action.PHONE_STATE";
public static String ACTION_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
public static String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_PHONE_STATE)) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
Toast.makeText(context, "Incoming call", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Incoming call");
}
} else if (intent.getAction().equals(ACTION_OUTGOING_CALL)) {
Toast.makeText(context, "Outgoing call", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Outgoing call");
} else if (intent.getAction().equals(ACTION_SMS_RECEIVED)) {
Toast.makeText(context, "Incoming message", Toast.LENGTH_SHORT).show();
Log.d(TAG, "Incoming message");
}
}
}
试试这个。它会一直工作,直到您强制关闭应用程序
您可以尝试在 activity 的 onCreate() 中注册广播接收器。
这是代码它对我来说很好用:
在清单中添加权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
后续步骤创建一个 Service
在启动 App 时启动(可能 MainActivity
)
在 Service
onCreate
中调用此代码
Code
((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(new PhoneStateListener.PhoneCallListener() {
@Override
public void PhoneCall() {
// Do something
}
@Override
public void PhoneOff() {
// Do something
}
@Override
public void MissCall() {
// Do something
}
}), PhoneStateListener.LISTEN_CALL_STATE);
PhoneStateListener.java
import android.telephony.TelephonyManager;
/**
* PhoneStateListener.
*
* @author DaoLQ
*/
public class PhoneStateListener extends android.telephony.PhoneStateListener {
public interface PhoneCallListener {
void PhoneCall();
void PhoneOff();
void MissCall();
}
private PhoneCallListener mPhoneCallListener;
private boolean ring = false;
private boolean callReceived = false;
public PhoneStateListener(PhoneCallListener listener) {
mPhoneCallListener = listener;
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
mPhoneCallListener.PhoneOff();
if (ring && !callReceived) {
mPhoneCallListener.MissCall();
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// CALL_STATE_OFFHOOK;
callReceived = true;
mPhoneCallListener.PhoneCall();
break;
case TelephonyManager.CALL_STATE_RINGING:
ring = true;
mPhoneCallListener.PhoneCall();
break;
default:
break;
}
}
}
您需要创建一个 Service
并在清单中注册它。之后你应该在服务中注册你的 BroadcastReceiver
而不是清单。
A Service
不会停止,当应用程序从最近的应用程序中删除时,因此您的接收器也将继续工作。当应用程序从最近的应用程序中删除时,您甚至还会通过 Service#onTaskRemoved
收到回调。
虽然您还需要处理其他一些情况,但可以停止 Service
。
一种情况是当系统内存不足时 android 可以停止您的服务,您可以通过从 onStartCommand
方法返回 START_STICKY
来修复它。
另一种情况是当设备重启时,您需要在 mnifest 中为 ACTION_BOOT_COMPLETED
注册一个广播接收器来解决这个问题。您可以在其 onReceive
方法中重新启动您的服务。
希望下面的示例代码对您有所帮助-
private BroadcastReceiver mReceiver;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.v(LOG_TAG, "worked");
}
};
registerReceiver(mReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
return START_STICKY;
}
@Override
public void onDestroy() {
unregisterReceiver(mReceiver);
super.onDestroy()
}