MIUI以上不能使用miui显示悬浮窗窗口了吗

原文出处:&前言最近UC浏览器中文版出了一个快速搜索的功能, 在使用其他app的时候, 如果复制了一些内容, 屏幕顶部会弹一个窗口, 提示一些操作, 点击后跳转到UC, 显示这个悬浮窗不需要申请android.permission.SYSTEM_ALERT_WINDOW权限.如下图, 截图是在使用Chrome时截的, 但是屏幕顶部却有UC的view浮在屏幕上. 我使用的是小米, 我并没有给UC授悬浮窗权限, 所以我看到这个悬浮窗时是很震惊的.悬浮窗原理做过悬浮窗功能的人都知道, 要想显示悬浮窗, 要有一个服务运行在后台, 通过getSystemService(Context.WINDOW_SERVICE)拿到WindowManager, 然后向其中addView,&addView第二个参数是一个WindowManager.LayoutParams,&WindowManager.LayoutParams中有一个成员type, 有各种值, 一般设置成TYPE_PHONE就可以悬浮在很多view的上方了, 但是调用这个方法需要申请android.permission.SYSTEM_ALERT_WINDOW权限, 在很多机型上, 这个权限的名字叫悬浮窗, 比如小米手机上默认是禁用这个权限的, 有些恶意app会用这个权限弹广告, 而且很难追查是哪个应用弹的. 如果这个权限被禁用, 那么结果就是悬浮窗无法展示, 比如有道词典的复制查词功能, 在小米手机上经常没用, 其实是用户没有授权, 而且应用也没有引导用户给它打开授权.现在UC能突破这个限制, 我很好奇它是怎么做到的.研究实现Android开发有点蛋疼的地方就是太容易被反编译, 但有时这也成为我们研究别人app的一种手段.反编译使用apktool可以很轻松的反编译UC.找代码逆向别人的app, 比较关键的地方是怎么找代码, 因为代码基本上都是混淆的, 直接看肯定是看不懂的, 只能去找, 突破口一般在字符资源上, 比如我们看到上图中的快速搜索是UC的字符, 那么我们到res/values/strings.xml去找快速搜索, 就可以找到下面的内容&string&name=&dark_search_banner_search&&快速搜索&/string&这里我们拿到了快速搜索对应的名字dark_search_banner_search, Android在编译时会给每个资源分配一个id, 我们grep一下这个字符资源的名字就能知道id是多少, 一般在R.java,&res/values/public.xml中有定义, 我直接到public.xml中找到了它的id&public&type=&string&&name=&dark_search_banner_search&&id=&0x7f070049&&/&有了字符资源的id&0x7f070049, 我们再在代码里面grep一下这个id, 就能知道哪几个文件使用了这个字符资源.之所以这么确定是在代码里, 是因为UC在我们复制的内容不同时, 悬浮窗标题会不一样, 一定是在代码里控制的, 结果如下./com/uc/browser/b/f.smali结果可能和大家不一样, 但是一定会找到一个被混淆的smali文件看代码这一部应该是最恶心的. smali代码和java代码的关系, 就像汇编代码和C++代码, 但是smali比汇编代码要容易理解的多, 不然也不会有那么多公司故意将代码写在C++层了.虽然代码都被混淆了, 而且以我们不熟悉的方式出现, 但我们可以根据一些蛛丝马迹来判断代码的执行, 比如Framework的类和API是不能被混淆的, 这也是我们能看懂smali的原因之一, 我们可以结合这些面包屑来还原整个app代码, 当然这需要我们对smali很熟悉, 如果不熟悉smali, 至少要对Android的API熟悉. 因为有时实在看不懂, 我们要靠猜来还原一段代码的逻辑.首先在代码里面找到0x7f070049, 发现了如下代码&&&&(省略)&&&&const&v3,&0x7f070049
&&&&invoke-virtual&{v1,&v3},&Landroid/content/res/R-&getString(I)Ljava/lang/S
&&&&move-result-object&v1
&&&&iput-object&v1,&v0,&Lcom/uc/browser/b/a;-&dpC:Ljava/lang/S
&&&&:cond_9
&&&&(省略)
&&&&invoke-virtual&{v0,&v1},&Lcom/uc/browser/b/a;-&o(Landroid/graphics/drawable/D)V
&&&&:try_end_2
&&&&.catch&Ljava/lang/E&{:try_start_2&..&:try_end_2}&:catch_0&&&&goto/16&:goto_0
&&&&(省略)这是0x7f070049出现之后的一部分代码, 一路看下来, 其实都是在取值赋值, 就拿0x7f070049来说:#使v3寄存器的值为0x7f070049
&&&&const&v3,&0x7f070049
#v1是Resources实例,&调用它的getString方法,&方法的参数是v3中的值
&&&&invoke-virtual&{v1,&v3},&Landroid/content/res/R-&getString(I)Ljava/lang/S
#将结果存入v1寄存器
&&&&move-result-object&v1其实就是我们常用的getResources().getString其实如果一直这么看下去, 会发现毫无头绪, 剩下的代码一直在干差不多的事情, 所以我只截取了这部分, 注意最后一行goto/16&:goto_0也就是说, 有可能代码转到goto_0那儿去了, 那么看看goto_0那里又写了些什么&:goto_0
&&&&(省略)
&&&&const-string&v1,&&window&
&&&&invoke-virtual&{v0,&v1},&Landroid/content/C-&getSystemService(Ljava/lang/S)Ljava/lang/O
&&&&move-result-object&v0
&&&&check-cast&v0,&Landroid/view/WindowM
&&&&invoke-interface&{v0},&Landroid/view/WindowM-&getDefaultDisplay()Landroid/view/D
&&&&move-result-object&v0
&&&&invoke-virtual&{v0},&Landroid/view/D-&getWidth()I
&&&&move-result&v0
&&&&iget-object&v1,&v10,&Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
&&&&iput&v0,&v1,&Landroid/view/WindowManager$LayoutP-&width:I
&&&&iget-object&v0,&v10,&Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
&&&&invoke-virtual&{v10},&Lcom/uc/browser/b/a;-&getContext()Landroid/content/C
&&&&move-result-object&v1
&&&&invoke-virtual&{v1},&Landroid/content/C-&getResources()Landroid/content/res/R
&&&&move-result-object&v1
&&&&const&v2,&0x7f0d0022
&&&&invoke-virtual&{v1,&v2},&Landroid/content/res/R-&getDimension(I)F
&&&&move-result&v1
&&&&float-to-int&v1,&v1
&&&&iput&v1,&v0,&Landroid/view/WindowManager$LayoutP-&height:I
&&&&iget-object&v0,&v10,&Lcom/uc/browser/b/a;-&mWindowManager:Landroid/view/WindowM
&&&&iget-object&v1,&v10,&Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
&&&&invoke-interface&{v0,&v10,&v1},&Landroid/view/WindowM-&addView(Landroid/view/VLandroid/view/ViewGroup$LayoutP)V其实看到const-string v1, &window&, 我们就应该有所警惕了, 这可能是关键代码了. 为什么这么说? 因为悬浮窗的实现里面, 需要获取WindowManager, 从而需要调用Context.getSystemService(Context.WINDOW_SERVICE), 而官方文档写了Context.WINDOW_SERVICE就是常量window. 而后我们看到代码中构造了WindowManager.LayoutParams, 最终在addView时传入.看到这里, 我也觉得很奇怪, 我在悬浮窗原理中写的是我知道的实现悬浮窗的方法, UC的实现好像跟我调用的是相同的API, 也没看到反射之类可能展示奇技淫巧的代码, 为什么UC就可以不需要权限直接显示悬浮窗呢?猜测我认为addView的第二个参数WindowManager.LayoutParams可能是关键, 所以我需要知道UC是如何构造这个WindowManager.LayoutParams的.由于是系统的类, 无法混淆, 直接搜索LayoutParams就找到了下面的代码iget-object&v1,&v10,&Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP这句话就是把v10的值付给v1,&v10是com/uc/browser/b/a的成员dpx, 那么打开com/uc/browser/b/a.smali看看dpx到底是怎么构造的.&&(省略)
.field&dpx:Landroid/view/WindowManager$LayoutP
&&&&(省略)
&&&&.line&68
&&&&new-instance&v0,&Landroid/view/WindowManager$LayoutP
&&&&invoke-direct&{v0},&Landroid/view/WindowManager$LayoutP-&&init&()V
&&&&iput-object&v0,&p0,&Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
&&&&.line&69
&&&&if-eqz&p2,&:cond_0
&&&&.line&70
&&&&iget-object&v0,&p0,&Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
&&&&const/16&v1,&0x7d5
&&&&iput&v1,&v0,&Landroid/view/WindowManager$LayoutP-&type:I
&&&&.line&74
&&&&:goto_0
&&&&iget-object&v0,&p0,&Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
&&&&const/4&v1,&0x1
&&&&iput&v1,&v0,&Landroid/view/WindowManager$LayoutP-&format:I
&&&&(省略)这里的代码就很简单的, 我最先看的是下面这段&&&&const/16&v1,&0x7d5
&&&&iput&v1,&v0,&Landroid/view/WindowManager$LayoutP-&type:I这两句代码就是把WindowManager.LayoutParams.type字段设成0x7d5, 官网上写了0x是WindowManager.LayoutParams.TYPE_TOAST的值.验证实际测试了一下, 将type设置成TYPE_TOAST果然有奇效, 不需要android.permission.SYSTEM_ALERT_WINDOW权限就能显示一个悬浮窗.之前我一直以为调用了系统WindowManager.addView需要android.permission.SYSTEM_ALERT_WINDOW权限, 但实际上调用这个方法是不需要权限的, 在Android源码中有这么一段public&int&checkAddPermission(WindowManager.LayoutParams&attrs)&{
&&&&int&type&=&attrs.
&&&&if&(type&&&WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
&&&&&&&&&&&&||&type&&&WindowManager.LayoutParams.LAST_SYSTEM_WINDOW)&{
&&&&&&&&return&WindowManagerImpl.ADD_OKAY;
&&&&String&permission&=&
&&&&switch&(type)&{
&&&&&&&&case&TYPE_TOAST:
&&&&&&&&&&&&//&XXX&right&now&the&app&process&has&complete&control&over
&&&&&&&&&&&&//&this...&&should&introduce&a&token&to&let&the&system
&&&&&&&&&&&&//&monitor/control&what&they&are&doing.
&&&&&&&&&&&&
&&&&&&&&case&TYPE_INPUT_METHOD:
&&&&&&&&case&TYPE_WALLPAPER:
&&&&&&&&&&&&//&The&window&manager&will&check&these.
&&&&&&&&&&&&
&&&&&&&&case&TYPE_PHONE:
&&&&&&&&case&TYPE_PRIORITY_PHONE:
&&&&&&&&case&TYPE_SYSTEM_ALERT:
&&&&&&&&case&TYPE_SYSTEM_ERROR:
&&&&&&&&case&TYPE_SYSTEM_OVERLAY:
&&&&&&&&&&&&permission&=&android.Manifest.permission.SYSTEM_ALERT_WINDOW;
&&&&&&&&&&&&
&&&&&&&&default:
&&&&&&&&&&&&permission&=&android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
&&&&if&(permission&!=&null)&{
&&&&&&&&if&(mContext.checkCallingOrSelfPermission(permission)
&&&&&&&&&&&&&&&&!=&PackageManager.PERMISSION_GRANTED)&{
&&&&&&&&&&&&return&WindowManagerImpl.ADD_PERMISSION_DENIED;
&&&&return&WindowManagerImpl.ADD_OKAY;
}可以猜到这个方法是往系统的WindowManager里addView的时候做权限检查用的, 那个type就是我们在构造WindowManager.LayoutParams时赋值的type, 可以看到, 除了TYPE_TOAST, 其他都是要权限的, 而且非常喜感的是, 代码中的注释还说他们现在对这种type毫无限制, 应该引入标记来限制开发者.实测效果看到有评论说这样的是不支持点击的. 我之前写的一个app有悬浮窗播放功能, 支持拖动窗口和点击暂停, 关闭窗口等等, 实测功能正常, 今天下班匆匆忙忙写的这篇文章, 没有录制演示视频.但是在2.3上不能接收点击事件.评论区的浮海大虾同学有更多补充如下:TYPE_TOAST一直都可以显示, 但是用TYPE_TOAST显示出来的在2.3上无法接收点击事件, 因此还是无法随意使用.下面是我之前研究后台线程显示对话框的时候记得笔记, 大家可以看看我们项目中有需求需要在后台任务中显示Dialog, 项目最初的做法是用Activity模拟Dialog, 一个Activity已经承载了近20种Dialog, 代码混乱至极. 后来我发现Dialog可以通过改变Window Type实现不依赖Activity显示, 然后就很兴奋的要在使用这种方式来作为新的实现方式.最初WindowType是WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, 可是这是悬浮窗了, MIUI会默认禁止(真他妈操蛋,也没有任何提示)最终放弃. 后来试着换成了WindowManager.LayoutParams.TYPE_TOAST, 起初效果很好,MIUI也不禁止了, 哪里都能显示, 这下开心了. 可是后来又发现在2.3上不能接收点击事件, 也就是说Dialog上的按钮不能点击, 这他妈就很操蛋了, 又放弃了. 又试了试其他的Type都不能满足需求, 结果如下:TYPE_SEARCH_BAR: 未知TYPE_ACCESSIBILITY_OVERLAY: 拒绝使用TYPE_APPLICATION: 只能配合Activity在当前APP使用TYPE_APPLICATION_ATTACHED_DIALOG: 只能配合Activity在当前APP使用TYPE_APPLICATION_MEDIA: 无法使用(什么也不显示)TYPE_APPLICATION_PANEL: 只能配合Activity在当前APP使用(PopupWindow默认就是这个Type)TYPE_APPLICATION_STARTING: 无法使用(什么也不显示)TYPE_APPLICATION_SUB_PANEL: 只能配合Activity在当前APP使用TYPE_BASE_APPLICATION: 无法使用(什么也不显示)TYPE_CHANGED: 只能配合Activity在当前APP使用TYPE_INPUT_METHOD: 无法使用(直接崩溃)TYPE_INPUT_METHOD_DIALOG: 无法使用(直接崩溃)TYPE_KEYGUARD_DIALOG: 拒绝使用TYPE_PHONE: 属于悬浮窗(并且给一个Activity的话按下HOME键会出现看不到桌面上的图标异常情况)TYPE_TOAST: 不属于悬浮窗, 但有悬浮窗的功能, 缺点是在Android2.3上无法接收点击事件TYPE_SYSTEM_ALERT: 属于悬浮窗, 但是会被禁止(TODO: 补充演示GIF)尾声现在我们都知道了如何在不申请权限的情况下显示悬浮窗, 我相信以中国Android开发者的脑洞, 一定会有很多有趣或恶心的功能被开发出来, 一方面我自己觉得这个东西很有用, 可以实现一些很神奇的功能, 另一方面又担心这个API被滥用, 最终不得不限制权限.还有就是, 逆向分析仅用于学习, 不要干违法的事情.本人技术有限, 如果文中有错误的欢迎指正, 以免误导他人利益声明: 虽然我目前在UC实习, 但我并没有UC浏览器中文版的代码权限, 也不会将公司的代码分享给外人. 本文完全是靠我自己开发经验+逆向分析经验+Google完成, 在此之前没有看过UC浏览器的任何代码.
上一篇: 概览 Retrofit 是一个Square开发的类型安全的REST安卓客户端。这个库为网络认证、与api交互以及发用 OkHttp 送网络请求提供了强大的框架 。理解OkHttp 的工作流程见 这个指南 。 注意本文是机遇Retrofit2.0讲解的 - 译者注。 这个库让从web api下载JSON 或
下一篇: 看看如下两个EditText。一个是在API 21的设备上,一个是在API 22的设备上。 看到区别了吗?在开启开发者选项的“显示布局界限”的时候更为明显: 两个EditText的高度和垂直对齐都不一样!这是由于EditText在v21 和 v22 之间背景的改变导致的( diff )。 如MIUI以上不能使用悬浮窗口了吗_百度知道
MIUI以上不能使用悬浮窗口了吗
提问者采纳
设置-全部设置-应用-360卫士-显示悬浮窗口选项打OK全米手机默认所软件悬浮窗功能关闭
电脑网络爱好者
其他类似问题
为您推荐:
其他1条回答
进入系统设置-通知状态栏-通知管理-找应应用进行管理
miui的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁}

我要回帖

更多关于 miui 悬浮窗权限 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信