如何保持我的BroadcastReceiver

时间:2016-04-23 19:37:42

标签: android broadcastreceiver android-service android-broadcastreceiver

目前我正在开发像Truecaller这样的呼叫拦截器应用程序。

我需要什么

  

即使我的应用已从中移除,我也想检测来电   最近的应用列表。

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
}

我的问题

  

我的BroadcastReceiver无法在后台工作,就像我从中移除一样   最近的应用列表。

我的完整清单代码

<?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如果无法保持活动广播接收器即使我的应用已关闭,我如何检测来电?

任何人给出详细的答案..

7 个答案:

答案 0 :(得分:2)

我们在这里通知接收方服务。

所以将服务类改为

    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();
        }
    }

现在从主要活动

启动服务
    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));

        }
    }

在清单中声明接收者和服务如下

 <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()。

当longTimeInFuture已经过时,

onFinish()最后被调用(只有一次)。

答案 1 :(得分:2)

您需要创建一个Service并在清单中注册它。之后,您应该在服务中注册BroadcastReceiver而不是清单。

当app从最近移除时,Service未停止,因此您的接收器也将继续工作。当应用程序从最近删除时,您甚至还会通过Service#onTaskRemoved收到回电。

虽然您还需要处理其他一些情况,但可以停止Service

有一种情况是,当系统内存不足时,android可以停止服务,您可以通过从START_STICKY方法返回onStartCommand来修复它。

其他情况是当设备重新启动时,您需要在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()
}

答案 2 :(得分:0)

<?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");
    }

}

}

试试这个。它会一直有效,直到您强行关闭应用程序

答案 3 :(得分:0)

您可以尝试在onCreate()活动中注册广播接收器。

答案 4 :(得分:0)

这是代码它适用于我:

在Manifest中添加权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

后续步骤在启动应用时创建Service启动(可能是MainActivity) 在onCreate

的方法Service中调用此代码
  

代码

((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;
        }
    }
}

答案 5 :(得分:-1)

这是我的食谱,实际上是从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. */
        }
    }
}

答案 6 :(得分:-2)

您必须从清单

添加权限
<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>

然后尝试将Log放入接收器块,

@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方法取消注册接收者