欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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));
        }

    }

效果如下:

android 花式保活

android 花式保活

查看adj: 

android 花式保活

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);
    }
}

结果如下:
     

android 花式保活

android 花式保活

android 花式保活

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

android 花式保活

 

本文地址:https://blog.csdn.net/qq_21727627/article/details/108718154