android - Cómo mantener vivo mi BroadcastReceiver
android-service android-broadcastreceiver (7)
Aquí está el código Funciona bien para mí:
En Manifiesto usted agrega permiso:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Los próximos pasos crean un inicio de Service
cuando inicie la aplicación (tal vez MainActivity
) llame a este código en el método onCreate
of Service
Código
((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;
}
}
}
Actualmente estoy desarrollando una aplicación de bloqueo de llamadas como Truecaller.
Lo que necesitaba
Quiero detectar las llamadas entrantes, incluso mi aplicación se elimina de la lista de aplicaciones recientes.
Manifest.xml codigo
<receiver android:name=".PhoneStateReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
Mi código receptor de emisión
@Override
public void onReceive(Context context, Intent intent) {
//my call blocking code
}
Mi problema
Mi BroadcastReceiver no funcionará en segundo plano como si lo hubiera eliminado de la lista de aplicaciones recientes.
Mi código de manifiesto completo aquí
<?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>
¿Debo usar el servicio o cualquier otra cosa?
Actualizar:
Con la respuesta de Suraj probé estas etiquetas en mi receptor
android:enabled="true"
android:exported="true"
android:process=":anotherProcess"
funciona en kitkat ... pero no funciona en paleta ...
Pregunta actualizada:
Si no es posible mantener vivo el receptor de difusión ¿Cómo puedo detectar las llamadas entrantes incluso si mi aplicación está cerrada?
alguien da respuesta detallada ...
Aquí está mi receta, en realidad funciona de 4.4 a 6.0
Manifiesto:
<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>
Luego en el 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. */
}
}
}
Aquí estamos notificando al receptor del servicio.
Así que haz una clase de servicio como
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;
}
}
Ahora haz un receptor como
public class MyReceiver extends WakefulBroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
Toast.makeText(context, "inside receiver", Toast.LENGTH_SHORT).show();
}
}
Ahora inicia el servicio desde la actividad principal.
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));
}
}
Declarar receptor y servicio en manifiesto como sigue
<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" />
Agregue el siguiente permiso a su manifiesto. Esto se utiliza para evitar que la CPU se duerma.
<uses-permission android:name="android.permission.WAKE_LOCK"/>
¿Qué es el temporizador de cuenta regresiva?
El temporizador de cuenta regresiva puede entenderse como una iteración que tiene métodos.
onTick () y onFinish ()
onTick () se llama muchas veces después de un intervalo (duración de tiempo) como se indica en el constructor CountDownTimer.
Al final se llama a onFinish () (solo una vez) cuando longTimeInFuture ha llegado.
Debes agregar permiso de manifiesto,
<uses-permission android:name="android.permission.READ_PHONE_STATE" >
Y el receptor debe tener los siguientes atributos declarados, también siempre trate de usar el nombre completo del paquete cuando declare el nombre.
<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>
A continuación, intente poner un registro dentro del bloque receptor,
@Override
public void onReceive(Context context, Intent intent) {
Log.i("TAG", "Receiver is called but might not block call for other reason!");
}
Asegúrese de no cancelar el registro del receptor por nombre de ninguno de ustedes en los métodos OnPause, onStop, onDestroy
Necesita crear un Service
y registrarlo en el manifiesto. Después de ello, debe registrar su BroadcastReceiver
dentro del servicio en lugar del manifiesto.
Un Service
no se detiene cuando se elimina la aplicación de los últimos momentos, por lo que su receptor también continuará funcionando. Incluso recibirá una devolución de llamada a través del Service#onTaskRemoved
cuando la aplicación se elimine de los últimos.
Aunque también necesitará manejar algunos otros casos, cuando se puede detener un Service
.
Un caso es cuando Android puede detener su servicio cuando el sistema tiene poca memoria, puede corregirlo devolviendo START_STICKY
desde su método onStartCommand
.
Otro caso es cuando el dispositivo se reinicia, deberá registrar un receptor de difusión para ACTION_BOOT_COMPLETED
en mnifest para solucionar este problema. Puede reiniciar su servicio en su método onReceive
.
Espero debajo del código de ejemplo ayuda-
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()
}
Puede intentar registrar Broadcast Receiver en onCreate () de la actividad.
<?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");
}
}
}
Prueba esto . Funcionará hasta forzar el cierre de la aplicación.