【问题标题】:Receiver not getting invoked if removed app from recents如果从最近删除应用程序,接收器不会被调用
【发布时间】:2018-08-04 16:29:09
【问题描述】:

我正在开发在通话结束时发送短信的应用程序。

Manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xxx.xxxx.xxxx.xxxx">

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <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>

    <service
        android:name=".MonitorService"
        android:enabled="true"
        android:exported="true" />
    <service
        android:name=".SendText"
        android:exported="false" />

    <receiver
        android:name=".BootReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
</application>

</manifest>

我已经从MainActivity 获取了所有运行时权限(如果它高于 Marshmallow)。

我的接收者:

public class BootReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
    Log.d("BootTest : ", "\nOnBootReceiver - Received a broadcast!");
    Toast.makeText(context, "InstaPromo Is Ready !!", Toast.LENGTH_LONG).show();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    {
        context.startForegroundService(new Intent(context, MonitorService.class));
    }
    else
    {
        context.startService(new Intent(context, MonitorService.class));
    }
}
}

实现接收器运行时为:

public class MonitorService extends Service
{
// Notification variables

private BroadcastReceiver mCallBroadcastReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        String action = intent.getAction();

        if (action.equalsIgnoreCase("android.intent.action.PHONE_STATE"))
        {
            if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING))
            {
                Log.d("RECEIVER X: ", "INCOMING CALL...");
            }
            if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_IDLE))
            {
                Log.d("RECEIVER X: ", "CALL ENDS HERE...");
                Intent Dispatcher = new Intent(context, SendText.class);
                startService(Dispatcher);
            }
            if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
            {
                Log.d("RECEIVER X: ", "ACTIVE CALL GOING ON...");
            }
        }
    }
};

public MonitorService() { }

@Override
public void onCreate()
{
    super.onCreate();

    // created notification here
    // also registered broadcast receiver here

    mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
    startForeground(17, mBuilder.build());
}

@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
    Log.d("WatchMan : ", "\nmCallBroadcastReceiver Listening....");

    //return super.onStartCommand(intent, flags, startId);

    return START_STICKY;
}

@Override
public void onDestroy()
{
    this.unregisterReceiver(mCallBroadcastReceiver);
    Log.d("WatchMan : ", "\nDestroyed....");
    Log.d("WatchMan : ", "\nWill be created again....");
}

@Override
public IBinder onBind(Intent intent)
{
    // TODO: Return the communication channel to the service.
    throw new UnsupportedOperationException("Not yet implemented");
}
}
  • Broadcastreceiver 在服务类中工作正常;即使应用程序从最近的应用程序列表中删除,但如果从最近的应用程序列表中删除,那么在下一个boot_complete 它永远不会再次调用接收器。如果 App 没有从最近删除...那么在每次 boot_complete / quick boot 它都会被触发并且广播接收器可以正常工作。我试过android:exclude_from_recents...,但这不是实现它的方法。

谁能帮我解决这个问题。谢谢

更新 2

我在 github 上研究了 Firebase JobDispatcher 文档并使用如下:

  1. 在 gradle 项目文件中实现依赖
  2. 之后同步成功
  3. 创建了一个 JobService
  4. 创建了一个作业并安排了它。
  5. 它也在 boot_completed 上被触发..

public class MyJobService extends JobService
{
@Override
public boolean onStartJob(JobParameters job)
{
    // Do some work here

    Log.d("MY_JOB :", "STARTED HERE...  \n");

    return false;

    // Answers the question: "Is there still work going on?"
}

@Override
public boolean onStopJob(JobParameters job)
{
    Log.d("MY_JOB :", "STOPPED HERE...  \n");

    return true;

    // Answers the question: "Should this job be retried?"
}
}

        FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(MainActivity.this));

    Bundle myExtrasBundle = new Bundle();
    myExtrasBundle.putString("some_key", "some_value");

    Job myJob = dispatcher.newJobBuilder()
            // the JobService that will be called
            .setService(MyJobService.class)
            // uniquely identifies the job
            .setTag("my-unique-tag")
            // one-off job
            .setRecurring(false)
            // don't persist past a device reboot
            .setLifetime(Lifetime.FOREVER)
            // start between 0 and 60 seconds from now
            .setTrigger(Trigger.executionWindow(10, 10+2))
            // don't overwrite an existing job with the same tag
            .setReplaceCurrent(false)
            // retry with exponential backoff
            .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
            // constraints that need to be satisfied for the job to run
            .setConstraints(
                    // only run when device is idle
                    Constraint.DEVICE_IDLE
            )
            .setExtras(myExtrasBundle)
            .build();

    dispatcher.mustSchedule(myJob);

