Android 原生保活

目录

方案一、前台服务+Notification

方案二、加入白名单

方案三、双进程守护 + JobScheduler 保活

1、JobService 代码

2、判定服务运行工具类

3、清单文件

4、MainActivity 代码

方案四、使用系统服务的return START_STICKY

方案五、一像素

1、Activity

2.注册清单文件:

3、监听锁屏和解锁通知,不能静态注册广播,只能动态注册:

4、分别在解锁和锁屏时唤醒我的HooliganActivity:

5、在最近使用的列表中隐藏应用

方案六、无声音乐

方案七、推送互相唤醒复活

方案八、app相互拉活


        Android保活众所周知,完全保活除非加入白名单,否则只能保住一段时间。下面一一介绍Android保活方案。由于时间有限,保活方案文章的编写,采用的是逐步完善的方式。在保证内容可用的条件下逐步晚上文字,不足之处还请见谅。完善所有代码后,会写成uni-app插件。

方案一、前台服务+Notification

代码

a、首先在AndroidManifest.xml添加以下权限

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

b、前台服务代码



public class KeepServices extends Service {

    private NotificationManager notificationManager;
    private String notificationId = "serviceid";
    private String notificationName = "servicename";

    @Override
    public void onCreate() {
        super.onCreate();
        notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        //创建NotificationChannel
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            NotificationChannel channel = new NotificationChannel(notificationId, notificationName, NotificationManager.IMPORTANCE_HIGH);
            notificationManager.createNotificationChannel(channel);
        }
        startForeground(1,getNotification());
    }

    private Notification getNotification() {
        Notification.Builder builder = new Notification.Builder(this)
                .setSmallIcon(R.mipmap.amin_pic)
                .setContentTitle("title")
                .setContentText("text");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder.setChannelId(notificationId);
        }
        Notification notification = builder.build();
        return notification;
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){

                    try {
                        Thread.sleep(2000);

                        Log.d("Services","====保活服务===数据支持====");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        }).start();


        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {

        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

    }

}

c、在AndroidManifest.xml中注册服务


<service
    android:name="com.xiaoya.keepalive.KeepServices"// 找到自己的服务路径
    android:enabled="true"
    android:exported="true" />

d、启动服务


 Intent intent=new Intent(this, KeepServices.class);
 startService(intent);

方案二、加入白名单

这里借鉴其他博主的国内厂商白名单跳转工具



public class SettingUtils {

    public static void enterWhiteListSetting(Context context) {
        try {
            context.startActivity(getSettingIntent());
        } catch (Exception e) {
            context.startActivity(new Intent(Settings.ACTION_SETTINGS));
        }
    }

    private static Intent getSettingIntent() {
        ComponentName componentName = null;
        String brand = android.os.Build.BRAND;
        switch (brand.toLowerCase()) {
            case "samsung":
                componentName = new ComponentName("com.samsung.android.sm",
                        "com.samsung.android.sm.app.dashboard.SmartManagerDashBoardActivity");
                break;
            case "huawei":
                componentName = new ComponentName("com.huawei.systemmanager",
                        "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity");
                break;
            case "xiaomi":
                componentName = new ComponentName("com.miui.securitycenter",
                        "com.miui.permcenter.autostart.AutoStartManagementActivity");
                break;
            case "vivo":
                componentName = new ComponentName("com.iqoo.secure",
                        "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity");
                break;
            case "oppo":
                componentName = new ComponentName("com.coloros.oppoguardelf",
                        "com.coloros.powermanager.fuelgaue.PowerUsageModelActivity");
                break;
            case "360":
                componentName = new
                        ComponentName("com.yulong.android.coolsafe",
                        "com.yulong.android.coolsafe.ui.activity.autorun.AutoRunListActivity");
                break;
            case "meizu":
                componentName = new ComponentName("com.meizu.safe",
                        "com.meizu.safe.permission.SmartBGActivity");
                break;
            case "oneplus":
                componentName = new ComponentName("com.oneplus.security",
                        "com.oneplus.security.chainlaunch.view.ChainLaunchAppListActivity");
                break;
            default:
                break;
        }
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (componentName != null) {
            intent.setComponent(componentName);
        } else {
            intent.setAction(Settings.ACTION_SETTINGS);
        }
        return intent;
    }


}

方案三、双进程守护 + JobScheduler 保活

