【问题标题】:How to detect auto clicker app used by android user?如何检测android用户使用的自动点击器应用程序?
【发布时间】:2020-08-29 12:29:48
【问题描述】:

一些 android 用户使用 Play 商店中提供的自动点击器应用程序来多次点击。

所以我想检测/阻止尝试使用自动点击器的用户。android 中有什么方法可以检测到此类用户?如果是,那么我们如何检测这些用户?

【问题讨论】:

    标签: android android-studio automation detect fraud-prevention


    【解决方案1】:

    没有 API 可以检测自动点击器是否正在运行。所有自动点击器都使用辅助功能服务来模拟点击,并且有一个 API 允许您检测是否有任何辅助功能服务正在运行。问题是,这些服务还包括屏幕阅读器和其他对残疾人有用的工具。您绝对不应该仅仅因为他们使用无障碍服务而阻止您的用户。

    不过,您也可以检测“不自然”的点击和手势。没有人可以执行多个手势,从屏幕上完全相同的点开始,在完全相同的点结束,并在每个手势上花费完全相同的时间。

    当您检测到该用户是
    a) 使用无障碍服务
    b) 执行不自然的点击
    您可以合理地假设他正在使用自动点击器。然后,您可以阻止他的触摸或做任何您想做的事情。

    为了检测不自然的触摸,您必须分析所有传入的触摸事件。获取所有这些内容的最简单方法是覆盖根容器的 onInterceptTouchEvent 方法。

    例如,创建此类并将其用作布局的根:

    class AutoclickerFrameLayout @JvmOverloads constructor(
            context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
    ) : FrameLayout(context, attrs, defStyleAttr) {
    
        override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
            AutoclickerDetector.recordEvent(event)
            // If you return true in this method touches will be blocked
            return false
        }
    
    }
    

    在分析 MotionEvents 时请记住,即使对于自动点击器,报告的坐标和时间也可能会略有不同。例如,您可以使用以下实现:

    object AutoclickerDetector {
    
        fun isAccessibilityServiceEnabled(context: Context): Boolean {
            val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
            val enabledServices = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK)
            return enabledServices.isNotEmpty()
        }
    
        var isDetectingSimilarGestures = false
            private set
    
        private data class Touch(
                val x: Float,
                val y: Float,
                val time: Long
        ) {
    
            fun isSimilar(other: Touch): Boolean {
                return abs(this.x - other.x) < 1.0f
                        && abs(this.y - other.y) < 1.0f
            }
    
        }
    
        private data class Gesture(
                val start: Touch,
                val end: Touch
        ) {
    
            val duration: Long = end.time - start.time
    
            fun isSimilar(other: Gesture): Boolean {
                return this.start.isSimilar(other.start)
                        && this.end.isSimilar(other.end)
                        && abs(this.duration - other.duration) < 50
            }
    
        }
    
        private var gestureStart: Touch? = null
        private val recentGestures = ArrayList<Gesture>()
    
        fun recordEvent(event: MotionEvent) {
            when (event.action) {
                MotionEvent.ACTION_DOWN -> {
                    gestureStart = Touch(event.rawX, event.rawY, System.currentTimeMillis())
                }
                MotionEvent.ACTION_UP -> {
                    gestureStart?.let { gestureStart ->
                        val gestureEnd = Touch(event.rawX, event.rawY, System.currentTimeMillis())
                        recentGestures.add(Gesture(gestureStart, gestureEnd))
                        trimGestureHistory()
                        checkSimilarGestures()
                    }
                    gestureStart = null
                }
            }
        }
    
        private const val HISTORY_SIZE = 20
    
        private fun trimGestureHistory() {
            while (recentGestures.size > HISTORY_SIZE) {
                recentGestures.removeAt(0)
            }
        }
    
        private fun checkSimilarGestures() {
            recentGestures.forEachIndexed { i, searchGesture ->
                var similarCount = 0
                recentGestures.forEachIndexed { j, compareGesture ->
                    if (i != j && searchGesture.isSimilar(compareGesture)) {
                        similarCount++
                    }
                }
                if (similarCount > 2) {
                    // There is no way user can physically perform almost exactly the same gesture
                    // 3 times amongst 20 last gestures
                    isDetectingSimilarGestures = true
                    return
                }
            }
            isDetectingSimilarGestures = false
        }
    
    }
    

    然后在您的主代码中,您可以检查自动点击器当前是否工作:

    AutoclickerDetector.isAccessibilityServiceEnabled(context) 
        && AutoclickerDetector.isDetectingSimilarGestures
    

    【讨论】:

    • 我有一个修改,其中将初始化手势开始移动到 ACTION_UP 并删除 ACTION_DOWN 部分。不知道为什么没有调用 ACTION_DOWN。
    • 这如何在 java 上工作?以及如何设置 AutoclickerFrameLayout?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-06
    • 2020-07-24
    • 1970-01-01
    • 2016-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多