Adnroid越过用户授权使用浮窗

GroverHughe 8年前
   <p>上一片篇文章分析了<a href="http://www.open-open.com/lib/view/open1462415483393.html">Android窗口系统层次</a>、Ativity的窗口和系统窗口的区别,这篇文章我来说说使用系统窗口来实现浮窗的一些限制,我们如何越过这些限制。</p>    <h2>简单的浮窗实现</h2>    <pre>  <code class="language-java">final WindowManager windowManager =     getWindowManager(context);  //创建自定义浮窗   FloatView    hideDialog = new FloatView(context);  WindowManager.LayoutParams  params = new     WindowManager.LayoutParams();  //params.type 窗口类型,主要决定了窗口的层次  params.type = WindowManager.LayoutParams.TYPE_PHONE;  params.format = PixelFormat.RGBA_8888;  //params.flags 描述窗体其他属性的标记位,  //LayoutParams.FLAG_NOT_FOCUSABLE表示不能获取输入法焦点  params.flags = LayoutParams.FLAG_NOT_FOCUSABLE;  params.gravity = Gravity.LEFT | Gravity.TOP;  params.width = LayoutParams.MATCH_PARENT;  params.height = LayoutParams.MATCH_PARENT;  //添加  windowManager.addView(hideDialog, dialogParams);</code></pre>    <p>使用WindowManager.LayoutParams.TYPE_PHONE<br> 或WindowManager.LayoutParams.TYPE_SYS_ALERT窗体类型,然后在别忘了AndroidManifest.xml文件中申明权限<uses-permissionandroid:name="android.permission.SYSTEM_ALERT_WINDOW" />,这是网上关于浮窗实现的帖子千篇一律的做法,很多开发团队也是这么做的。然而在Android 4.4( api 19 )以后,手机rom就可以把这个权限动态的交给用户来选择了,例如华为、小米、oppo等一些机型。例如在华为荣耀6上,关掉《九游》App的浮窗权限,九游的浮窗就显示不了了。</p>    <p><img src="https://simg.open-open.com/show/5181e6e77d327643d99efc6dc3afad7a.gif"></p>    <h2>九游App浮窗</h2>    <p><br> 于是很多产品在浮窗功能环节就加入了授权引导(针对不同的机型提示引导用户去授权),本人最讨论这样的引导了,兴致勃勃的要使用某项功能,突然来个提示框,叫我到xxx设置去进行n个步骤操作,对于这样的功能我一般都是直接放弃使用的。好在这些痛点我们是可以技术策略解决的。</p>    <p>窗实现越过权限使用浮窗</p>    <p>《交易猫》App已经越过浮窗授权,正常使用浮窗功能。</p>    <p><img src="https://simg.open-open.com/show/f9fefafd23fcc3fbe2379ca2b482916c.gif" alt="Adnroid越过用户授权使用浮窗" width="357" height="446"></p>    <h2>交易猫App浮窗</h2>    <p><br> 类型为TYPE_PHONE、TYPE_PRIORITY_PHONE、TYPE_SYSTEM_ALERT、TYPE_SYSTEM_ERROR、TYPE_SYSTEM_ERROR这些的窗口都是需要用户授权的,类型为TYPE_TOAST的不需要,然而在Android 4.4 (api 19)以下TYPE_TOAST是无法获取焦点的,具体源码分析过程可以参考文章:<br> <a href="/misc/goto?guid=4959672870912240220">《Android悬浮窗TYPE_TOAST小结源码分析》</a>。于是我们就可以做一个细分流程了:首先获取系统版本如果大于等于19我们使用TYPE_TOAST,小于19我们使用TYPE_PHONE窗口类型。</p>    <p><img src="https://simg.open-open.com/show/24ef1be3e7da02dbbf27b716bdf460c2.png" alt="Adnroid越过用户授权使用浮窗" width="399" height="423"></p>    <p>根据系统版本使用浮窗</p>    <p>输入法的限制</p>    <p>在4.4以上使用TYPE_TOAST还是有些小小的限制,如果浮窗交互中需要输入框,TYPE_TOAST和TYPE_PHONE两种类型窗体对输入法的处理还是有些区别。当我们的浮窗在横屏环境中(浮窗下面的应用是横屏的),输入法默认是全屏的,我们可以通过设置文本属性android:imeOptions=“flagNoExtractUi”来禁止输入法的全屏,同时可以设置窗体属性为adjustResize来适配调整浮窗位置防止输入法盖住输入框。</p>    <p><img src="https://simg.open-open.com/show/27e2f2aee57d29e4750212fcffdfaf9c.png" alt="Adnroid越过用户授权使用浮窗" width="547" height="241"></p>    <p>type_phone输入法.png</p>    <p>然而adjustResize这个属性对TYPE_TOAST类型的窗体是无效的,本人暂时没找到对应的源码佐证,如果你找到了请告诉我一下。所以如果你的浮窗交互中是需要输入文字的,就不能使用半屏幕输入法的体验了。</p>    <p><img src="https://simg.open-open.com/show/b7e229cc61692f898da74f8366a1ef79.png" alt="Adnroid越过用户授权使用浮窗" width="557" height="257"></p>    <p>TYPE_TOAST输入法.png</p>    <p><br> 为了最大程度的优化体验,我们使用浮窗的流程可以细化为:</p>    <p><img src="https://simg.open-open.com/show/0e15a72b23f6f911cf8e994c96bcff8c.png" alt="Adnroid越过用户授权使用浮窗" width="641" height="433"></p>    <p>授权判断.png</p>    <p><br> 关于浮窗授权,我们可以使用一下方法来判断是否授权:</p>    <pre>  <code class="language-java">/**   * 判断是否开启浮窗权限,api未公开,使用反射调用   * @return   */  private static boolean hasAuthorFloatWin(Context context){        if (Device.getSystemVersion() < 19){          return false;      }      try {          AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);          Class c = appOps.getClass();          Class[] cArg = new Class[3];          cArg[0] = int.class;          cArg[1] = int.class;          cArg[2] = String.class;          Method lMethod = c.getDeclaredMethod("checkOp", cArg);          //24是浮窗权限的标记          return (AppOpsManager.MODE_ALLOWED == (Integer) lMethod.invoke(appOps, 24, Binder.getCallingUid(), context.getPackageName())){        } catch(Exception e) {         return false;      }  }</code></pre>    <p>AppOpsManager是api 19以后引入的,第三方rom可以利用它来管理权限,将某些权限交给用户来定夺,例如浮窗。详细参考官方文档:<a href="/misc/goto?guid=4959672871012066877">AppOpsManager</a>。</p>    <p><br>  </p>    <p>来源:http://www.jianshu.com/p/50fbec2baeb4<br>  </p>