参考(【Android 进程保活】应用进程拉活 ( 双进程守护 + JobScheduler 保活 | 成功率最高 | 推荐使用 )-CSDN博客

1、JobService 代码


public class KeepAliveJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
        Log.i("KeepAliveJobService", "JobService onStartJob 开启");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            // 如果当前设备大于 7.0 , 延迟 5 秒 , 再次执行一次
            startJob(this);
        }

        // 判定本地前台进程是否正在运行
        boolean isLocalServiceRunning =
                ServiceUtils.isServiceRunning(this, LocalForegroundService.class.getName());
        if (!isLocalServiceRunning){
            startService(new Intent(this, LocalForegroundService.class));
        }

        // 判定远程前台进程是否正在运行
        boolean isRemoteServiceRunning =
                ServiceUtils.isServiceRunning(this, RemoteForegroundService.class.getName());
        if (!isRemoteServiceRunning){
            startService(new Intent(this, RemoteForegroundService.class));
        }

        return false;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        Log.i("KeepAliveJobService", "JobService onStopJob 关闭");
        return false;
    }

    public static void startJob(Context context){
        // 创建 JobScheduler
        JobScheduler jobScheduler =
                (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);

        // 第一个参数指定任务 ID
        // 第二个参数指定任务在哪个组件中执行
        // setPersisted 方法需要 android.permission.RECEIVE_BOOT_COMPLETED 权限
        // setPersisted 方法作用是设备重启后 , 依然执行 JobScheduler 定时任务
        JobInfo.Builder jobInfoBuilder = new JobInfo.Builder(10,
                new ComponentName(context.getPackageName(), KeepAliveJobService.class.getName()))
                .setPersisted(true);

        // 7.0 以下的版本, 可以每隔 5000 毫秒执行一次任务
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N){
            jobInfoBuilder.setPeriodic(5_000);

        }else{
            // 7.0 以上的版本 , 设置延迟 5 秒执行
            // 该时间不能小于 JobInfo.getMinLatencyMillis 方法获取的最小值
            jobInfoBuilder.setMinimumLatency(5_000);
        }

        // 开启定时任务
        jobScheduler.schedule(jobInfoBuilder.build());

    }
}
  
 

2、判定服务运行工具类



public class ServiceUtils {
    /**
     * 判定 Service 是否在运行
     * @param context
     * @return
     */
    public static boolean isServiceRunning(Context context, String serviceName){
        if(TextUtils.isEmpty(serviceName)) return false;

        ActivityManager activityManager =
                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

        // 最多获取 200 个正在运行的 Service
        List<ActivityManager.RunningServiceInfo> infos =
                activityManager.getRunningServices(200);

        // 遍历当前运行的 Service 信息, 如果找到相同名称的服务 , 说明某进程正在运行
        for (ActivityManager.RunningServiceInfo info: infos){
            if (TextUtils.equals(info.service.getClassName(), serviceName)){
                return true;
            }
        }

        return false;
    }
}
  

3、清单文件


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kim.hsl.two_progress_alive">

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Two_Progress_Alive">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- 本地提权前台服务 Service -->
        <service
            android:name=".LocalForegroundService"
            android:enabled="true"
            android:exported="true"></service>

        <!-- 本地服务 , API 18 ~ 25 以上的设备, 关闭通知到专用服务 -->
        <service
            android:name=".LocalForegroundService$CancelNotificationService"
            android:enabled="true"
            android:exported="true"></service>

        <!-- 远程提权前台服务 Service -->
        <service
            android:name=".RemoteForegroundService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote"></service>

        <!-- 远程服务 , API 18 ~ 25 以上的设备, 关闭通知到专用服务 -->
        <service
            android:name=".RemoteForegroundService$CancelNotificationService"
            android:enabled="true"
            android:exported="true"
            android:process=":remote"></service>

        <!-- JobScheduler 拉活 -->
        <service
            android:name=".KeepAliveJobService"
            android:enabled="true"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE"></service>

    </application>

</manifest>

4、MainActivity 代码


package kim.hsl.two_progress_alive;

import android.content.Intent;
import android.os.Build;
import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 通过前台 Service 提升应用权限
        // 启动普通 Service , 但是在该 Service 的 onCreate 方法中执行了 startForeground
        // 变成了前台 Service 服务
        startService(new Intent(this, LocalForegroundService.class));
        startService(new Intent(this, RemoteForegroundService.class));

        // JobScheduler 拉活
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            KeepAliveJobService.startJob(this);
        }
    }
}

