Android 静默安装二(无障碍服务版)

近期开发上线一个常驻app,项目已上线,今天随笔记录一下静默安装相关内容。我分三篇静默安装(root版)、静默安装(无障碍版)、监听系统更新、卸载、安装。
先说说我的项目需求:要求app一直运行,通过指令进行自动安装并在安装成功后自动开启。行业人事都了解,非root权限不可能无声无息的完成此要求。我分两步完成了此功能开发。今天记录一下无障碍权限下实现自动安装app。
本文使用AccessibilityService执行系统安装程序自动安装指定文件。

一、自定义AccessibilityService并监听系统弹窗节点


/**
 * 自动安装服务
 */
class AutoInstallService : AccessibilityService() {
    // 检查节点
    private fun checkNodes(node: AccessibilityNodeInfo):Boolean{
        if (node==null) {
            return false
        }
        if (node.className.isEmpty()) {
            return false
        }
        try {
            // 检查当前窗体
            if (node.className.equals("android.widget.Button")) {
                if (node.text.toString().isEmpty()) {
                    return false
                }
                // 模拟点击
                if (node.text.equals("安装")||
                    node.text.equals("完成")||
                    node.text.equals("打开")||
                    node.text.equals("确定")
                ) {
                    node.performAction(AccessibilityNodeInfo.ACTION_CLICK)
                    return true
                }
                // 检查滑动节点
            } else if (node.className.equals("android.widget.ScrollView")){
                node.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD)
            }
            // 检查下级窗体
            for (i in 0..node.childCount) {
                var child = node.getChild(i)
                if (checkNodes(child)) {
                    return true
                }
            }
        }catch (e:Exception){
            e.printStackTrace()
        }
        return false
    }
    private var nodes:MutableMap<Int,Boolean> = LinkedHashMap()
    // 分析系统弹窗节点
    override fun onAccessibilityEvent(p0: AccessibilityEvent?) {
        // 监听系统窗体
        p0?.let {
            it.source?.let {
                obj->{
                var eventType = it.eventType
                if (eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED || eventType == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {
                    // 监听窗体节点
                    if (nodes.get(it.windowId) == null) {
                        if (checkNodes(obj))nodes.put(it.windowId,true)
                    }
                   }
                }
            }
        }
    }
    // 销毁
    override fun onDestroy() {
        super.onDestroy()
        jumpToAccessServiceSetUi(this)
    }
   // 连接成功后退出设置页面
    override fun onServiceConnected() {
        super.onServiceConnected()
        // 连接成功,执行返回按钮
        performGlobalAction(GLOBAL_ACTION_BACK)
        Thread.sleep(500L)
        performGlobalAction(GLOBAL_ACTION_BACK)
    }

    override fun onInterrupt() {

    }
    // 跳转辅助服务
     fun jumpToAccessServiceSetUi(context:Context){
        context?.let {
            try {
                it.startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))
            }catch (e:Exception){
                var intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
                intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                it.startActivity(intent)
                e.printStackTrace()
            }
        }
    }

    /**
     * 检查辅助服务是否开启
     * @appcaliionId 应用id
     * @ct     设备id
     */
    fun checkAccessServiceState(appcaliionId:String,ct:Context):Boolean{
        try {
            var state = Settings.Secure.getInt(ct.contentResolver, Settings.Secure.ACCESSIBILITY_ENABLED, 0)
            if (state != 1) {
                return false
            } else{
                var serviceName = Settings.Secure.getString(
                    ct.contentResolver,
                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
                )
                if (serviceName.isEmpty()) {
                    return serviceName.contains(appcaliionId)
                }
                return false
            }
        } catch (e:Exception){
            e.printStackTrace()
        }
        return false
    }



}

这是我自定的AccessibilityService,内部包含了跳转到开启AccessibilityService设置页面,分析系统弹窗节点,添加安装节点,自动执行。开启AccessibilityService服务,销毁后重新开启AccessibilityService。

