运行 在 android Oreo 中接收短信服务

Run service on incoming SMS in android Oreo

我正在开发一个应用程序,每当收到短信时都需要 运行 一些代码(网络)。
在 API 25 及更低版本中没问题,我在 Manifest 文件中注册了一个隐式 receiver 并在扩展 BroadcastReceiver 的指定 class 中启动我的服务。在 API 26 中,您不能在 receiver 中注册 android.provider.Telephony.SMS_RECEIVED,因为它不起作用。

来自 Android 文档:

Note: If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for implicit broadcasts (broadcasts that do not target your app specifically), except for a few implicit broadcasts that are exempted from that restriction. In most cases, you can use scheduled jobs instead.

我读过几篇文章,例如 this one on medium。有 JobSchedulerExplicit Receiver 等解决方案,但第一个用于更改网络状态,我找不到在 SMS_RECEIVED 事件和第二个事件上触发作业的方法在您的 activity 启动并 运行ning 之前有效。

由于我的应用程序的性质,我需要侦听传入的 SMS,无论该应用程序是否 运行ning。如何在 API 26+ 中做到这一点?

编辑

也许 code in JobInfoBuilder doc on android website 可以提供帮助。它监视设备上照片的变化并在变化时开始工作。但是我找不到合适的 Uri 来对 SMS 做同样的事情(甚至不确定是否可以通过 ContentObserver 监控 SMS)

我认为目前您是安全的,因为 SMS_RECEIVED_ACTION 存在于当前豁免的隐式广播 list 中。此外,在收到系统广播后,您可以启动前台服务或安排工作(在您的情况下执行网络操作)。此外,我也在使用相同的操作,经测试它似乎工作正常。

由于androidO中有很多方法可以完成这项工作,所以我post这个答案并提到我解决问题的方法。显然,问题是指一般问题,而不是 SMS_RECEIVED 接收器本身。

我启动了一个前台服务,并在其中注册了一个动态或显式接收器来监听来电(例如):

MainActivity.java中:

String action = "START"
final Intent intent = new Intent(this, CallMonitorService.class);
intent.setAction(action);
startService(intent);

CallMonitorService.javas onCreate() 方法中,我将 BroadcastReceiver callExplicitReceiver 作为字段:

    final IntentFilter intentFilter = new IntentFilter();
    intentFilter.setPriority(2147483647);
    intentFilter.addAction("android.intent.action.PHONE_STATE");
    this.callExplicitReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
                // do the stuff here
            }
        }
    };
    registerReceiver(callExplicitReceiver, intentFilter);

然后在 onStartCommand():

    if (intent.getAction().equals("START")) {
        Intent callServiceNotificationIntent = new Intent(this, MainActivity.class);
        callServiceNotificationIntent.setFlags(
            Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        PendingIntent pendingIntent = PendingIntent
            .getActivity(this, CALL_SERVICE_REQUEST_CODE,
                    callServiceNotificationIntent, CALL_SERVICE_FLAG);

        Notification notification = new NotificationCompat.Builder(this)
            .setContentTitle(CALL_NOTIFICATION_CONTENT_TITLE)
            .setTicker(CALL_NOTIFICATION_TICKER)
            .setContentText(CALL_NOTIFICATION_CONTENT_TEXT)
            .setSmallIcon(R.drawable.ic_info_outline_black_24dp)
            .setContentIntent(pendingIntent)
            .setOngoing(true)
            .build();
        startForeground(CALL_NOTIFICATION_ID, notification);
    }

最后:

@Override
public void onDestroy() {
    super.onDestroy();
    unregisterReceiver(callExplicitReceiver);
}

我认为这是一个很好的方法,因为由于不可关闭的通知,用户会收到 运行 服务的通知,而这正是 android Oreo 想要的,但是通过一个按钮在应用程序中,用户可以停止服务和监控接收器作为破坏服务的直接结果(我清除了那部分代码)。