方案四、使用系统服务的return START_STICKY

START_STICKY:

“粘性”。如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。

START_NOT_STICKY:

“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。

START_REDELIVER_INTENT:

重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。

START_STICKY_COMPATIBILITY:

START_STICKY的兼容版本,但不保证服务被kill后一定能重启。

只要 targetSdkVersion 不小于5,就默认是 START_STICKY。 但是某些ROM 系统不会拉活。并且经过测试,Service 第一次被异常杀死后很快被重启,第二次会比第一次慢,第三次又会比前一次慢,一旦在短时间内 Service 被杀死4-5次,则系统不再拉起。

原文链接:Android 给App保活(10种方案)_android app保活_zhang_senlin的博客-CSDN博客

public int onStartCommand(Intent intent, int flags, int startId) {

......

return START_STICKY;

}

优点:利用services自身的api,可靠。

缺点:很多手机厂商已经做限制,导致很多类似华为、小米手机无效。只会重启5次。被系统强制停止也无法重启。

方案五、一像素

参考(Android 传说中的1像素保活大法-面圈网

1、Activity


public class HooliganActivity extends Activity {
        private static HooliganActivity instance;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            instance = this;
            Window window = getWindow();
            window.setGravity(Gravity.LEFT | Gravity.TOP);
            WindowManager.LayoutParams params = window.getAttributes();
            params.x = 0;
            params.y = 0;
            params.height = 1;
            params.width = 1;
            window.setAttributes(params);
        }
    
        /**
         * 开启保活页面
         */
        public static void startHooligan() {
            Intent intent = new Intent(DWApplication.getAppContext(), HooliganActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            DWApplication.getAppContext().startActivity(intent);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            instance = null;
        }
    
        /**
         * 关闭保活页面
         */
        public static void killHooligan() {
            if(instance != null) {
                instance.finish();
            }
        }
    }

2.注册清单文件:


    <activity android:name=".activity.HooliganActivity"
    android:configChanges="keyboardHidden|orientation|screenSize|navigation|keyboard"
    android:excludeFromRecents="true"
    android:exported="false"
    android:finishOnTaskLaunch="false"
    android:launchMode="singleInstance"
    android:theme="@style/HooliganActivityStyle"/>

   <style name="HooliganActivityStyle">
        <item name="android:windowBackground">@color/transparent</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowNoDisplay">false</item>
        <item name="android:windowDisablePreview">true</item>
    </style>

3、监听锁屏和解锁通知,不能静态注册广播,只能动态注册:


IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_SCREEN_ON);
    filter.addAction(Intent.ACTION_SCREEN_OFF);
    registerReceiver(new BootCompleteReceiver(),filter);

4、分别在解锁和锁屏时唤醒我的HooliganActivity:


 public class BootCompleteReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                HooliganActivity. startHooligan();
            } else if(intent.getAction().equals(Intent.ACTION_SCREEN_ON)){
                HooliganActivity. killHooligan();
            }
        }
    }

5、在最近使用的列表中隐藏应用


Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.addCategory(Intent.CATEGORY_HOME);
    getAppContext().startActivity(intent);

android:excludeFromRecents="true"

至此,整个的保活就结束了 这样你在后台每次锁屏,实际上都会吊起一个一像素的页面,假装app在前台,拥有最高进程优先级。

方案六、无声音乐


