后台保活
之前用的比较多的方案: 1 个像素的 Activity,播放无声音频,双进程互相守护等。
后台运行白名单
从 Android 6.0 开始,系统为了省电增加了休眠模式,系统待机一段时间后,会杀死后台正在运行的进程。但系统会有一个后台运行白名单,白名单里的应用将不会受到影响,在原生系统下,通过「设置」 - 「电池」 - 「电池优化」 - 「未优化应用」,可以看到这个白名单。
目前系统允许我们申请把应用加入白名单中,具体步骤为:
- 首先,在 AndroidManifest.xml 文件中配置一下权限:
复制代码
1
2<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
- 判断我们的应用是否在白名单中:
复制代码
1
2
3
4
5
6
7
8
9
10
11@RequiresApi(api = Build.VERSION_CODES.M) private boolean isIgnoringBatteryOptimizations() { boolean isIgnoring = false; PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); if (powerManager != null) { isIgnoring = powerManager.isIgnoringBatteryOptimizations(getPackageName()); } return isIgnoring; }
- 申请加入白名单
复制代码
1
2
3
4
5
6
7
8
9
10
11@RequiresApi(api = Build.VERSION_CODES.M) public void requestIgnoreBatteryOptimizations() { try { Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } catch (Exception e) { e.printStackTrace(); } }
- 常用代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/** * 跳转到指定应用的首页 */ private void showActivity(@NonNull String packageName) { Intent intent = getPackageManager().getLaunchIntentForPackage(packageName); startActivity(intent); } /** * 跳转到指定应用的指定页面 */ private void showActivity(@NonNull String packageName, @NonNull String activityDir) { Intent intent = new Intent(); intent.setComponent(new ComponentName(packageName, activityDir)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); }
- 如果能把应用加入厂商系统的后台管理白名单,可以进一步降低进程被杀的概率。不同的厂商在不同的地方进行设置,一般是在各自的「手机管家」。以下为大部分手机的厂商判断,跳转方法及对应设置步骤:
华为
操作步骤:应用启动管理 -> 关闭应用开关 -> 打开允许自启动
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public boolean isHuawei() { if (Build.BRAND == null) { return false; } else { return Build.BRAND.toLowerCase().equals("huawei") || Build.BRAND.toLowerCase().equals("honor"); } } private void goHuaweiSetting() { try { showActivity("com.huawei.systemmanager", "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity"); } catch (Exception e) { showActivity("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.bootstart.BootStartActivity"); } }
小米
代码操作步骤:授权管理 -> 自启动管理 -> 允许应用自启动
复制代码
1
2
3
4
5
6
7
8
9public static boolean isXiaomi() { return Build.BRAND != null && Build.BRAND.toLowerCase().equals("xiaomi"); } private void goXiaomiSetting() { showActivity("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity"); }
OPPO
代码操作步骤:权限隐私 -> 自启动管理 -> 允许应用自启动
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public static boolean isOPPO() { return Build.BRAND != null && Build.BRAND.toLowerCase().equals("oppo"); } private void goOPPOSetting() { try { showActivity("com.coloros.phonemanager"); } catch (Exception e1) { try { showActivity("com.oppo.safe"); } catch (Exception e2) { try { showActivity("com.coloros.oppoguardelf"); } catch (Exception e3) { showActivity("com.coloros.safecenter"); } } } }
VIVO
代码操作步骤:权限管理 -> 自启动 -> 允许应用自启动
复制代码
1
2
3
4
5
6
7
8public static boolean isVIVO() { return Build.BRAND != null && Build.BRAND.toLowerCase().equals("vivo"); } private void goVIVOSetting() { showActivity("com.iqoo.secure"); }
魅族
代码操作步骤:权限管理 -> 后台管理 -> 点击应用 -> 允许后台运行
复制代码
1
2
3
4
5
6
7
8public static boolean isMeizu() { return Build.BRAND != null && Build.BRAND.toLowerCase().equals("meizu"); } private void goMeizuSetting() { showActivity("com.meizu.safe"); }
三星
代码操作步骤:自动运行应用程序 -> 打开应用开关 -> 电池管理 -> 未监视的应用程序 -> 添加应用
复制代码
1
2
3
4
5
6
7
8
9
10
11
12public static boolean isSamsung() { return Build.BRAND != null && Build.BRAND.toLowerCase().equals("samsung"); } private void goSamsungSetting() { try { showActivity("com.samsung.android.sm_cn"); } catch (Exception e) { showActivity("com.samsung.android.sm"); } }
心跳分析
Socket tcp心跳包的机制
一、首先服务器和客户端有一次“握手
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public void connect() { LogUtil.e(TAG, "准备链接..."); InetAddress serverAddr; try { socket = new Socket(Config.Host, Config.SockectPort); _connect = true; mReceiveThread = new ReceiveThread(); receiveStop = false; mReceiveThread.start(); LogUtil.e(TAG, "链接成功."); } catch (Exception e) { LogUtil.e(TAG, "链接出错." + e.getMessage().toString()); e.printStackTrace(); } }
二、下面就要开启一个线程 去不断读取服务器那边传过来的数据 采用Thread去实现
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64private class ReceiveThread extends Thread { private byte[] buf; private String str = null; @Override public void run() { while (true) { try { // LogUtil.e(TAG, "监听中...:"+socket.isConnected()); if (socket!=null && socket.isConnected()) { if (!socket.isInputShutdown()) { BufferedReader inStream = new BufferedReader( new InputStreamReader( socket.getInputStream())); String content = inStream.readLine(); if (content == null) continue; LogUtil.e(TAG, "收到信息:" + content); LogUtil.e(TAG, "信息长度:"+content.length()); if (!content.startsWith("CMD:")) continue; int spacePos = content.indexOf(" "); if (spacePos == -1) continue; String cmd = content.substring(4, spacePos); // String body = StringUtil.DecodeBase64(content // .substring(spacePos)); String body = content.substring(spacePos).trim(); LogUtil.e(TAG, "收到信息(CMD):" + cmd); LogUtil.e(TAG, "收到信息(BODY):" + body); if (cmd.equals("LOGIN")) { // 登录 ReceiveLogin(body); continue; } if (cmd.equals("KEEPLIVE")) { if (!body.equals("1")) { Log.e(TAG, "心跳时检测到异常,重新登录!"); socket = null; KeepAlive(); } else { Date now = Calendar.getInstance().getTime(); lastKeepAliveOkTime = now; } continue; } } } else { if(socket!=null) LogUtil.e(TAG, "链接状态:" + socket.isConnected()); } } catch (Exception e) { LogUtil.e(TAG, "监听出错:" + e.toString()); e.printStackTrace(); } } }
三 、 Socket 是否断开了 断开了 需要重新去连接
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67public void KeepAlive() { // 判断socket是否已断开,断开就重连 if (lastKeepAliveOkTime != null) { LogUtil.e( TAG, "上次心跳成功时间:" + DateTimeUtil.dateFormat(lastKeepAliveOkTime, "yyyy-MM-dd HH:mm:ss")); Date now = Calendar.getInstance().getTime(); long between = (now.getTime() - lastKeepAliveOkTime.getTime());// 得到两者的毫秒数 if (between > 60 * 1000) { LogUtil.e(TAG, "心跳异常超过1分钟,重新连接:"); lastKeepAliveOkTime = null; socket = null; } } else { lastKeepAliveOkTime = Calendar.getInstance().getTime(); } if (!checkIsAlive()) { LogUtil.e(TAG, "链接已断开,重新连接."); connect(); if (loginPara != null) Login(loginPara); } //此方法是检测是否连接 boolean checkIsAlive() { if (socket == null) return false; try { socket.sendUrgentData(0xFF); } catch (IOException e) { return false; } return true; } //然后发送数据的方法 public void sendmessage(String msg) { if (!checkIsAlive()) return; LogUtil.e(TAG, "准备发送消息:" + msg); try { if (socket != null && socket.isConnected()) { if (!socket.isOutputShutdown()) { PrintWriter outStream = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())), true); outStream.print(msg + (char) 13 + (char) 10); outStream.flush(); } } LogUtil.e(TAG, "发送成功!"); } catch (Exception e) { e.printStackTrace(); } }
最后
以上就是沉默煎饼最近收集整理的关于android 后台保活+心跳分析的全部内容,更多相关android内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复