Compare commits
9 Commits
4ef4f6fe39
...
ac624c70b2
| Author | SHA1 | Date | |
|---|---|---|---|
| ac624c70b2 | |||
| 030e8250e6 | |||
| c0548705a2 | |||
| 6ae23c1e2f | |||
| bfc5a741a6 | |||
| cf5039ae63 | |||
| 46fe0c6d24 | |||
| e9b769be85 | |||
| cb660865a1 |
@@ -37,7 +37,8 @@ dependencies {
|
|||||||
implementation 'com.google.code.gson:gson:2.10'
|
implementation 'com.google.code.gson:gson:2.10'
|
||||||
// https://mvnrepository.com/artifact/com.jakewharton.timber/timber
|
// https://mvnrepository.com/artifact/com.jakewharton.timber/timber
|
||||||
implementation 'com.jakewharton.timber:timber:5.0.1'
|
implementation 'com.jakewharton.timber:timber:5.0.1'
|
||||||
|
// 添加 WorkManager 的依赖
|
||||||
|
implementation "androidx.work:work-runtime:2.7.0"
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||||
implementation 'com.google.android.material:material:1.3.0'
|
implementation 'com.google.android.material:material:1.3.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||||
<uses-permission android:name="android.permission.ACTION_NOTIFICATION_LISTENER_SETTINGS" />
|
<uses-permission android:name="android.permission.ACTION_NOTIFICATION_LISTENER_SETTINGS" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package com.nbee.echolink;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
public class DeviceInfo {
|
|
||||||
|
|
||||||
public static int getApiVersion() {
|
|
||||||
return Build.VERSION.SDK_INT;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,40 @@
|
|||||||
package com.nbee.echolink;
|
package com.nbee.echolink;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.work.ExistingPeriodicWorkPolicy;
|
||||||
|
import androidx.work.PeriodicWorkRequest;
|
||||||
|
import androidx.work.WorkManager;
|
||||||
|
|
||||||
|
import com.nbee.echolink.utils.HeartbeatWorker;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class EchoLink extends Application {
|
public class EchoLink extends Application {
|
||||||
|
private static final int EXECUTION_INTERVAL = 15; // 示例:15分钟
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
// 植入 Timber
|
// 植入 Timber
|
||||||
Timber.plant(new FileLoggingTree(this));
|
Timber.plant(new FileLoggingTree(this));
|
||||||
|
|
||||||
// 打印日志文件的路径
|
// 打印日志文件的路径
|
||||||
Timber.d("Log file path: " + this.getFilesDir() + "/logs/echoLink.log");
|
Timber.d("Log file path: " + this.getFilesDir() + "/logs/echoLink.log");
|
||||||
|
// 安排定时任务
|
||||||
|
doScheduledTask(this);
|
||||||
|
}
|
||||||
|
private void doScheduledTask(Context context){
|
||||||
|
Timber.d("start do scheduled task");
|
||||||
|
PeriodicWorkRequest heartbeatWorkRequest =
|
||||||
|
new PeriodicWorkRequest.Builder(HeartbeatWorker.class, EXECUTION_INTERVAL, TimeUnit.MINUTES)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 安排周期性工作
|
||||||
|
WorkManager.getInstance(context).enqueueUniquePeriodicWork("HeartbeatWork",
|
||||||
|
ExistingPeriodicWorkPolicy.KEEP,
|
||||||
|
heartbeatWorkRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,13 @@ import android.view.View;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.work.ExistingPeriodicWorkPolicy;
|
||||||
|
import androidx.work.PeriodicWorkRequest;
|
||||||
|
import androidx.work.WorkManager;
|
||||||
|
|
||||||
import com.nbee.echolink.service.MonitorService;
|
import com.nbee.echolink.service.MonitorService;
|
||||||
import com.nbee.echolink.utils.BatteryOptimizationUtil;
|
import com.nbee.echolink.utils.BatteryOptimizationUtil;
|
||||||
|
import com.nbee.echolink.utils.HeartbeatWorker;
|
||||||
import com.nbee.echolink.utils.PermissionUtils;
|
import com.nbee.echolink.utils.PermissionUtils;
|
||||||
import com.nbee.echolink.utils.ShellUtils;
|
import com.nbee.echolink.utils.ShellUtils;
|
||||||
|
|
||||||
@@ -20,6 +24,7 @@ import java.io.BufferedReader;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@@ -98,5 +103,4 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
return "读取日志文件时出错";
|
return "读取日志文件时出错";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
49
app/src/main/java/com/nbee/echolink/model/DeviceInfo.java
Normal file
49
app/src/main/java/com/nbee/echolink/model/DeviceInfo.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package com.nbee.echolink.model;
|
||||||
|
|
||||||
|
public class DeviceInfo {
|
||||||
|
private String deviceBrand;
|
||||||
|
private String deviceModel;
|
||||||
|
private String androidVersion;
|
||||||
|
|
||||||
|
public DeviceInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceInfo(String deviceBrand, String deviceModel, String androidVersion) {
|
||||||
|
this.deviceBrand = deviceBrand;
|
||||||
|
this.deviceModel = deviceModel;
|
||||||
|
this.androidVersion = androidVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceBrand() {
|
||||||
|
return deviceBrand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceBrand(String deviceBrand) {
|
||||||
|
this.deviceBrand = deviceBrand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceModel() {
|
||||||
|
return deviceModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeviceModel(String deviceModel) {
|
||||||
|
this.deviceModel = deviceModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAndroidVersion() {
|
||||||
|
return androidVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAndroidVersion(String androidVersion) {
|
||||||
|
this.androidVersion = androidVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "DeviceInfo{" +
|
||||||
|
"deviceBrand='" + deviceBrand + '\'' +
|
||||||
|
", deviceModel='" + deviceModel + '\'' +
|
||||||
|
", androidVersion='" + androidVersion + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,22 +20,6 @@ public class DeviceInfoUtils {
|
|||||||
public static int getDeviceHeight(Context context) {
|
public static int getDeviceHeight(Context context) {
|
||||||
return context.getResources().getDisplayMetrics().heightPixels;
|
return context.getResources().getDisplayMetrics().heightPixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取设备的唯一标识, 需要 “android.permission.READ_Phone_STATE”权限
|
|
||||||
* Android 10 无法获取此权限
|
|
||||||
*/
|
|
||||||
public static String getIMEI(Context context) {
|
|
||||||
TelephonyManager tm = (TelephonyManager) context
|
|
||||||
.getSystemService(Context.TELEPHONY_SERVICE);
|
|
||||||
String deviceId = tm.getDeviceId();
|
|
||||||
if (deviceId == null) {
|
|
||||||
return "UnKnown";
|
|
||||||
} else {
|
|
||||||
return deviceId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取厂商名
|
* 获取厂商名
|
||||||
**/
|
**/
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package com.nbee.echolink.utils;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.work.Worker;
|
||||||
|
import androidx.work.WorkerParameters;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.nbee.echolink.R;
|
||||||
|
import com.nbee.echolink.model.DeviceInfo;
|
||||||
|
import com.nbee.echolink.response.ApiResponse;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public class HeartbeatWorker extends Worker {
|
||||||
|
private final Context context;
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
|
||||||
|
public HeartbeatWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
||||||
|
super(context, workerParams);
|
||||||
|
this.context = context; // 保存上下文引用
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Result doWork() {
|
||||||
|
Context context = getApplicationContext();
|
||||||
|
// 在这里实现您的心跳发送逻辑
|
||||||
|
sendHeartbeatSignal();
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendHeartbeatSignal() {
|
||||||
|
String heartBeatURL = context.getResources().getString(R.string.heart_beat_url); // 获取URL
|
||||||
|
OkHttpClient client = new OkHttpClient();
|
||||||
|
Request request = buildRequest(heartBeatURL);
|
||||||
|
client.newCall(request).enqueue(new okhttp3.Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(okhttp3.Call call, IOException e) {
|
||||||
|
Timber.d("Request to " + heartBeatURL);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
// 在这里处理响应错误
|
||||||
|
Timber.d("Request to " + heartBeatURL + " returned error: " + response.code() + ", " + response.message());
|
||||||
|
throw new IOException("Unexpected code " + response);
|
||||||
|
}
|
||||||
|
// ... 处理响应 ...
|
||||||
|
Gson gson1 = new Gson();
|
||||||
|
ApiResponse apiResponse = gson1.fromJson(response.body().string(), ApiResponse.class);
|
||||||
|
if (apiResponse.getCode().equals(0)){
|
||||||
|
Timber.d("Received response from " + heartBeatURL + ": " + apiResponse.getCode() + " - " + apiResponse.getMsg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T>Request buildRequest(String apiUrl){
|
||||||
|
accessToken = context.getResources().getString(R.string.access_token);
|
||||||
|
DeviceInfo deviceInfo = new DeviceInfo();
|
||||||
|
deviceInfo.setDeviceBrand(DeviceInfoUtils.getDeviceBrand());
|
||||||
|
deviceInfo.setDeviceModel(DeviceInfoUtils.getDeviceModel());
|
||||||
|
deviceInfo.setAndroidVersion(DeviceInfoUtils.getDeviceAndroidVersion());
|
||||||
|
Gson gson = new Gson();
|
||||||
|
// 将对象转换为JSON字符串
|
||||||
|
String json = gson.toJson(deviceInfo);
|
||||||
|
Timber.d("Building request to " + apiUrl + " with data: " + json);
|
||||||
|
// 创建请求体
|
||||||
|
MediaType JSON = MediaType.get("application/json; charset=utf-8");
|
||||||
|
RequestBody body = RequestBody.create(json, JSON);
|
||||||
|
|
||||||
|
// 构建请求,并设置请求头
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(apiUrl)
|
||||||
|
.addHeader("accessToken", accessToken) // 使用加载的accessToken
|
||||||
|
.addHeader("Content-Type", "application/json")
|
||||||
|
.post(body)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
<string name="app_name">EchoLink</string>
|
<string name="app_name">EchoLink</string>
|
||||||
<string name="call_api_url">https://api.kimgo.cn/api/call</string>
|
<string name="call_api_url">https://api.kimgo.cn/api/call</string>
|
||||||
<string name="message_api_url">https://api.kimgo.cn/api/sms</string>
|
<string name="message_api_url">https://api.kimgo.cn/api/sms</string>
|
||||||
|
<string name="heart_beat_url">https://api.kimgo.cn/heartbeat</string>
|
||||||
<string name="access_token">gKGCDSgWV82XbU0H</string>
|
<string name="access_token">gKGCDSgWV82XbU0H</string>
|
||||||
<string name="notification_title">监控服务运行中</string>
|
<string name="notification_title">监控服务运行中</string>
|
||||||
<string name="notification_text">EchoLink正在运行</string>
|
<string name="notification_text">EchoLink正在运行</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user