feat: 设备端 Agent 首个版本——剪贴板注入 / 应用商店 / 身份显示 / 配置下发
配合 auto_control 平台的设备端补位 App(接口契约见 INTERFACE.md,与平台仓库
doc/DEVICE_AGENT.md 是同一份)。
四个 adb 可拉起的 Activity + 一个商店界面:
- ClipActivity 剪贴板注入(透明 Activity,**必须等窗口获得焦点再写** ——
Android 10+ 只有前台应用能写剪贴板,这正是 u2 set_clipboard
"成功但内容被丢弃"的原因);写完立即退出,不驻留
- InfoActivity 全屏大字显示设备身份(名称/IP/序列号/平台地址),
替代原来"推 HTML 让设备浏览器打开"那套
- ConfigActivity 一次性配置下发(平台用 adb 把 server/token/指纹推进来),
一批设备不用一台台手输
- PingActivity 自检(版本/指纹/配置状态),结果写 logcat + 外部私有目录的
status.json,平台据此判断"装没装、哪一版"
- MainActivity 应用商店:拉平台清单 → 选应用 → 安装;已装的显示「已安装」,
有新版显示「更新到 vX」
实机踩出来的几个坑(都已处理):
- **应用身份读不到 ro.serialno**(shell 能读、应用被 SELinux 挡)→ 指纹改由平台
通过 ConfigActivity 下发(平台本来就知道),本机 getprop 只作兜底
- **Android 9+ 默认拦明文 HTTP** → 平台是局域网 http,需 usesCleartextTraffic
- **Android 11+ 软件包可见性** → 不加 QUERY_ALL_PACKAGES 会"明明装了却显示未安装"
- **MIUI 安装确认不止一步** → 装完检测窗口给到 3 分钟(人会依次点继续→勾选→继续更新)
- 上报带重试(实测遇到过一次网络抖动导致 timeout)
构建:JDK 17 + Android SDK(minSdk 29 / targetSdk 34),只依赖 androidx.core,
HTTP 用 HttpURLConnection、JSON 用系统内置 org.json。
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!--
|
||||
usesCleartextTraffic=true 的原因:平台跑在局域网里、只有 HTTP(没有 TLS),
|
||||
Android 9+ 默认会拦掉明文请求(实测报 "Cleartext HTTP traffic ... not permitted")。
|
||||
本 App 只连你在「配置」里填的那个平台地址,不传输用户隐私数据。
|
||||
将来平台上了 HTTPS,把 application 上那一行删掉即可。
|
||||
-->
|
||||
|
||||
<!-- 从平台拉应用清单 / 下载 APK -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<!-- 自己调系统安装器安装 APK(这正是绕开 MIUI「USB 安装」拦截的关键) -->
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<!--
|
||||
查询任意已安装应用的版本号 —— 用来在商店列表里显示「已安装 / 可更新 / 安装」。
|
||||
Android 11+ 默认限制了软件包可见性(不给的话 getPackageInfo 一律抛 NameNotFound,
|
||||
实测表现为"明明装了却全显示未安装");本 App 不是上架 Google Play 的应用,
|
||||
用这个权限没有商店审核问题。
|
||||
-->
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.DeviceAgent">
|
||||
|
||||
<!-- 主界面:应用商店(看清单、选应用、下载安装) -->
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- 剪贴板注入:透明 Activity,由平台用 adb am start 拉起
|
||||
(完整命令见 README「快速开始」,参数 text_b64 传 base64 文本) -->
|
||||
<activity
|
||||
android:name=".ClipActivity"
|
||||
android:exported="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true"
|
||||
android:theme="@style/Theme.DeviceAgent.Transparent" />
|
||||
|
||||
<!-- 身份显示:全屏大字,人在机架前一眼看出这台是平台的哪一台
|
||||
(参数 name / ip / serial / server,close=1 关闭;命令见 README) -->
|
||||
<activity
|
||||
android:name=".InfoActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:excludeFromRecents="true" />
|
||||
|
||||
<!-- 一次性配置下发(平台用 adb 推地址与令牌,省得每台手输) -->
|
||||
<activity
|
||||
android:name=".ConfigActivity"
|
||||
android:exported="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true"
|
||||
android:theme="@style/Theme.DeviceAgent.Transparent" />
|
||||
|
||||
<!-- 自检:平台用来判断"装没装、哪一版" -->
|
||||
<activity
|
||||
android:name=".PingActivity"
|
||||
android:exported="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true"
|
||||
android:theme="@style/Theme.DeviceAgent.Transparent" />
|
||||
|
||||
<!-- 把下载到私有目录的 APK 授权给系统安装器读 -->
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
</manifest>
|
||||
Reference in New Issue
Block a user