android - 始终接收 API 级别 +26 的广播(即使在后台)的广播接收器
问题描述
我将其设置为问答风格,因为我发现这个想法有效。它解决了 Android 初学者难以破解的难题。
谷歌已弃用
Broadcast Receiver
从 API 级别 26+ 注册到下面这样的清单(除了一些)
<receiver android:name=".MyBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
但是,如果一个人想要在应用程序处于后台时接收特定的设备状态更改,例如Internet 连接更改(这是不允许的),并且如果这对他的应用程序的任何功能都很重要,他应该怎么做?
解决方案
当我浏览文档时,我的眼睛卡在这里:
只要注册上下文有效,上下文注册的接收者就会接收广播。例如,如果您在 Activity 上下文中注册,只要该 Activity 未被销毁,您就会收到广播。如果您在应用程序上下文中注册,只要应用程序正在运行,您就会收到广播。
这实际上意味着如果我可以持有一个 Context,注册它的广播接收器将在后台运行。
为此,aService
将是最佳实践。
STICKY_SERVICE
这是在杀死后再次启动的代码下面,因此上下文仍然有效。
AlwaysOnService.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();
}
}
现在,实际做事的接收者:
ClickReceiver.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;
}
推荐阅读
- security - 估计密码破解时间
- python - 由于数据类型不匹配 PySpark 无法解析列
- java - 用java制作一个基本的游戏,jFrame形式vs jframe
- css - 当我尝试通过样式更改图标颜色时,它保持黑色
- ios - 如何解决 React Native 中 Firebase 的 invalidRegistration 错误
- node.js - 构建了带有反应前端和快递代理后端的电子应用程序,而不是引导 api 请求来表达
- logic - 试图计算系统中的客户数量
- r - r - 检查列表的所有元素是否与向量完全匹配
- javascript - 我可以在 io-ts 中使用 TypeScript 的类型吗
- jq - 如附图中所述,如何解析 json 对象以从第一个对象本身获取“大小”值