我应该如何安排它只在重新启动/启动完成时运行一次

  1. 我只想在停止后重复.. : setRecurring(false), IS IT OKAY to false or true it should be true?
  2. setLifetime(Lifetime.UNTIL_NEXT_BOOT) 将其设置为 FOREVER THIS OKAY
  3. setTrigger(Trigger.executionWindow(0, 60)) 没有得到这个
  4. setReplaceCurrent(false) 是的,没关系。
  5. 使用指数退避重试这是什么?

如何设置这些标签在BOOT/REBOOT上启动且只启动一次,启动失败试试,不要再启动..?

【问题讨论】:

  • 你的目标sdk版本是什么
  • @RohitSharma, min sdk = 21, 编译 sdk 26, 目标 sdk 26;
  • 您能否尝试将 targetSdkVersion 保持在 25 或更低,并检查反馈,Hack of CommonsWare 是否有类似情况。
  • 它也在重新启动时运行..(即使从最近删除)在奥利奥下方和之上,只有在奥利奥中如果从最近删除然后它永远不会在重新启动时被调用,直到应用程序再次打开.. . GOOGLE MADE COMPULSORY TARGET SDK 26 ... 现在需要两周时间才能上传到 Play 商店
  • 你试过我的answer提到的JobIntentService

标签: java android broadcastreceiver


【解决方案1】:

每次启动后使用 FirebaseJobDispatcher 重新启动您的服务。有关 JobDispatcher 的更多信息,请参阅this

【讨论】:

  • 是否支持 Api 26、27...(Android O 和​​ next...)?即使应用程序被用户从最近列表中删除,它是否保证每次启动时重启服务都完成?
  • @sandhyasasane 是的,它支持 API 回到 API 14。是的,它保证,我个人使用了相同的方法
  • 通过builder初始化作业调度器时使用setReplaceCurrent(true)属性。
  • 如果您想在重新启动后保持作业,也不要忘记添加setLifetime(Lifetime.FOREVER)
  • 不,你不需要。顺便问一下,一加3是否预装了googleplay?
【解决方案2】:
  • 如果应用程序是首次安装或用户强制停止BroadcastReceviers 将不会运行,直到用户手动运行应用程序至少一次

  • 按照doc & answer

    • 请注意,应用程序的停止状态Activity's 停止状态不同。系统分别管理这两个停止状态

    • 应用程序在首次安装但尚未启动以及手动安装时处于停止状态 由用户停止(在管理应用程序中)。 (他们的意思是力 停止应用

  • Htc 设备添加com.htc.intent.action.QUICKBOOT_POWERON >> 从此answer

    <receiver android:enabled="true" android:name=".receivers.BootUpReceiver">
        <intent-filter>
            <category android:name="android.intent.category.DEFAULT" />
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
            <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
         </intent-filter>
    </receiver>
    

Starting from Android O,

  • 如果您仍然需要在设备启动时启动服务,您现在可以使用@987654331 @

将 BroadcastReceiver 和 JobIntentService 添加到清单中

<receiver android:name=".BootReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
</receiver>

<service android:name=".MyService"
         android:permission="android.permission.BIND_JOB_SERVICE"/>

为您的 JobIntentService 排队工作:

public class BootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
            MyService.enqueueWork(context, new Intent());
        }
    }

}

定义您的 JobIntentService:

public class MyJobIntentService extends JobIntentService {

    public static final int JOB_ID = 0x01;

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, MyJobIntentService.class, JOB_ID, work);
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        // your code
    }

/**
 * This will be called if the JobScheduler has decided to stop this job.  The job for
 * this service does not have any constraints specified, so this will only generally happen
 * if the service exceeds the job's maximum execution time.
 *
 * @return True to indicate to the JobManager whether you'd like to reschedule this work,
 * false to drop this and all following work. Regardless of the value returned, your service
 * must stop executing or the system will ultimately kill it.  The default implementation
 * returns true, and that is most likely what you want to return as well (so no work gets
 * lost).
 */
public boolean onStopCurrentWork() {
    return true;
}

}

【讨论】:

  • 1) 强制停止与从最近删除它不同 2) 如果您在清单中的接收器上放置多个操作,则奥利奥以后它永远不会调用它;只需要保留允许的特例意图操作,并且不允许在运行时实现它...您可以查看代码。它严格按照文档
  • 是的...,它很明显;但是如何在 JobIntentService 中实现注册和注销运行时接收器......?允许吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-05
相关资源
最近更新 更多