同步操作将从 neo-android/MyAgent 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
└── com
└── tiny
└── myagent
├── broadcast // 接收开机广播,实现开机自启动
├── enums // 关机、重启枚举
├── MainActivity.java // 主类
├── util // 工具类
└── websocket // web-socket连接
安卓端使用Java-WebSocket:1.4.0
依赖,创建web-socket连接
dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation "org.java-websocket:Java-WebSocket:1.4.0"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
package com.tiny.myagent.im;
import android.util.Log;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import java.net.URI;
public class JWebSocketClient extends WebSocketClient {
public JWebSocketClient(URI serverUri) {
super(serverUri, new Draft_6455());
}
@Override
public void onOpen(ServerHandshake handshakedata) {
Log.e("JWebSocketClient", "onOpen()");
}
@Override
public void onMessage(String message) {
Log.e("JWebSocketClient", "onMessage()");
}
@Override
public void onClose(int code, String reason, boolean remote) {
Log.e("JWebSocketClient", "onClose()");
}
@Override
public void onError(Exception ex) {
Log.e("JWebSocketClient", "onError()" + ex.getMessage());
}
}
/**
* 初始化websocket连接
*/
private void initSocketClient() {
URI uri = URI.create(Util.ws);
client = new JWebSocketClient(uri) {
@Override
public void onMessage(String message) {
Log.e("JWebSocketClientService", "收到的消息:" + message);
BootAction action = BootAction.getReboot(message);
if (action != null) {
BootUtil.downAndReboot(action);
}
Intent intent = new Intent();
intent.setAction("com.tiny.myagent");
intent.putExtra("message", message);
sendBroadcast(intent);
}
@Override
public void onOpen(ServerHandshake handshakedata) {
super.onOpen(handshakedata);
Log.e("JWebSocketClientService", "websocket连接成功");
}
};
connect();
}
private static final long HEART_BEAT_RATE = 10 * 1000;//每隔10秒进行一次对长连接的心跳检测
private Handler mHandler = new Handler();
private Runnable heartBeatRunnable = new Runnable() {
@Override
public void run() {
Log.e("JWebSocketClientService", "心跳包检测websocket连接状态");
try {
sendMsg("这里是客户端MAC:==>" + NetWorkUtil.getDeviceMacAddress());
} catch (Exception e) {
Log.e("获取mac地址异常", e.toString());
}
if (client != null) {
if (client.isClosed()) {
reconnectWs();
}
} else {
//如果client已为空,重新初始化连接
client = null;
initSocketClient();
}
//每隔一定的时间,对长连接进行一次心跳检测
mHandler.postDelayed(this, HEART_BEAT_RATE);
}
};
/**
* 开启重连
*/
private void reconnectWs() {
mHandler.removeCallbacks(heartBeatRunnable);
new Thread() {
@Override
public void run() {
try {
Log.e("JWebSocketClientService", "开启重连");
client.reconnectBlocking();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
目前websocket
的服务地址在util/Util类中,可以配置自己的服务端地址(可以使用Java的springboot快速实现服务)
public class Util {
//websocket测试地址
public static final String ws = "ws://ip:port/websocket/neo";
public static void showToast(Context ctx, String msg) {
Toast.makeText(ctx, msg, Toast.LENGTH_LONG).show();
}
}
在AndroidManifest.xml
中添加权限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.tiny.myagent"
android:sharedUserId="android.uid.system">
<!--允许程序开机自动运行-->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!--允许程序在手机屏幕关闭后后台进程仍然运行-->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!--网络权限-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 解锁屏幕需要的权限 -->
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<!-- 申请电源锁需要的权限 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!--震动权限-->
<uses-permission android:name="android.permission.VIBRATE" />
<!--android 9.0之后使用前台服务,需要添加权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyAgent"
tools:targetApi="31">
<service
android:name=".websocket.JWebSocketClientService"
android:enabled="true"
android:exported="true" />
<service
android:name=".websocket.JWebSocketClientService$GrayInnerService"
android:enabled="true"
android:exported="false"
android:process=":gray" />
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--注册开机广播地址-->
<receiver
android:name=".broadcast.BootCompleteReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<!-- 开机广播 -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
<!-- <category android:name="android.intent.category.DEFAULT" />-->
</intent-filter>
<!-- 解锁广播 -->
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT" />
<!-- <category android:name="android.intent.category.DEFAULT" />-->
</intent-filter>
<!--亮屏-->
<intent-filter>
<action android:name="android.intent.action.ACTION_SCREEN_ON" />
<!-- <category android:name="android.intent.category.DEFAULT" />-->
</intent-filter>
<!--熄屏-->
<intent-filter>
<action android:name="android.intent.action.ACTION_SCREEN_OFF" />
<!--<category android:name="android.intent.category.DEFAULT" />-->
</intent-filter>
</receiver>
</application>
</manifest>
接收广播
package com.tiny.myagent.broadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.util.Log;
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("开机自启==", "我接收到广播啦");
PackageManager packageManager = context.getPackageManager();
intent = packageManager.getLaunchIntentForPackage("com.tiny.myagent");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
/*Intent it = new Intent(context, MainActivity.class);
it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(it);*/
switch (intent.getAction()) {
case Intent.ACTION_BOOT_COMPLETED:
Log.i("开机自启==", "手机开机了");
break;
case Intent.ACTION_SHUTDOWN:
Log.i("开机自启==", "手机关机了");
break;
case Intent.ACTION_SCREEN_ON:
Log.i("开机自启==", "亮屏");
break;
case Intent.ACTION_SCREEN_OFF:
Log.i("开机自启==", "息屏");
break;
case Intent.ACTION_USER_PRESENT:
Log.i("开机自启==", "手机解锁");
break;
}
}
}
目前测试了android 7.1.1
、android 9.0
、android 10.0
三个版本,均可实现开机自启、关机、重启🚗🚗🚗
由于之前没写过Android代码,经过测试需要先下载好对应版本的SDK,目前还不知道具体原因。
由于实现关机和重启需要系统权限,所以需要在AndroidManifest.xml
中配置系统权限
配置该权限后需要使用android
的密钥对进行签名,目前使用的是原生安卓的密钥对,如果使用厂商的板子,需要厂商提供该密钥对。可以在该地址获取target/product/security - platform/build - Git at Google (googlesource.com)
首先下载工具https://github.com/getfatday/keytool-importkeypair.git
生成命令
sh keytool-importkeypair -k giftedcat.jks -p 123456 -pk8 platform.pk8 -cert platform.x509.pem -alias agent
#解释
sh keytool-importkeypair -k 密钥名称 -p 密码 -pk8 platform.pk8 -cert platform.x509.pem -alias 别名
编辑app
下的build.gradle
文件
signingConfigs {
debug {
storeFile file('../key/giftedcat.jks')
storePassword '123456'
keyAlias 'agent'
keyPassword '123456'
}
release {
storeFile file('../key/giftedcat.jks')
storePassword '123456'
keyAlias 'agent'
keyPassword '123456'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug
}
}
使用sign-util
下的工具可以对现有的apk安装包进行签名
java -jar signapk.jar platform.x509.pem platform.pk8 签名前.apk 签名后.apk
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。