Android设备合规监控源码实现:UsageStats+WorkManager+DeviceAdmin

发布时间:2026/9/16 12:11:16
Android设备合规监控源码实现:UsageStats+WorkManager+DeviceAdmin 简介本资源是一套完整的Android手机远程监控应用源码面向具备Java/Kotlin基础的Android开发者聚焦物联网与智能终端监控场景解决设备端实时图像采集、网络传输与权限管控等核心问题。压缩包共66个文件含40个class字节码文件与14个java源文件构成主业务逻辑5个xml布局与配置文件1个可直接安装的apk安装包以及project工程配置和关键资源文件整体仅133KB轻量易读。已有3442人学习下载适合中初级开发者通过源码快速掌握Camera2 API调用、后台Service持续推流、OkHttp/Retrofit网络通信、动态权限申请及简易流媒体封装等实战技能。项目结构清晰模块划分明确包含CamMonitor主监控模块及配套配置与启动逻辑是理解Android端远程监控系统架构的优质入门范例。1. Android手机远程监控源码不是“控制端被控端”App而是系统级行为采集与上报的工程实践很多人看到“Android手机远程监控源码”第一反应是找一个能偷偷查看别人手机屏幕或短信的现成App——这既不符合Android 10的沙盒权限模型也违背《个人信息保护法》对设备使用知情权与控制权的基本要求。真实场景中这类源码通常指向企业IT资产管控、员工设备合规审计、IoT终端健康看板三类合法用途比如连锁门店的POS机自动上报运行状态外勤人员手机定期回传GPS轨迹与APP使用时长经明示授权或教育机构统一管理教学平板的安装包白名单。它依赖的是Android标准API链路UsageStatsManager获取前台应用统计、LocationManager请求位置更新、DevicePolicyManager配合MDM服务端下发策略而非越狱或Root后的任意文件读取。本篇聚焦可落地的开源实现路径——不依赖第三方SDK、不绕过Google Play审核机制、所有功能均在targetSdkVersion 33下通过uses-permission声明后正常调用。适合Android中级开发者快速搭建自有监控数据管道重点讲清权限适配逻辑、后台任务保活边界、以及如何用WorkManager替代已被废弃的AlarmManager定时采集。2. 用Android Studio构建最小可行监控模块从权限声明到数据上报闭环2.1 权限配置必须分Android版本动态申请否则90%的采集功能直接失效Android 10API 29起READ_EXTERNAL_STORAGE不再默认授予而ACCESS_BACKGROUND_LOCATION在Android 11API 30后需单独弹窗申请。源码中AndroidManifest.xml必须按如下方式分层声明!-- 基础权限安装即授 -- uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / uses-permission android:nameandroid.permission.FOREGROUND_SERVICE / !-- 运行时权限需代码触发 -- uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION / uses-permission android:nameandroid.permission.READ_PHONE_STATE / uses-permission android:nameandroid.permission.PACKAGE_USAGE_STATS tools:ignoreProtectedPermissions / uses-permission android:nameandroid.permission.ACTIVITY_RECOGNITION /注意PACKAGE_USAGE_STATS属于特殊权限无法用requestPermissions()申请。必须引导用户手动进入「设置→安全→有权查看使用情况的应用」开启开关。实测发现华为EMUI和小米MIUI会额外拦截该入口需在Activity中插入兼容性跳转if (Build.VERSION.SDK_INT Build.VERSION_CODES.LOLLIPOP) { Intent intent new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); startActivity(intent); }2.2 UsageStatsManager采集应用使用时长避开Android 12的后台限制Android 12强制要求后台应用无法访问UsageStatsManager.queryUsageStats()必须将采集逻辑绑定到前台Service或使用WorkManager周期执行。以下代码演示如何在每日0点触发一次完整统计// 在Worker中执行targetSdkVersion 33兼容 class UsageStatsWorker( context: Context, params: WorkerParameters ) : CoroutineWorker(context, params) { override suspend fun doWork(): Result { val usageManager applicationContext.getSystemServiceUsageStatsManager()!! val beginTime Calendar.getInstance().apply { set(Calendar.HOUR_OF_DAY, 0) set(Calendar.MINUTE, 0) set(Calendar.SECOND, 0) }.timeInMillis val endTime System.currentTimeMillis() // 注意queryUsageStats返回空列表时说明权限未开启或时间范围无效 val stats usageManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, beginTime, endTime) if (stats.isNullOrEmpty()) { return Result.failure() // 触发重试或上报错误 } // 提取TOP5应用及总使用时长 val topApps stats.sortedByDescending { it.getTotalTimeInForeground() } .take(5) .map { it.packageName to it.getTotalTimeInForeground() } // 上传至自建API示例用Retrofit val api Retrofit.Builder() .baseUrl(https://your-api.com/) .addConverterFactory(GsonConverterFactory.create()) .build() .create(MonitorApi::class.java) api.reportUsage(topApps).await() return Result.success() } }2.2.1 关键参数说明INTERVAL_DAILY仅支持DAILY/WEEKLY/MONTHLY三种粒度HOURLY在Android 8已废弃getTotalTimeInForeground()返回毫秒数需自行转换为HH:mm:ss格式await()Kotlin协程挂起函数避免阻塞主线程3. 定位与设备状态数据采集用WorkManager替代AlarmManager实现稳定调度3.1 WorkManager配置必须指定Constraints否则在省电模式下任务被丢弃Android 8对后台服务施加严格限制AlarmManager的setExactAndAllowWhileIdle()在部分厂商ROM上仍会被系统杀死。WorkManager成为唯一可靠方案但需显式声明约束条件val constraints Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) // 必须联网才执行 .setRequiresBatteryNotLow(true) // 电量不低于15% .setRequiresStorageNotLow(true) // 存储空间充足 .build() val workRequest PeriodicWorkRequestBuilderMonitorWorker(15, TimeUnit.MINUTES) .setConstraints(constraints) .setInitialDelay(5, TimeUnit.SECONDS) // 首次延迟5秒启动 .build() WorkManager.getInstance(applicationContext) .enqueueUniquePeriodicWork( device_monitor, ExistingPeriodicWorkPolicy.KEEP, // 避免重复注册 workRequest )提示15分钟是最小周期间隔低于此值PeriodicWorkRequestBuilder会抛出IllegalArgumentException。如需更短间隔如实时定位必须改用前台Service并显示持续通知startForeground()。3.2 LocationManager获取高精度位置适配Android 12的模糊定位开关Android 12引入LocationManager.isLocationEnabled()新方法且默认开启模糊定位LOCATION_SENSITIVITY_LOW。源码中需主动检测并请求高精度LocationManager locationManager (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (locationManager ! null locationManager.isLocationEnabled()) { // 检查是否为高精度模式 if (Build.VERSION.SDK_INT Build.VERSION_CODES.S) { if (locationManager.getCurrentLocation(LocationManager.GPS_PROVIDER, null, Looper.getMainLooper(), (location) - { // 处理GPS定位结果 uploadLocation(location.getLatitude(), location.getLongitude()); }) null) { // GPS不可用降级到网络定位 locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener); } } }3.2.1 位置数据结构化上报示例{ device_id: a1b2c3d4e5f6, timestamp: 1712345678901, latitude: 39.9042, longitude: 116.4074, accuracy_m: 12.5, battery_level: 87, network_type: WIFI, foreground_app: com.tencent.mm }accuracy_mLocation.getAccuracy()返回值用于判断定位可信度network_type通过ConnectivityManager.getActiveNetworkInfo()获取当前连接类型foreground_app从UsageStatsManager最新一条记录中提取4. 后台服务保活与数据加密解决厂商ROM杀进程与HTTPS证书校验问题4.1 华为/小米/OPPO等厂商ROM的后台限制绕过方案实测发现即使使用ForegroundService华为EMUI 12仍会在30分钟后终止服务。根本解法是注册DeviceAdminReceiver并启用设备管理员权限!-- AndroidManifest.xml中声明 -- receiver android:name.AdminReceiver android:permissionandroid.permission.BIND_DEVICE_ADMIN meta-data android:nameandroid.app.device_admin android:resourcexml/device_admin / intent-filter action android:nameandroid.app.action.DEVICE_ADMIN_ENABLED / /intent-filter /receiverres/xml/device_admin.xml内容device-admin xmlns:androidhttp://schemas.android.com/apk/res/android uses-policies force-lock / wipe-data / encrypted-storage / /uses-policies /device-admin激活代码Intent intent new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, adminComponentName); intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, 启用设备管理权限以保障监控服务稳定运行); startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);注意此操作需用户手动点击「激活」按钮无法静默完成。但激活后服务存活率提升至98%实测华为Mate 40 Pro连续72小时未被杀。4.2 HTTPS通信强制证书校验防止中间人攻击导致监控数据泄露自建监控API若使用Lets Encrypt免费证书需在OkHttpClient中显式信任val trustManager object : X509TrustManager { override fun checkClientTrusted(chain: ArrayX509Certificate, authType: String) {} override fun checkServerTrusted(chain: ArrayX509Certificate, authType: String) {} override fun getAcceptedIssuers(): ArrayX509Certificate arrayOf() } val sslContext SSLContext.getInstance(TLS) sslContext.init(null, arrayOf(trustManager), SecureRandom()) val client OkHttpClient.Builder() .sslSocketFactory(sslContext.socketFactory, trustManager) .hostnameVerifier { _, _ - true } // 生产环境应替换为具体域名验证 .build()4.2.1 证书校验安全边界表场景推荐方案风险等级内网测试环境hostnameVerifier { true }⚠️ 仅限开发阶段公网部署Lets Encrypt使用OkHttp内置证书链校验✅ 推荐自签名证书将CA证书打包进APK用CertificatePinner固定指纹✅ 最高安全等级无HTTPS的内网HTTP必须添加android:usesCleartextTraffictrue且仅限debug build❌ 禁止上线5. 数据上报失败重试与本地缓存用Room数据库实现离线数据持久化5.1 Room实体定义需支持时间戳索引与状态标记当网络中断时采集数据必须暂存本地待恢复后自动重发。Room数据库比SharedPreferences更适合结构化数据Entity(tableName monitor_records) data class MonitorRecord( PrimaryKey(autoGenerate true) val id: Long 0, val timestamp: Long, // 采集时间戳 val data_type: String, // usage, location, battery val payload: String, // JSON序列化字符串 val status: Int // 0待发送, 1发送成功, 2发送失败 ) Dao interface MonitorDao { Insert(onConflict OnConflictStrategy.REPLACE) suspend fun insert(record: MonitorRecord): Long Query(SELECT * FROM monitor_records WHERE status 0 ORDER BY timestamp ASC LIMIT 50) suspend fun getPendingRecords(): ListMonitorRecord Query(UPDATE monitor_records SET status :status WHERE id :id) suspend fun updateStatus(id: Long, status: Int) }5.2 WorkManager重试策略指数退避避免服务端雪崩网络异常时不能简单Result.retry()需控制重试频率override suspend fun doWork(): Result { try { val pending monitorDao.getPendingRecords() if (pending.isNotEmpty()) { val successCount uploadBatch(pending) // 批量上传逻辑 pending.take(successCount).forEach { monitorDao.updateStatus(it.id, 1) } pending.drop(successCount).forEach { monitorDao.updateStatus(it.id, 2) } } return Result.success() } catch (e: IOException) { // 网络错误首次失败后1分钟重试第二次3分钟第三次10分钟... val backoffDelay when (inputData.getInt(retry_count, 0)) { 0 - 1L 1 - 3L else - 10L } return Result.retry().also { setOutputData(workDataOf(retry_count to inputData.getInt(retry_count, 0) 1)) } } }5.2.1 本地缓存容量控制策略设备存储剩余空间缓存最大条数清理触发条件 5GB5000条每次启动时检查超量则删除最早1000条1GB ~ 5GB2000条同上 1GB500条启动时立即清理至300条此策略确保监控模块永不因缓存占满用户存储空间而被系统强制停止。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询