Подтвердить что ты не робот

Как сохранить мой BroadcastReceiver

В настоящее время я разрабатываю приложение блокировки вызовов, такое как Truecaller.

Что мне нужно

Я хочу обнаружить входящие звонки, даже мое приложение удалено из список последних приложений.

Код манифест .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>

Должен ли я использовать сервис или что-то еще?

Update:

С ответом Suraj я пробовал эти теги в своем приемнике

    android:enabled="true"
    android:exported="true"
    android:process=":anotherProcess"

он работает на kitkat.. , но не работает на леденец.

Обновленный вопрос:

Инкасирование Если невозможно поддерживать живой широковещательный приемник Как я могу обнаружить входящие звонки, даже мое приложение закрыто?

кто-нибудь даст подробный ответ.

4b9b3361

Ответ 1

Здесь мы уведомляем получателя от службы.

Итак, создайте класс обслуживания как

    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" />

Добавьте в свой манифест следующее разрешение. Это используется для предотвращения спала процессора.

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

Что такое таймер обратного отсчета?

Таймер обратного отсчета можно понимать как итерацию, которая имеет методы

onTick() и onFinish()

onTick() вызывается много раз после интервала (время), как указано в конструкторе CountDownTimer.

onFinish() вызывается наконец (только один раз), когда longTimeInFuture имеет aarived.

Ответ 2

Вам нужно создать Service и зарегистрировать его в манифесте. После этого вы должны зарегистрировать свой BroadcastReceiver внутри службы вместо манифеста.

A Service не останавливается, когда приложение удаляется из recents, поэтому ваш ресивер также продолжит работу. Вы даже получите обратный вызов через Service#onTaskRemoved, когда приложение будет удалено из ретентатов.

Хотя вам также придется обрабатывать некоторые другие случаи, когда Service можно остановить.

В одном случае, когда андроид может остановить ваше обслуживание, когда система неактивна в памяти, вы можете исправить ее, возвращая START_STICKY из вашего метода onStartCommand.

В другом случае, когда устройство перезагружается, вам необходимо зарегистрировать широковещательный приемник для ACTION_BOOT_COMPLETED в mnifest, чтобы исправить это. Вы можете перезапустить службу в своем методе 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()
}

Ответ 3

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

}

}

Попробуйте это. Он будет работать до тех пор, пока вы не закроете приложение

Ответ 4

Вы можете попробовать зарегистрировать широковещательный приемник внутри on onCreate() активности.

Ответ 5

Вот код. Он отлично работает для меня:

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

Ответ 6

Вы должны добавить разрешение манифеста,

<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 methods

Ответ 7

Вот мой рецепт, он работает от 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. */
        }
    }
}