广播接收器,始终接收 API 级别 +26 的广播(即使在后台)



我把它作为问答风格,因为我发现这个想法很有效。对于Android初学者来说,这是破解难题的解决方法。

Google 已弃用从 API 级别 26+ 将Broadcast Receiver注册到下面的清单中(某些除外(

<receiver android:name=".MyBroadcastReceiver"  android:exported="true">
<intent-filter>
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>

但是,如果一个人想在应用程序处于后台时接收特定的设备状态更改,例如互联网连接更改(这是不允许的(,并且如果这对应用程序的任何功能都很重要,他应该怎么做?

当我浏览文档时,我的眼睛卡在这里:

上下文注册

的接收器只要其注册上下文有效,就会接收广播。例如,如果您在 活动上下文,只要活动是 没有被摧毁。如果使用应用程序上下文注册,则 只要应用正在运行,就会接收广播。

这实际上意味着,如果我可以持有上下文,则向其注册的广播接收器将在后台运行。

为此,Service将是最佳实践。

这是在杀死后再次启动STICKY_SERVICE的代码,因此上下文仍然有效

始终在线服务.class

package app.exploitr.auto;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.support.annotation.Nullable;
public class AlwaysOnService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
registerReceiver(new ClickReceiver(), new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"));
return Service.START_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onLowMemory() {  // rem this if you want it always----
stopSelf();
super.onLowMemory();
}
}

现在,实际做事的接收器:

点击接收器.class

package app.exploitr.auto;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import java.util.Objects;
public class ClickReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
switch (Objects.requireNonNull(intent.getAction())) {
case AutoJob.NOTIFICATION_CANCEL_TAG:
System.out.println("Not related");
break;
case AutoJob.LOGIN_CANCEL_TAG:
System.out.println("Not related");
break;
case "android.net.conn.CONNECTIVITY_CHANGE":
System.out.println("Oops! It works...");
break;
}
}
}

从任何活动类启动代码

private void setUpBackOffWork() {
if (DataMan.getInstance(getBaseContext()).getPeriodic()) {
AutoJob.schedulePeriodic();
//Not related
}
if (DataMan.getInstance(getBaseContext()).getPureAutoLogin()) {
startService(new Intent(this, AlwaysOnService.class));
}
}

所以我的目标是在我打开安卓的 WiFi 时自动登录我的 ISP,并且代码运行流畅。它永远不会失败(到目前为止,它运行了 7 小时 37 分钟并且运行良好 |不是在重新启动之间(。


要使接收器在重新启动后保持运行,请尝试清单可注册BOOT_COMPLETED操作。它就像旧的一样工作。

<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>


更新 1

现在,随着谷歌迈出了一步来限制后台执行,因此你也必须使该服务成为foreground服务。因此,程序如下。

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, new Intent(THIS_SERVICE_CLASS_NAME.this, ACTIVITY_TO_TARGET.class), 0);
/*Handle Android O Notifs as they need channel when targeting 28th SDK*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel(
"download_check_channel_id", 
"Channel name",
NotificationManager.IMPORTANCE_LOW);
if (notificationManager != null) {
notificationManager.createNotificationChannel(notificationChannel);
}
builder = new Notification.Builder(this.getBaseContext(), notificationChannel.getId())
.setContentTitle("Hi! I'm service")
.setContentIntent(pendingIntent)
.setOngoing(true);
notification = builder.build();
startForeground("StackOverflow".length(), notification);
}
return START_STICKY;
}

这也适用于 Xamarin Android。Play商店要求将我的应用程序的SDK升级到8.0 Oreo,但一堆东西停止了工作。

Microsoft关于广播接收器的文档非常令人困惑:

以 Android 8.0(API 级别 26(或更高版本为目标平台的应用不得静态注册隐式广播。应用仍可能静态注册显式广播。有一小部分隐式广播不受此限制。

即使是谷歌的官方文档也相当难以理解。

在Xamarin Android上,遵循以下模式就足够了:

[BroadcastReceiver]
[IntentFilter(new string[] {MyReceiver.MyAction})]
public class MyReceiver : BroadcastReceiver
{
public const String MyAction = "com.mytest.services.MyReceiver.MyAction";
public override void OnReceive (Context context, Intent intent)
{
// ...
}
}

IntentFilter注释指示编译器在生成过程中将接收器和意向筛选器注册添加到清单文件。但从目标 SDK v8.0(Oreo/API 26(及更高版本开始,Android 会忽略清单上的这些配置(某些系统隐式操作除外(。因此,这意味着IntentFilter注释仅适用于这些异常,并且要使广播接收器接收广播,需要在执行时注册它们:

#if DEBUG
[Application(Debuggable=true)]
#else
[Application(Debuggable=false)]
#endif
public class MyApplication: Application
{
public override void OnCreate ()
{
base.OnCreate ();
Context.RegisterReceiver(new MyReceiver(), new IntentFilter(MyReceiver.MyAciton));
}
}

也可以仅在活动的生命周期中注册接收方,如 @Toaster 所述。您可以继续正常发送广播:

// ...
ApplicationContext.SendBroadcast(new Intent(MyReceiver.MyAction));
// ...

最新更新