首页/新闻资讯/正文详情

Android 监听用户打开系统相机录像行为:TaoToken 统一 Key 接入与配置验证

发布时间:2026/9/26 9:37:39 来源:云帆数科 栏目:资讯中心
Android 监听用户打开系统相机录像行为:TaoToken 统一 Key 接入与配置验证
1. 为什么 Android 端监听系统相机录像这么难Android 系统相机是一个相对独立的系统应用用户从桌面图标、锁屏快捷方式、第三方 App 的Intent拉起它之后录像文件最终会落到MediaStore里。很多做行为审计、家长守护、企业设备管理或者场景联动的开发者第一反应都是「我能不能监听用户打开相机并开始录像」。答案是可以但要分清楚你能拿到的是「录像完成后的回调」还是「录像进行中的状态」——这两件事在 Android 上的实现路径完全不同。我先把结论摆出来Android 没有官方 API 让你实时知道「用户此刻正在录像」但你可以通过MediaStore的ContentObserver感知新视频落盘通过系统相机广播部分 ROM 支持感知录像完成事件再配合前台应用检测判断当前是不是相机在前台。三者组合起来就能在真机上稳定复现「用户打开系统相机录像」这个行为的监听结果。这篇面向需要做行为审计或场景联动的开发者给出可复制的权限与清单配置、监听回调骨架以及用 TaoToken 统一 Key/API 通道完成联调验证的具体动作。TaoToken 在这里的角色不是监听本身而是当你的监听回调触发后需要调用大模型做内容理解、事件分类或上报摘要时用一套统一 Key 打通多家模型省掉每个模型单独申请和切换的麻烦。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 通道是 https://taotoken.net/api 后面配置验证会用到。2. 前置准备权限、清单与 TaoToken 统一 Key2.1 监听录像行为需要哪些权限录像文件落盘后要读取MediaStoreAndroid 10API 29之后引入了分区存储读取其他应用写入的媒体文件需要READ_MEDIA_VIDEOAndroid 13或READ_EXTERNAL_STORAGEAndroid 12 及以下。如果你只是监听自己进程内的变化权限要求会低一些但监听系统相机写入的文件必须拿到媒体读取权限。!-- AndroidManifest.xml -- uses-permission android:nameandroid.permission.READ_MEDIA_VIDEO / uses-permission android:nameandroid.permission.READ_EXTERNAL_STORAGE android:maxSdkVersion32 / uses-permission android:nameandroid.permission.QUERY_ALL_PACKAGES tools:ignoreQueryAllPackagesPermission /QUERY_ALL_PACKAGES是为了检测当前前台应用是不是相机Android 11 之后包可见性收紧不加这个你查不到相机包名。注意这个权限在 Google Play 上架时会被审核做设备管理类应用一般没问题普通消费级应用要谨慎。2.2 注册录像完成广播接收器部分 ROM尤其是早期版本和部分定制系统在录像完成后会发出广播常见 action 是com.android.camera.NEW_VIDEO和android.hardware.action.NEW_VIDEO。这个广播不是 AOSP 标准能不能收到取决于厂商所以它只能作为辅助手段不能作为唯一方案。receiver android:name.receiver.CameraVideoReceiver android:enabledtrue android:exportedtrue intent-filter android:priority2147483647 action android:namecom.android.camera.NEW_VIDEO / action android:nameandroid.hardware.action.NEW_VIDEO / category android:nameandroid.intent.category.DEFAULT / data android:mimeType*/* / /intent-filter /receiverpriority拉到最大是为了尽量先于其他接收器拿到事件但 Android 8.0 之后静态注册的隐式广播大部分被限制这个接收器在部分机型上可能收不到所以下面还要用ContentObserver兜底。2.3 用 TaoToken 统一 Key 打通后续模型调用监听回调触发后你大概率要做两件事把事件上报到服务端或者调用大模型对视频元数据做分类摘要。如果每个模型都单独申请 Key、单独改 base_url维护成本很高。TaoToken 提供统一 Key 和统一 API 通道兼容 OpenAI 风格的接口你只需要在控制台创建一个 Key就能在代码里通过同一个base_url调用不同模型。先去控制台创建 Keyhttps://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 然后在 API Keys 页面复制https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各语言的调用示例。Key 拿到后先别急着写进代码用模型对话页面验证一下通道是否通https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。3. 可复制配置ContentObserver 前台检测 广播三件套3.1 ContentObserver 监听 MediaStore 新增视频这是最可靠的一条路径。系统相机录像完成后会把文件插入MediaStore.Video.Media.EXTERNAL_CONTENT_URI我们注册一个ContentObserver监听这个 Uri 的变化一旦有新增就读取最新一条记录。public class VideoContentObserver extends ContentObserver { private final Context context; private static final String TAG VideoObserver; public VideoContentObserver(Context context, Handler handler) { super(handler); this.context context; } Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); if (uri null) return; Log.d(TAG, MediaStore changed: uri.toString()); queryLatestVideo(); } private void queryLatestVideo() { String[] projection { MediaStore.Video.Media._ID, MediaStore.Video.Media.DISPLAY_NAME, MediaStore.Video.Media.DATA, MediaStore.Video.Media.DURATION, MediaStore.Video.Media.DATE_ADDED, MediaStore.Video.Media.SIZE }; String sortOrder MediaStore.Video.Media.DATE_ADDED DESC LIMIT 1; try (Cursor cursor context.getContentResolver().query( MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, null, null, sortOrder)) { if (cursor ! null cursor.moveToFirst()) { String name cursor.getString(cursor.getColumnIndexOrThrow( MediaStore.Video.Media.DISPLAY_NAME)); long duration cursor.getLong(cursor.getColumnIndexOrThrow( MediaStore.Video.Media.DURATION)); long size cursor.getLong(cursor.getColumnIndexOrThrow( MediaStore.Video.Media.SIZE)); Log.d(TAG, new video: name duration duration size size); onVideoDetected(name, duration, size); } } } private void onVideoDetected(String name, long duration, long size) { // 这里做你的业务上报、分类、调用模型 } }注册和注销要跟生命周期绑定否则会内存泄漏private VideoContentObserver observer; Override protected void onResume() { super.onResume(); observer new VideoContentObserver(this, new Handler(Looper.getMainLooper())); getContentResolver().registerContentObserver( MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true, observer); } Override protected void onPause() { super.onPause(); if (observer ! null) { getContentResolver().unregisterContentObserver(observer); } }registerContentObserver第二个参数传true表示监听子 Uri这样新增、修改、删除都能触发。实测下来录像开始和结束都会触发onChange所以你要用DURATION和SIZE过滤掉时长为 0 的中间态只处理真正落盘完成的视频。3.2 前台应用检测判断相机是否活跃ContentObserver只能告诉你「有视频落盘」不能告诉你「用户此刻在录像」。要判断相机是否在前台用UsageStatsManager查询最近的前台应用包名。public boolean isCameraForeground(Context context) { UsageStatsManager usm (UsageStatsManager) context.getSystemService( Context.USAGE_STATS_SERVICE); long now System.currentTimeMillis(); ListUsageStats stats usm.queryUsageStats( UsageStatsManager.INTERVAL_DAILY, now - 60_000, now); if (stats null) return false; String topPackage null; long topTime 0; for (UsageStats s : stats) { if (s.getLastTimeUsed() topTime) { topTime s.getLastTimeUsed(); topPackage s.getPackageName(); } } if (topPackage null) return false; return topPackage.contains(camera) || topPackage.contains(Camera); }UsageStatsManager需要用户在设置里手动授予「使用情况访问权限」代码里要引导用户跳转Intent intent new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); startActivity(intent);这个权限不是运行时权限没法用requestPermissions申请只能跳设置页让用户手动开。做设备管理类应用时通常由 MDM 统一配置消费级应用要提前跟用户说明用途。3.3 广播接收器兜底把 2.2 里注册的接收器实现补全作为ContentObserver的补充public class CameraVideoReceiver extends BroadcastReceiver { Override public void onReceive(Context context, Intent intent) { if (intent null || intent.getData() null) return; Uri uri intent.getData(); try (Cursor cursor context.getContentResolver().query( uri, null, null, null, null)) { if (cursor ! null cursor.moveToFirst()) { String path cursor.getString(cursor.getColumnIndexOrThrow(_data)); String name cursor.getString(cursor.getColumnIndexOrThrow(_display_name)); Log.d(CameraReceiver, path path name name); } } } }注意_data字段在 Android 10 之后对第三方应用不可见getColumnIndexOrThrow可能抛异常生产环境要用getColumnIndex加判空。4. 验证请求用 TaoToken 通道联调监听结果4.1 监听触发后调用模型做事件分类假设你的业务是检测到新录像后把视频元数据文件名、时长、大小、拍摄时间发给模型让模型判断这是「正常拍摄」还是「可疑行为」然后决定是否上报。用 TaoToken 的统一通道代码里只需要一个base_url和一个 Key。import requests TAOTOKEN_API https://taotoken.net/api API_KEY sk-你的TaoTokenKey def classify_video_event(name, duration, size): prompt ( f视频文件名{name}时长{duration}毫秒 f大小{size}字节。请判断这是正常拍摄还是可疑行为 f只返回 normal 或 suspicious。 ) resp requests.post( f{TAOTOKEN_API}/v1/chat/completions, headers{ Authorization: fBearer {API_KEY}, Content-Type: application/json }, json{ model: gpt-4o-mini, messages: [{role: user, content: prompt}], temperature: 0 }, timeout15 ) resp.raise_for_status() return resp.json()[choices][0][message][content].strip()把classify_video_event挂到 3.1 的onVideoDetected里就完成了「监听 → 分类 → 上报」的闭环。模型名可以按需替换TaoToken 通道兼容多家模型换模型不用改base_url。4.2 真机验证步骤先在模型对话页面确认通道可用https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 发一条测试消息看是否正常返回。然后按下面步骤在真机复现第一步安装 App进入主界面确认ContentObserver已注册Logcat 里能看到registerContentObserver相关日志。第二步打开系统相机切到录像模式录一段 5 秒以上的视频停止录制。第三步观察 Logcat应该先看到MediaStore changed再看到new video: xxx duration5000 sizexxx。第四步如果isCameraForeground返回 true说明前台检测生效。第五步看模型分类结果是否返回normal或suspicious。实测下来ContentObserver在大多数机型上都能稳定触发广播接收器在部分 ROM 上收不到前台检测依赖用户授权。三者组合的覆盖率最高。4.3 用 Coding Plan 做长期联调如果你要长期迭代这套监听逻辑反复改代码、跑真机、调模型建议用 TaoToken 的 Coding Plan把编码和模型调用放在同一个通道里管理省掉频繁切换 Key 的麻烦https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。Claude Code 接入方式在 https://taotoken.net/claude-code?utm_sourcetaotoken_aicg_blog_endutm_contentclaude-codeutm_campaignrewrite Anthropic 兼容通道在 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaude-code-anthropicutm_campaignrewrite 。5. 本篇常见错排查5.1 收不到广播最常见的原因是 Android 8.0 之后静态注册的隐式广播被限制com.android.camera.NEW_VIDEO不在豁免列表里。解决办法是改用ContentObserver作为主路径广播只做辅助。另外部分 ROM 根本不发这个广播不要在这上面死磕。5.2 ContentObserver 触发多次录像开始、暂停、恢复、结束都会触发onChange导致同一个视频被处理多次。解决办法是用DATE_ADDED加SIZE做去重维护一个已处理视频 ID 的集合或者只在DURATION 0且SIZE 阈值时才处理。5.3 读取 MediaStore 返回空Android 13 之后没申请READ_MEDIA_VIDEO会直接返回空 Cursor不报错。检查权限是否在运行时申请了并且用户是否真的授予了。Android 12 及以下用READ_EXTERNAL_STORAGE注意maxSdkVersion要设对。5.4 前台检测一直返回 falseUsageStatsManager需要「使用情况访问权限」没授权时queryUsageStats返回空列表。检查是否跳转设置页让用户开了权限部分 ROM 还需要在电池优化白名单里加你的应用。5.5 TaoToken 调用返回 401Key 没复制完整或者Authorization头格式不对。正确格式是Bearer sk-xxx注意Bearer和 Key 之间有一个空格。如果还是 401去 API Keys 页面重新生成一个https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入细节看文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。5.6 模型返回超时监听回调里做网络请求要放到子线程别在主线程调。另外给requests.post设timeout避免回调阻塞。如果经常超时检查网络环境或者换个响应更快的模型。6. 把监听链路和模型通道接起来整套方案的核心是三条链路并行ContentObserver负责感知视频落盘UsageStatsManager负责判断相机是否在前台广播接收器做兜底。三条链路任意一条触发都可以走 TaoToken 统一通道调用模型做后续处理。Key 在控制台创建通道用https://taotoken.net/api模型对话页面可以快速验证通道是否通。真机验证时重点看 Logcat 里MediaStore changed和new video两条日志是否按顺序出现出现了就说明监听生效剩下的就是业务逻辑的事。