import android.media.MediaPlayer;
import java.io.File;
import java.io.IOException;
import java.io.FileOutputStream;
import android.util.Base64;
import java.io.FileInputStream;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class MySer extends Service {
    MediaPlayer mediaplayer=null;
    //转base64的音频文件
    String base64 = "AAAAGGZ0eXBtcDQyAAAAAG1wNDFpc29tAAAAKHV1aWRcpwj7Mo5CBahhZQ7KCpWWAAAADDEwLjAuMTgzNjMuMAAAAG5tZGF0AAAAAAAAABAnDEMgBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBAIBDSX5AAAAAAAAB9Pp9Pp9Pp9Pp9Pp9Pp9Pp9Pp9Pp9Pp9Pp9AAAC/m1vb3YAAABsbXZoZAAAAADeilCc3opQnAAAu4AAAAIRAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAHBdHJhawAAAFx0a2hkAAAAAd6KUJzeilCcAAAAAgAAAAAAAAIRAAAAAAAAAAAAAAAAAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAABXW1kaWEAAAAgbWRoZAAAAADeilCc3opQnAAAu4AAAAIRVcQAAAAAAC1oZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU291bmRIYW5kbGVyAAAAAQhtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAMxzdGJsAAAAZHN0c2QAAAAAAAAAAQAAAFRtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAAu4AAAAAAADBlc2RzAAAAAAOAgIAfAAAABICAgBRAFQAGAAACM2gAAjNoBYCAgAIRkAYBAgAAABhzdHRzAAAAAAAAAAEAAAABAAACEQAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAYc3RzegAAAAAAAAAAAAAAAQAAAF4AAAAUc3RjbwAAAAAAAAABAAAAUAAAAMl1ZHRhAAAAkG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXIAAAAAAAAAAAAAAAAAAAAAY2lsc3QAAAAeqW5hbQAAABZkYXRhAAAAAQAAAADlvZXpn7MAAAAcqWRheQAAABRkYXRhAAAAAQAAAAAyMDIyAAAAIWFBUlQAAAAZZGF0YQAAAAEAAAAA5b2V6Z+z5py6AAAAMVh0cmEAAAApAAAAD1dNL0VuY29kaW5nVGltZQAAAAEAAAAOABUA2rD/dVfYAQ==";
    
    @Override
    public void onCreate() {
        super.onCreate();
        
        if(mediaplayer==null){
            new Thread(new Runnable(){

                    @Override
                    public void run() {
                        mediaplayer=new MediaPlayer();
                        try {
                            byte[] mp3SoundByteArray = Base64.decode(base64, Base64.DEFAULT);// 将字符串转换为byte数组
                            File tempMp3 = File.createTempFile("s", ".mp3");
                            tempMp3.deleteOnExit();
                            FileOutputStream fos = new FileOutputStream(tempMp3);
                            fos.write(mp3SoundByteArray);
                            fos.close();
                            FileInputStream fis = new FileInputStream(tempMp3);
                            mediaplayer.setDataSource(fis.getFD());
                            mediaplayer.setLooping(true);
                            mediaplayer.prepareAsync ();//异步准备播放 这部必须设置不然无法播放
                            mediaplayer.start();//开始播放
                        } catch (IllegalStateException e) {
                            System.out.print("出错了="+e);
                        } catch (SecurityException e) {} catch (IOException e) {
                            System.out.print("出错了="+e);
                        } catch (IllegalArgumentException e) {}
                    }
                }).start();

        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //停止
        mediaplayer.stop();
        mediaplayer=null;
    }
    @Override
    public IBinder onBind(Intent intent) {

        return null;
    }
}

方案七、推送互相唤醒复活

......

方案八、app相互拉活

.......

  • 1
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android原生开发是指使用Android SDK提供的工具和API,使用Java或Kotlin编写应用程序的开发方式。与使用跨平台框架如React Native或Flutter进行开发不同,原生开发可以充分利用Android设备的特性和功能,提供更好的性能和用户体验。 Android原生开发的优势在于可以直接调用系统提供的各种功能与服务,如摄像头、传感器、定位、通知等,使得应用程序能够更好地与硬件进行交互。此外,Android原生开发可以充分利用Android SDK中提供的广泛的API,包括UI组件、多媒体、网络、数据库等,以及许多第三方库和插件,使得开发过程更加灵活和高效。 Android原生开发的另一个重要特点是可以适应不同的设备和屏幕尺寸,通过适配不同的布局、样式和分辨率,使得应用程序在各种设备上都能够良好地运行和展示。此外,原生开发还可以充分利用设备的性能和资源,提供更好的响应速度和流畅度。 然而,Android原生开发也存在一些挑战。首先,与使用跨平台框架相比,原生开发需要更多的学习和了解Android系统和API的知识,对开发者的技术要求较高。其次,对于需要在多个平台上开发的应用程序来说,原生开发需要分别开发和维护各个平台的代码,增加了开发的复杂性和工作量。最后,由于Android系统的不断更新和改进,原生开发需要及时跟进和适应新的API和特性,对开发者来说可能需要持续的学习和更新。 总之,尽管Android原生开发需要具备一定的技术功底和对Android系统的了解,但它可以充分利用Android设备的特性和功能,提供更好的性能和用户体验,适应不同的设备和屏幕尺寸。对于注重性能和用户体验的应用程序来说,原生开发是一种值得选择的开发方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值