赞
踩
目录
方案四、使用系统服务的return START_STICKY
4、分别在解锁和锁屏时唤醒我的HooliganActivity:
Android保活众所周知,完全保活除非加入白名单,否则只能保住一段时间。下面一一介绍Android保活方案。由于时间有限,保活方案文章的编写,采用的是逐步完善的方式。在保证内容可用的条件下逐步晚上文字,不足之处还请见谅。完善所有代码后,会写成uni-app插件。
代码
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;
- }
-
-
- }
参考(【Android 进程保活】应用进程拉活 ( 双进程守护 + JobScheduler 保活 | 成功率最高 | 推荐使用 )-CSDN博客)
-
- 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());
-
- }
- }
-
-
-
-
- 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;
- }
- }
-
-
- <?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>
-
- 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);
- }
- }
- }
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次。被系统强制停止也无法重启。
-
- 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();
- }
- }
- }
-
- <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>
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- registerReceiver(new BootCompleteReceiver(),filter);
-
- 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();
- }
- }
- }
-
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addCategory(Intent.CATEGORY_HOME);
- getAppContext().startActivity(intent);
<code class="language-plaintext hljs">android:excludeFromRecents="true"</code>
至此,整个的保活就结束了 这样你在后台每次锁屏,实际上都会吊起一个一像素的页面,假装app在前台,拥有最高进程优先级。
<code class="language-plaintext hljs">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;
}
}</code>
......
.......
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。