相关推荐

STM32智能电子秤工程实践:从传感器闭环到答辩落地
STM32智能电子秤工程实践:从传感器闭环到答辩落地

1. 这不是普通电子秤,而是一套可落地、可答辩、可扩展的STM32工程闭环“基于STM32的智能计价电子秤”——光看标题,很多人第一反应是“老掉牙的毕设题”,甚至怀疑是不是十年前就做烂了的课设复刻。但如果你真去翻过近三年高校电子类毕设答辩P… · 2026/9/26 9:37:39

光模块TEC温控系统设计:PID算法与热界面工程实战
光模块TEC温控系统设计:PID算法与热界面工程实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 9:37:39

Multisim 14.3安装与汉化实操手册:解决闪退、数据库错误与乱码
Multisim 14.3安装与汉化实操手册:解决闪退、数据库错误与乱码

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 9:37:39

解密《生活英语读写》:阅读题型拆解与写作表达进阶全攻略
解密《生活英语读写》:阅读题型拆解与写作表达进阶全攻略

最近总有人在后台留言问我,《生活英语读写》这门课的作业答案到底怎么找、能不能直接抄。作为把这门课从头到尾跟过一轮、也帮不少学弟学妹理顺过学习节奏的人,我特别理解这种心态:线上课时间紧、任务重,谁不想走个捷径&#xff1… · 2026/9/26 10:17:38

