辅助功能 之 小米手机悬浮窗权限

辅助功能 之 小米手机悬浮窗权限

最近做项目遇到小米手机比较人(zhuang)性(bi)化的悬浮窗权限,当在小米手机上安装完应用后默认是关闭这个权限的,需要用户手动到应用详情页打开该权限。

重(keng)要(die)的是使用这个权限开关系统window后, 小米手机不给任何提示就是不给弹窗。一开始以为是自己代码逻辑写错了,半天才反应过来,小米还有个这个权限,当天6.0以上安卓系统也需要这个权限,但是会有log提示的。

这么麻烦的操作怎么可能让用户自己去找应用详情然后开启操作呢?本文将实现一键开启小米悬浮窗权限!

1分析问题

想要实现自动调整到改应用的详情页的权限管理页面,就要知道权限管理页的类名及包名,我们又没有小米rom的源码,怎么才能知道指定页面的相关信息呢?

查看权限页面类名

这个方法应该有很多中,但是我只验证了一种:想到了 adb shell dumpsys activity

usb链接电脑后,手动打开应用的详情页面里的权限管理页面:

类名信息: com.miui.securitycenter/com.miui.permcenter.permissions.AppPermissionsEditorActivity

构造跳转Intent

知道到了要跳转的activity,我们直接构造Intent 是否可以直接跳过去?

答案肯定是不行的. Intent 需要构造参数,来区分指定app的权限管理页面:

   /**
     * 经测试V5版本是有区别的
     * @param context
     */
    public void openMiuiPermissionActivity(Context context) {
        Intent intent = new Intent("miui.intent.action.APP_PERM_EDITOR");

        if ("V5".equals(getProperty())) {
            PackageInfo pInfo = null;
            try {
                pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            } catch (PackageManager.NameNotFoundException e) {
                Log.e("canking", "error");
            }
            intent.setClassName("com.miui.securitycenter", "com.miui.securitycenter.permission.AppPermissionsEditor");
            intent.putExtra("extra_package_uid", pInfo.applicationInfo.uid);
        } else {
            intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
            intent.putExtra("extra_pkgname", context.getPackageName());
        }

        if (isActivityAvailable(context, intent)) {
            if (context instanceof Activity) {
                Activity a = (Activity) context;
                a.startActivityForResult(intent, 2);
            }
        } else {
            Log.e("canking", "Intent is not available!");
        }
    }

测试适配rom

