1 Star 0 Fork 5

huyande / MyAgent

forked from neo-android / MyAgent 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

使用websocket实现android在线状态监控,远程实现关机、重启

项目结构

└── com
    └── tiny
        └── myagent
            ├── broadcast // 接收开机广播,实现开机自启动
            ├── enums // 关机、重启枚举
            ├── MainActivity.java // 主类
            ├── util // 工具类
            └── websocket // web-socket连接

一、web-socket

1、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'
}

2、创建web-socket客户端

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());
    }
}

3、创建JWebSocketClientService继承Service

    /**
     * 初始化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();
    }

4、创建线程检测心跳

    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();
    }

5、配置websocket地址

目前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();
    }
}

二、开机自启实现

1、添加权限

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>

2、实现静态广播

接收广播

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.0android 10.0三个版本,均可实现开机自启、关机、重启🚗🚗🚗

1、提前准备SDK

由于之前没写过Android代码,经过测试需要先下载好对应版本的SDK,目前还不知道具体原因。

image-20220830221907686

2、配置plateform签名密钥对

由于实现关机和重启需要系统权限,所以需要在AndroidManifest.xml中配置系统权限

image-20220830222656858

配置该权限后需要使用android的密钥对进行签名,目前使用的是原生安卓的密钥对,如果使用厂商的板子,需要厂商提供该密钥对。可以在该地址获取target/product/security - platform/build - Git at Google (googlesource.com)

image-20220830223156248

3、生成密钥

首先下载工具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 别名

4、配置密钥

编辑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
        }
    }

四、测试

1、心跳检测

image-20220830224011176

2、服务端收到消息

image-20220830224050646

3、远程控制--发送消息

image-20220830224215011

4、客户端收到消息后执行关机

image-20220830224145817

五、对现有的apk进行签名

使用sign-util下的工具可以对现有的apk安装包进行签名

java -jar signapk.jar platform.x509.pem platform.pk8 签名前.apk 签名后.apk

六、致谢

本代码参考:https://gitee.com/richardxiong/web-socket.git

空文件

简介

安卓android实现开机自启、远程关机、远程重启demo 展开 收起
Java
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/huyande/my-agent.git
git@gitee.com:huyande/my-agent.git
huyande
my-agent
MyAgent
master

搜索帮助