android 花式保活
程序员文章站
2022-03-16 15:02:51
1.在看到19-24版本不可见前台serivce,就有一个疑问 25 以后不行? 带这个疑问去看了下8.0 源码发现,可以做到不可见前台serivce,那怎么玩呢:2.先创建个service :public class LocalDaemonService extends Service { private static final String TAG = "LocalDaemonService"; public static final int NOTICE_ID =......
1.在看到19-24版本可以做到不可见前台serivce, 就有一个疑问 25 以后不行?
带这个疑问去看了下 源码发现,8.0可以做到不可见前台serivce,那怎么玩呢:
2.先创建个service :
public class LocalDaemonService extends Service {
private static final String TAG = "LocalDaemonService";
public static final int NOTICE_ID = 100;
@Override
public int onStartCommand(Intent intent3, int flags, int startId) {
FixForeGroundService.fixService(NOTICE_ID, TAG, this);
return START_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
重点在 FixForeGroundService:
public class FixForeGroundService extends Service {
private static final String TAG = "FixForeGroundService";
public static String FIX_SERVICE_ACTION = "FIX_SERVICE_ACTION";
public static String FIX_SERVICE_ID = "FIX_SERVICE_ID";
public static String FIX_SERVICE_CHANNEL = "FIX_SERVICE_CHANNEL";
public static String FIX_SERVICE_DATA = "FIX_SERVICE_DATA";
public static void fixService(int notifyId, String channel, Service service) {
int sdkInt = Build.VERSION.SDK_INT;
// 这前面两个网上一大堆
if (sdkInt < Build.VERSION_CODES.JELLY_BEAN_MR2) {
service.startForeground(notifyId, new Notification());
} else if (Build.VERSION_CODES.JELLY_BEAN_MR2 <= sdkInt && Build.VERSION_CODES.N_MR1 > sdkInt) {
Notification notification = NotificationUtils.getNotification(service);
Intent intent = new Intent(service, FixForeGroundService.class);
intent.setAction(FIX_SERVICE_ACTION);
intent.putExtra(FIX_SERVICE_ID, notifyId);
intent.putExtra(FIX_SERVICE_DATA, notification);
service.startForeground(notifyId, notification);
service.startService(intent);
}else if(Build.VERSION_CODES.N_MR1 == sdkInt){
Log.d(TAG,"怎么适配25");
} else if (Build.VERSION_CODES.N_MR1 < sdkInt) {
Log.d(TAG,"进来了 sdk="+sdkInt);
Log.d(TAG,"进来了 service="+service.getClass().getCanonicalName());
//这个才是重点 先不创建通道
// NotificationUtils.createNotificationChannelForSilent(service, channel);
//创建一个没声音没震动没闪光通知 ,当然随便一个通知也行
Notification build = NotificationUtils.getNotificationWithSilent(service, channel);
service.startForeground(notifyId, build);
Intent intent = new Intent(service, FixForeGroundService.class);
intent.setAction(FIX_SERVICE_ACTION);
intent.putExtra(FIX_SERVICE_CHANNEL, channel);
service.startService(intent);
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
stopSelf();
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
}
}
3.然后点击按钮启动service :
public void startService(View v){
if (Build.VERSION.SDK_INT>26){
startForegroundService(new Intent(this, LocalDaemonService.class));
}
}
效果如下:
查看adj:
6不6 ,在荣耀 adnroid 10 也是这样的效果。怎么做的呢:
在 NotificationManagerService 类中
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
int incomingUserId) {
.....
final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
notificationUid, channelId, false /* includeDeleted */);
// 为null
if (channel == null) {
final String noChannelStr = "No Channel found for "
+ "pkg=" + pkg
+ ", channelId=" + channelId
+ ", id=" + id
+ ", tag=" + tag
+ ", opPkg=" + opPkg
+ ", callingUid=" + callingUid
+ ", userId=" + userId
+ ", incomingUserId=" + incomingUserId
+ ", notificationUid=" + notificationUid
+ ", notification=" + notification;
Log.e(TAG, noChannelStr);
// 弹出吐司
doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
"Failed to post notification on channel \"" + channelId + "\"\n" +
"See log for more details");
return;
}
.....
}
有打印日志:2020-09-21 22:41:52.878 1788-1819/? E/NotificationService: No Channel found for pkg=com.test.keepalive, channelId=LocalDaemonService, id=100, tag=null, opPkg=com.test.keepalive, callingUid=10189, userId=0, incomingUserId=0, notificationUid=10189, notification=Notification(channel=LocalDaemonService pri=1 contentView=null vibrate=null sound=null defaults=0x0 flags=0x50 color=0x00000000 vis=PRIVATE)
虽然在8.0 会弹出吐司 ,但是已经提生adj了。目标版本:targetSdkVersion 26,大于26如果在9.0版本会报错误的.
4.如果是targetSdkVersion >26 ,怎么玩,贴出完整的Service :
public class FixForeGroundService extends Service {
private static final String TAG = "FixForeGroundService";
public static String FIX_SERVICE_ACTION = "FIX_SERVICE_ACTION";
public static String FIX_SERVICE_ID = "FIX_SERVICE_ID";
public static String FIX_SERVICE_CHANNEL = "FIX_SERVICE_CHANNEL";
public static String FIX_SERVICE_DATA = "FIX_SERVICE_DATA";
public static void fixService(int notifyId, String channel, Service service) {
int sdkInt = Build.VERSION.SDK_INT;
if (sdkInt < Build.VERSION_CODES.JELLY_BEAN_MR2) {
service.startForeground(notifyId, new Notification());
} else if (Build.VERSION_CODES.JELLY_BEAN_MR2 <= sdkInt && Build.VERSION_CODES.N_MR1 > sdkInt) {
Notification notification = NotificationUtils.getNotification(service);
Intent intent = new Intent(service, FixForeGroundService.class);
intent.setAction(FIX_SERVICE_ACTION);
intent.putExtra(FIX_SERVICE_ID, notifyId);
intent.putExtra(FIX_SERVICE_DATA, notification);
service.startForeground(notifyId, notification);
service.startService(intent);
}else if(Build.VERSION_CODES.N_MR1 == sdkInt){
Log.d(TAG,"怎么适配25");
} else if (Build.VERSION_CODES.N_MR1 < sdkInt) {
Log.d(TAG,"进来了 sdk="+sdkInt);
Log.d(TAG,"进来了 service="+service.getClass().getCanonicalName());
NotificationUtils.createNotificationChannelForSilent(service, channel);
Notification build = NotificationUtils.getNotificationWithSilent(service, channel);
service.startForeground(notifyId, build);
Intent intent = new Intent(service, FixForeGroundService.class);
intent.setAction(FIX_SERVICE_ACTION);
intent.putExtra(FIX_SERVICE_CHANNEL, channel);
service.startService(intent);
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
if (intent != null) {
// 把通知渠道删除
if (FIX_SERVICE_ACTION.equals(intent.getAction())) {
int sdkVersion26 = Build.VERSION_CODES.O;
if (Build.VERSION.SDK_INT >= sdkVersion26) {
Log.d(TAG, "隐藏service 26"+intent.toString());
Handler handler=new Handler(getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
String channelId = intent.getStringExtra(FIX_SERVICE_CHANNEL);
if (!TextUtils.isEmpty(channelId)) {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.deleteNotificationChannel(channelId);
}
}
},30);
}
}
}
stopSelf();
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
}
}
结果如下:
5、7.1由于没有这channel 概念,找不到合适入口,其他入口只是给系统应用用的,那么7.1 怎么来玩呢?
5.1 可以检测悬浮权限有弹出悬浮:玩法跟一像素一样的
悬浮窗提升adj 从11提升3
The system will adjust the importance of processes with this window type to reduce the chance of the low-memory-killer killing them.
5.2 检测通知权限,没有通知权限,直接创建前台service 就完事了。
ActiveServices 类
private void setServiceForegroundInnerLocked(ServiceRecord r, int id,
Notification notification, int flags) {
....
// 7.1 没有这些判断的
这是8.0
switch (mode) {
case AppOpsManager.MODE_ALLOWED:
break;
case AppOpsManager.MODE_IGNORED:
Slog.w(TAG, "Instant app " + r.appInfo.packageName
+ " does not have permission to create foreground services"
+ ", ignoring.");
return;
case AppOpsManager.MODE_ERRORED:
throw new SecurityException("Instant app " + r.appInfo.packageName
+ " does not have permission to create foreground services");
default:
.......
}
.....
}
5.3 上面都不满足,就搞音乐service吧.
ps :下文, 强力的拉活手段 效果如下:
华为荣耀 android 10
本文地址:https://blog.csdn.net/qq_21727627/article/details/108718154