如何在Android平台使用Kotlin检测用户访问的网站
可行的网站监控替代方案
一、AccessibilityService(辅助功能服务)
- 核心逻辑:通过监听系统中浏览器应用的界面元素变化,提取地址栏中的URL。无需VPN权限,但需要用户手动开启辅助功能。
- 实现要点:
- 创建继承自
AccessibilityService的类,重写onAccessibilityEvent方法处理界面变化事件。 - 在AndroidManifest中声明服务,指定可监听的主流浏览器包名(如Chrome、Edge)。
- 遍历界面节点,识别地址栏控件并提取文本内容。
- 创建继承自
- 代码示例:
class WebMonitorAccessibilityService : AccessibilityService() { override fun onAccessibilityEvent(event: AccessibilityEvent) { if (event.eventType != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) return // 过滤目标浏览器包名 val targetPackages = listOf("com.android.chrome", "com.microsoft.emmx", "org.mozilla.firefox") if (!targetPackages.contains(event.packageName)) return rootInActiveWindow?.let { findUrlInNodes(it) } } private fun findUrlInNodes(node: AccessibilityNodeInfo) { // 匹配地址栏输入框(多数浏览器用EditText承载地址) if (node.className == "android.widget.EditText" && node.text != null) { val url = node.text.toString() if (url.startsWith("http")) { // 此处可将URL存入本地数据库或上传至后端 Log.d("WebMonitor", "当前访问网址: $url") } } // 递归遍历子节点 for (i in 0 until node.childCount) { node.getChild(i)?.let { findUrlInNodes(it) } } } override fun onInterrupt() {} }
- 注意:不同浏览器的地址栏控件结构可能不同,需要针对性适配;无法监控浏览器隐身模式下的访问。
二、监听浏览器历史ContentProvider
- 核心逻辑:多数主流浏览器会将浏览历史存储在公开的ContentProvider中,通过
ContentObserver监听数据变化,读取最新历史记录。 - 实现要点:
- 在AndroidManifest中添加权限:
android.permission.READ_HISTORY_BOOKMARKS(针对系统浏览器);Android 10+访问Chrome历史需额外申请QUERY_ALL_PACKAGES权限或指定Chrome包名的QUERY_PACKAGE_CONTENTS权限。 - 创建
ContentObserver子类,监听对应浏览器的历史URI。 - 历史数据变化时,查询ContentProvider获取最新URL。
- 在AndroidManifest中添加权限:
- 代码示例(以Chrome为例):
class ChromeHistoryObserver(private val context: Context, handler: Handler) : ContentObserver(handler) { private val CHROME_HISTORY_URI = Uri.parse("content://com.android.chrome.browser/bookmarks") fun startObserving() { context.contentResolver.registerContentObserver(CHROME_HISTORY_URI, true, this) } fun stopObserving() { context.contentResolver.unregisterContentObserver(this) } override fun onChange(selfChange: Boolean, uri: Uri?) { super.onChange(selfChange, uri) // 查询最新1条历史记录 val projection = arrayOf("url", "date_added") val sortOrder = "date_added DESC LIMIT 1" context.contentResolver.query(CHROME_HISTORY_URI, projection, null, null, sortOrder)?.use { cursor -> if (cursor.moveToFirst()) { val url = cursor.getString(cursor.getColumnIndexOrThrow("url")) val timestamp = cursor.getLong(cursor.getColumnIndexOrThrow("date_added")) Log.d("WebMonitor", "Chrome历史新增: $url 时间戳: $timestamp") } } } } // 使用方式 val observer = ChromeHistoryObserver(context, Handler(Looper.getMainLooper())) observer.startObserving()
- 注意:不同浏览器的历史URI不同,需自行查阅对应文档;部分小众浏览器可能不开放历史ContentProvider;无法实时监控正在访问的网址,只能获取已记录的历史。
三、UsageStatsManager + 辅助功能组合方案
- 核心逻辑:通过
UsageStatsManager获取当前活跃的应用包名,判断是否为浏览器,再结合辅助功能服务提取当前网址。 - 实现要点:
- 申请
android.permission.PACKAGE_USAGE_STATS权限,需引导用户跳转到系统设置开启。 - 定时查询应用使用统计,识别当前活跃的浏览器。
- 若检测到浏览器活跃,触发辅助功能服务提取地址栏URL。
- 申请
- 代码示例(获取当前活跃浏览器):
fun getCurrentActiveBrowser(context: Context): String? { val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager val endTime = System.currentTimeMillis() val startTime = endTime - 60 * 1000 // 查询最近1分钟的使用记录 val stats = usageStatsManager.queryUsageStats( UsageStatsManager.INTERVAL_BEST, startTime, endTime ) var currentPackage: String? = null var lastActiveTime = 0L stats.forEach { stat -> if (stat.lastTimeUsed > lastActiveTime) { lastActiveTime = stat.lastTimeUsed currentPackage = stat.packageName } } val browserPackages = listOf("com.android.chrome", "com.microsoft.emmx", "org.mozilla.firefox") return if (browserPackages.contains(currentPackage)) currentPackage else null }
- 注意:仅能识别活跃浏览器,需配合辅助功能才能获取具体网址;权限开启流程较繁琐,需做好用户引导。
内容的提问来源于stack exchange,提问作者Powplowdevs
相关产品推荐
相关产品推荐