EAP状态持久化策略探索
EAP状态持久化策略探索

EAP状态持久化策略探索 在之前的优化中&#xff0c;我们将EAP启动状态&#xff08;section/zone是否已启动&#xff09;从Dictionary<string, bool>升级为线程安全的EapSectionStateManager&#xff08;基于HashSet<string> lock&#xff09;。当前实现是纯内存&a… · 2026/9/26 10:17:38

优化后的完整代码,重点优化了 `CalculateIntervalAndPoint` 方法,使其能够根据实际“老化时间(秒)”或“老化时间(分:秒)”来精确计算区间均值和点电流差
优化后的完整代码,重点优化了 `CalculateIntervalAndPoint` 方法,使其能够根据实际“老化时间(秒)”或“老化时间(分:秒)”来精确计算区间均值和点电流差

优化后的完整代码,重点优化了 CalculateIntervalAndPoint 方法,使其能够**根据实际“老化时间(秒)”或“老化时间(分:秒)”**来精确计算区间均值和点电流差,而不是简单地把分钟数当作列表索引。 优化要点说明: 不再依赖固定索引:原来直接用 Floor(分钟) 作为索引,非常不… · 2026/9/26 10:17:32

OpCore-Simplify 完整指南:三步把硬件报告变成可启动的 OpenCore EFI
OpCore-Simplify 完整指南:三步把硬件报告变成可启动的 OpenCore EFI