2、AccessibilityService注册

在清单文件中注册自定义的AutoInstallService

 <service android:name="com.zhujing.nadedemospace.AutoInstallService"
            android:label="自动安装服务"
            android:exported="true"
            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
            <intent-filter>
                <action android:name="android.accessibilityservice.AccessibilityService" />
            </intent-filter>
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/accessibility_config" />
        </service>

accessibility_config自定义配置

<accessibility-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFlags="flagDefault"
    android:accessibilityFeedbackType="feedbackGeneric"
    android:canRetrieveWindowContent="true"/>

三、使用

// 开启无障碍
 findViewById<View>(R.id.open_accessbt).setOnClickListener {
            if (!AutoInstallService().checkAccessServiceState("com.zhujing.nadedemospace",this)) {
                AutoInstallService().jumpToAccessServiceSetUi(this)
            }
        }
 // 安装应用
         findViewById<View>(R.id.install_apk).setOnClickListener {
            //
            var intent = Intent(Intent.ACTION_GET_CONTENT)
            intent.type = "*/*"
            intent.addCategory(Intent.CATEGORY_OPENABLE)
            startActivityForResult(intent,100)
        }
        // 调用系统安装方法
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == 100 && resultCode == RESULT_OK && data?.data != null){
            var uri = data?.data
            var intent = Intent(Intent.ACTION_VIEW)
            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            intent.setDataAndType(uri,"application/vnd.android.package-archive")
            startActivity(intent)
        }
    }
    

四、总结

我使用的是AccessibilityService无障碍服务实现自动安装的,严格意义上这并不算静默安装。andorid系统被限制的角度来说,这也是一种曲线救国的实现方式。能够满足,无需用户手动操作实现应用安装。欢迎各位指导……

相关推荐

  1. Android 静默安装障碍服务

    2024-03-23 13:30:01       21 阅读
  2. Android静默安装一(Root

    2024-03-23 13:30:01       20 阅读
  3. Android 静默安装成功后自启动

    2024-03-23 13:30:01       23 阅读

最近更新

  1. 环境变量Path

    2024-03-23 13:30:01       0 阅读
  2. 数据守卫者:sklearn中的异常点检测技术

    2024-03-23 13:30:01       1 阅读
  3. 概率解码:SKlearn中模型的概率预测指南

    2024-03-23 13:30:01       1 阅读
  4. 遇到的问题汇总

    2024-03-23 13:30:01       1 阅读
  5. Oracle中CREATE FORCE VIEW的说明和例子

    2024-03-23 13:30:01       1 阅读
  6. 探索邻近奥秘:SKlearn中K-近邻(KNN)算法的应用

    2024-03-23 13:30:01       1 阅读
  7. 简谈设计模式之工厂模式

    2024-03-23 13:30:01       1 阅读
  8. tensorflow学习笔记(二)

    2024-03-23 13:30:01       1 阅读
  9. Typescript【网址取ID传入后端API】

    2024-03-23 13:30:01       1 阅读

热门阅读

  1. Windows C++ 监听注册表是否发生变化

    2024-03-23 13:30:01       22 阅读
  2. ChatGPT助力写作:论文写作新利器

    2024-03-23 13:30:01       24 阅读
  3. 001-Windows下PyTorch极简开发环境配置(上)

    2024-03-23 13:30:01       19 阅读
  4. js知识总结

    2024-03-23 13:30:01       20 阅读
  5. 多目标优化算法帕累托前沿的指标

    2024-03-23 13:30:01       21 阅读
  6. 前端需要掌握的 mysql 基础知识

    2024-03-23 13:30:01       23 阅读
  7. 数据结构与算法:选择排序与快速排序

    2024-03-23 13:30:01       20 阅读
  8. Redis中的常用数据结构

    2024-03-23 13:30:01       19 阅读
  9. C# 线程锁使用

    2024-03-23 13:30:01       20 阅读