经测试V5版本和后续版本是后区别的, 分别需要app ID和pkgname. 为了区分V5版本,我们需要得到小米rom的版本名:

    public static String getProperty() {
        String property = "null";
        if (!"Xiaomi".equals(Build.MANUFACTURER)) {
            return property;
        }
        try {
            Class<?> spClazz = Class.forName("android.os.SystemProperties");
            Method method = spClazz.getDeclaredMethod("get", String.class, String.class);
            property = (String) method.invoke(spClazz, "ro.miui.ui.version.name", null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return property;
    }

该反射方法来自网络,经验证是有效的.

这样我们就跳转到了指定应用的权限管理页面.

2.实现一键打开

标题已经写了,我们的目标是用户一键开启,入口做到一键就能开启小米rom悬浮窗权限呢? 可以利用安卓辅助功能自动帮用户跳转, 自动点击打开权限,完成操作后返回.

这里写了个BaseAccessibilityService 通用的操作方法封装在这里.

       /**
     * Created by changxing on 16-6-2.
     */
    public class BaseAccessService extends AccessibilityService {

        @Override
        protected void onServiceConnected() {
        super.onServiceConnected();
        }

        @Override
        public void onInterrupt() {

        }

        @Override
        public void onAccessibilityEvent(AccessibilityEvent event) {

        }

        protected boolean clickByText(AccessibilityNodeInfo nodeInfo, String str) {
        if (null != nodeInfo) {
            List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText(str);
            if (null != list && list.size() > 0) {
                AccessibilityNodeInfo node = list.get(list.size() - 1);
                if (node.isClickable()) {
                    return node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                } else {
                    AccessibilityNodeInfo parentNode = node;
                    for (int i = 0; i < 5; i++) {
                        if (null != parentNode) {
                            parentNode = parentNode.getParent();
                            if (null != parentNode && parentNode.isClickable()) {
                                return parentNode.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                            }
                        }
                    }
                }
            }
        }
        return false;
        }

        protected AccessibilityNodeInfo findOpenButton(AccessibilityNodeInfo node) {
        if (node == null)
            return null;

        //非layout元素
        if (node.getChildCount() == 0) {
            if ("android.widget.Button".equals(node.getClassName())) {
                return node;
            } else
                return null;
        }

        //layout元素,遍历找button
        for (int i = 0; i < node.getChildCount(); i++) {
            AccessibilityNodeInfo button = findOpenButton(node.getChild(i));
            if (button != null)
                return button;
        }
        return null;
        }
    }

继承这个class ,重写onAccessibilityEvent ,在该方法内处理具体逻辑:

到这里只监听TYPE_WINDOW_STATE_CHANGED类型就行了.通过控件的TEXT来实现找到需要点击的控件.
这里可以Dump View hierarchy工具来查看我们想要的控件具体信息.

Dump View hierarchy

     @Override
        public void onAccessibilityEvent(AccessibilityEvent event) {
        int eventType = event.getEventType();
        XLogger.v("eventType:" + eventType);

        switch (eventType) {
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                String clazzName = event.getClassName().toString();
                AccessibilityNodeInfo nodeInfo = event.getSource();
                XLogger.i( "悬浮窗:" + clazzName);
                if (clazzName.equals("com.miui.permcenter.permissions.AppPermissionsEditorActivity")) {
                    if (end) {
                        clickByText(nodeInfo, "XiaomiPJ");
                    } else {
                        boolean access = clickByText(nodeInfo, "显示悬浮窗");
                        XLogger.i("access" + access);
                    }
                }
                if (clazzName.equals("miui.app.AlertDialog")) {
                    end = clickByText(nodeInfo, "允许");
                    XLogger.i( "getClick:" + end);
                }
        }
        }

到这里就可以实现一键开启小米rom悬浮窗权限了

但是一键开启前我们需要判断,该权限是否已经开启:

       /**
         * 判断MIUI的悬浮窗权限
         * @param context
         * @return
         */
        @TargetApi(Build.VERSION_CODES.KITKAT)
        public static boolean isMiuiFloatWindowOpAllowed(Context context) {
        final int version = Build.VERSION.SDK_INT;
        if (version >= 19) {
            return checkOp(context, 24);  // AppOpsManager.OP_SYSTEM_ALERT_WINDOW
        } else {
            if ((context.getApplicationInfo().flags & 1 << 27) == 1 << 27) {
                return true;
            } else {
                return false;
            }
        }
        }

        @TargetApi(Build.VERSION_CODES.KITKAT)
        public static boolean checkOp(Context context, int op) {
        final int version = Build.VERSION.SDK_INT;

        if (version >= 19) {
            AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
            try {

                Class<?> spClazz = Class.forName(manager.getClass().getName());
                Method method = manager.getClass().getDeclaredMethod("checkOp", int.class, int.class, String.class);
                int property = (Integer) method.invoke(manager, op,
                        Binder.getCallingUid(), context.getPackageName());
                XLogger.e(AppOpsManager.MODE_ALLOWED + " invoke " + property);

                if (AppOpsManager.MODE_ALLOWED == property) { 
                    return true;
                } else {
                    return false;
                }
            } catch (Exception e) {
                XLogger.e(e.getMessage());
            }
        } else {
            XLogger.e("Below API 19 cannot invoke!");
        }
        return false;
        }

api>=19需要用反射来活取系统相关配置信息,应该也适用于魅族手机,为验证.

这里我们就实现了一键开启小米Rom悬浮窗权限,并且实现了判断是否已经开启了该权限状态.

个人学习博客
本Demo相关源码地址: https://github.com/CankingApp/XiaomiPJ, 欢迎下载交流学习~

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 桌球悬浮窗辅助线是一款为2023年iOS设备开发的桌球辅助工具。虽然没有具体的产品信息,但我们可以假设它是一种通过虚拟现实或增强现实技术来提供实时辅助线的应用程序。 这款桌球悬浮窗辅助线应用程序可能会利用设备的摄像头和计算机视觉算法,实时跟踪桌球运动,根据球的位置和角度生成辅助线。这样,使用此应用的玩家可以更准确地计算击球力度和方向,提高球技水平。 桌球悬浮窗辅助线应用程序可能会具备一些实用的功能,如可根据用户的技术水平设定不同的辅助程度,从完全无辅助辅助线的显示频率和精度不同,以满足不同玩家的需求。 此外,该应用程序可能还提供一些额外的功能,如实时分析和跟踪球技进步情况,记录历史数据以及与其他玩家进行对战或挑战等。 总之,桌球悬浮窗辅助线2023 iOS是一款可能有助于提高玩家桌球水平的应用程序。它利用先进的技术为玩家提供实时的辅助线,提供了一种更精准和准确的击球方式。 ### 回答2: 桌球悬浮窗辅助线是一种在桌球游戏中使用的辅助工具。在2023年的iOS操作系统中,该功能设计得更加智能化和先进。 桌球是一项技巧和策略相结合的运动,需要运动员在有限的时间内将球击进袋中,并在此过程中避开其他球员的干扰。桌球悬浮窗辅助线旨在帮助玩家更好地掌握击球角度和力度,提供更精确的击球指导。 通过2023年iOS系统中的桌球悬浮窗辅助线功能,玩家可以轻松地预测击球后球的运动轨迹。悬浮窗将根据球的位置、玩家调整的击球力度和角度等参数提供实时的辅助线,并显示球经过该线时可能的路径。 桌球悬浮窗辅助线不仅可以帮助新手玩家快速入门,并提供一种学习的机会,还能帮助经验丰富的选手提高自己的技术水平。同时,该功能的智能设计确保了它不会过度干扰游戏过程,而是更像是一个有益的参考工具。 随着技术的进步,游戏辅助工具的功能也在不断优化和升级。桌球悬浮窗辅助线作为一项创新功能,会为桌球爱好者带来更好的游戏体验和更高的挑战。无论是初学者还是专业选手,都可以通过这一功能更好地享受桌球运动的魅力。 ### 回答3: 桌球悬浮窗辅助线是一种辅助桌球游戏的功能,在2023年的iOS操作系统上使用。 桌球游戏是一种需要精准控制力度和角度的运动,以将球击入目标洞口。然而,对于初学者来说,掌握正确的击球力度和角度往往是一项挑战。这就是桌球悬浮窗辅助线的用途。 悬浮窗辅助线是在游戏画面上显示的一条虚拟直线,根据玩家的球杆位置和目标洞口的位置计算得出。它可以帮助玩家准确判断击球的力度和角度,提供一个参考线来指导击球。 当玩家准备击球时,悬浮窗辅助线会自动显示在游戏画面上,显示从球杆到目标洞口的直线。玩家可以根据这条线调整击球力度和角度,以尽量准确地将球击入目标洞口。同时,悬浮窗辅助线还会根据球杆的移动和角度变化实时更新,帮助玩家更好地掌握击球技巧。 使用桌球悬浮窗辅助线有助于提高初学者的击球准确性和技巧,缩短学习周期。它可以帮助玩家更快地了解和掌握击球的力度和角度,提升游戏体验,并激发更大的游戏兴趣。 总之,桌球悬浮窗辅助线2023ios是一项能在桌球游戏中提供帮助的功能,它可以帮助初学者提高击球准确性和技巧,提升游戏体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值