OpCore-Simplify 完整指南&#xff1a;三步把硬件报告变成可启动的 OpenCore EFI 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify OpCore-Simplify 是一… · 2026/9/26 10:17:26

边缘计算控制器:从三笔账看懂工业现场为何需要它
边缘计算控制器:从三笔账看懂工业现场为何需要它

做工业自动化的朋友&#xff0c;这几年应该没少听到“边缘计算”这个词。说实话&#xff0c;前两年我也是带着怀疑在听的&#xff1a;现场好好的PLC加工控机&#xff0c;为什么要换一种新控制器&#xff1f;直到我陪客户把一个高频振动监测项目从头到尾算了一遍账&#xff0c;才… · 2026/9/26 10:17:26

GPU Kernel提交与并行效率优化:从launch-bound到CUDA Graph实战
GPU Kernel提交与并行效率优化:从launch-bound到CUDA Graph实战

GPU Kernel 提交的快慢&#xff0c;往往决定了整个任务的墙钟时间。我在接手这个“优化 GPU Kernel 提交与并行效率”的项目之前&#xff0c;一直把注意力放在 kernel 内部的线程组织和访存上&#xff0c;直到用 Nsight 工具看到完整时间线&#xff0c;才意识到真正的问题往往不… · 2026/9/26 10:17:26

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介&#xff1a;万常选版《数据库原理与设计》课后习题答案资源&#xff0c;覆盖第2至6章及第9章&#xff0c;适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件&#xff0c;含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故&#xff0c;是很多团队绕不过去的坎。线上环境里&#xff0c;服务端明明已经上线了新版接口&#xff0c;老的移动端还在照着旧文档传参数。请求一到网关&#xff0c;校验直接拒绝&#xff0c;用户操作失败&#xff0c;客服群炸了锅&#xff0c;开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码