我正在开发一个 kotlin Android 应用程序,我需要监视用户在其设备上访问的网站。我尝试过许多不同的代码变体,所有这些变体都以一种或另一种方式尝试通过 VPN 路由流量,但所有这些变体最终都会遇到相同形式的问题,即一旦代码运行,网站将不再加载。不久前,我在这篇文章上用代码问了一个关于这个问题的问题,但我最终放弃了该代码,因为我无法修复我在那篇文章中提到的错误。
我写这篇文章是为了询问是否有人知道一种方法来检测和记录用户在 kotlin Android 应用程序上访问的网站?
任何指导、示例或参考资料将不胜感激。预先感谢!
我最终找到了一个非常晦涩难懂的解决方案来解决这个问题。事实证明,Android 的辅助功能服务可以跟踪网络流量,不是通过数据包嗅探或 VPN,而是利用 AccessibilityNodeInfo 对象。我还不完全理解,但这是我最好的解释。
通过监视浏览器的 UI,特别是 android.widget.EditText 视图,您可以找出用户当前正在访问/加载的网站。至少 Chrome 使用 android.widget.EditText 视图在搜索栏中显示网站的域名。因此,通过检查该节点并获取其值,我们可以找到用户所在的网站。
我认为这段代码确实有缺点,因为它取决于我认为特定于浏览器的代码和 UI,因此更新可能会破坏它。
这是我最终使用的代码,尽管我没有仅过滤此代码中的搜索栏视图,而是扫描整个屏幕。
import android.accessibilityservice.AccessibilityService
import android.accessibilityservice.AccessibilityServiceInfo
import android.util.Log
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
class UrlLoggingService : AccessibilityService() {
private val TAG = "UrlLoggingService"
override fun onServiceConnected() {
val info = AccessibilityServiceInfo().apply {
eventTypes = AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
packageNames = arrayOf("com.android.chrome")
feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC
notificationTimeout = 100
}
serviceInfo = info
Log.d(TAG, "Accessibility Service connected")
}
override fun onAccessibilityEvent(event: AccessibilityEvent?) {
event ?: return
val rootNode = rootInActiveWindow ?: return
Log.d(TAG, "Root node obtained, starting URL extraction")
val url = extractUrl(rootNode)
url?.let {
Log.d(TAG, "Visited URL: $it")
} ?: Log.d(TAG, "No URL found")
}
private fun extractUrl(node: AccessibilityNodeInfo?): String? {
if (node == null) {
Log.d(TAG, "Node is null, returning")
return null
}
Log.d(TAG, "Processing node: ${node.className}, Text: ${node.text}")
if (node.className == "android.widget.EditText" && node.text != null) {
val text = node.text.toString()
Log.d(TAG, "Found URL: $text")
return text
}
for (i in 0 until node.childCount) {
val childNode = node.getChild(i)
val url = extractUrl(childNode)
if (url != null) {
return url
}
}
return null
}
override fun onInterrupt() {
Log.d(TAG, "Accessibility Service interrupted")
}
}
我还应该注意此代码需要可访问权限才能运行,可以使用此代码请求
startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))