终端开发

使用Android Studio开发可独立运行(runnable)混淆过的Jar程序 Android安装包精简系列之资源精简 Android安装包精简系列之图片优化 Android安装包精简系列之为什么要优化精简安装包 Android安装包精简系列(总纲) Android安装包精简系列之图标转字体 gradle相关资料汇总 Android编译常见错误解决 Android编译编译速度提升 终端基于gradle的开源项目运行环境配置指引 制作终端产品演示的gif 一个关于APK Signature Scheme v2签名的神奇bug定位经历 如何随apk一起打包并使用SQLite SDK热更之gradle插件(如何在SDK代码中自动插桩及如何生成补丁包) 关于Android的APK Signature Scheme v2签名相关的资料汇总 封装HttpURLConnection实现的简单的网络请求库 一款基于Java环境的读取应用包名、签名、是否V2签名等基本信息的工具 Android的APK Signature Scheme v2签名及一款基于Java环境的校验工具介绍 如何使用Eclipse开发可执行Jar程序,并生成混淆过的jar程序 Android 相关的学习资料整理(持续更新) macOS(Sierra 10.12)上Android源码(AOSP)的下载、编译与导入到Android Studio Google也看不下去被玩坏的悬浮窗了么? Android开发常用工具资源 SDK热更系列之概述(持续整理编辑中~) SDK热更系列之SDKHotfix待优化点 Android 终端开发相关的一些神图(持续更新) SDK热更系列之Demo项目介绍概述 SDK热更系列之Demo体验方法 SDK热更系列之如何获取应用在当前设备上的so对应的指令集 Gradle Android插件使用的中那些特别注意的点 Experimental Plugin User Guide(From Android Tools Project Site) 基于Android Studio使用gradle构建包含jni以及so的构建实例 基于Instrumentation框架的自动化测试 - Android自动化测试系列(四) Instrumentation框架介绍-Android自动化测试系列(三) 关于终端设备的设备唯一性的那些事之MAC地址 关于终端设备的设备唯一性的那些事之IMEI Android 检查应用是否有root权限 ant常见错误解决方案 Gradle介绍 iMac上Android Studio 相关设置及常见问题 再说adb 再看Android官方文档之分享 再看Android官方文档之Fragment&数据保存 再看Android官方文档之Activity&Intent 再看Android官方文档之ActionBar和兼容性 adb shell input(Android模拟输入)简单总结 再看Android官方文档之建立第一个APP Android开发调试常用工具 ANR(网络资料整理) Java参数引用传递引发的惨案(又一次Java的String的“非对象”特性的踩坑经历) android.view.WindowManager$BadTokenException,Unable to add window Android签名校验机制(数字证书) Robotium二三事-Android自动化测试系列(二) Robotium介绍-Android自动化测试系列(一) Android开发中遇到的那些坑 Eclipse使用中部分经验总结 Android中关于Nativa编译(NDK、JNI)的一些问题 Android简单实现的多线程下载模块 Android内存耗用之VSS/RSS/PSS/USS adb Advanced Command URL编码中的空格(编码以后变为+) Android MD5后 bye数组转化为Hex字符串的坑(记一次为女神排忧解难的经历) Android学习之路 adb Base Command Android Log的那些坑…………

标签

android 46

Android编译常见错误解决 一个关于APK Signature Scheme v2签名的神奇bug定位经历 关于Android的APK Signature Scheme v2签名相关的资料汇总 封装HttpURLConnection实现的简单的网络请求库 一款基于Java环境的读取应用包名、签名、是否V2签名等基本信息的工具 Android的APK Signature Scheme v2签名及一款基于Java环境的校验工具介绍 如何使用Eclipse开发可执行Jar程序,并生成混淆过的jar程序 Android 相关的学习资料整理(持续更新) macOS(Sierra 10.12)上Android源码(AOSP)的下载、编译与导入到Android Studio Android开发常用命令备忘 Google也看不下去被玩坏的悬浮窗了么? Android开发常用工具资源 Android 终端开发相关的一些神图(持续更新) Gradle Android插件使用的中那些特别注意的点 Experimental Plugin User Guide(From Android Tools Project Site) iMac(OS X)搭建私有maven仓库,提供Nexus Responsitory镜像 基于Android Studio使用gradle构建包含jni以及so的构建实例 基于Instrumentation框架的自动化测试 - Android自动化测试系列(四) Instrumentation框架介绍-Android自动化测试系列(三) 关于终端设备的设备唯一性的那些事之MAC地址 关于终端设备的设备唯一性的那些事之IMEI Android 检查应用是否有root权限 iMac(OS X)El Capitan 更新遇到的那些坑 ant常见错误解决方案 Gradle介绍 iMac上Android Studio 相关设置及常见问题 再说adb 再看Android官方文档之分享 再看Android官方文档之Fragment&数据保存 再看Android官方文档之Activity&Intent 再看Android官方文档之ActionBar和兼容性 adb shell input(Android模拟输入)简单总结 再看Android官方文档之建立第一个APP Android开发调试常用工具 ANR(网络资料整理) Java参数引用传递引发的惨案(又一次Java的String的“非对象”特性的踩坑经历) android.view.WindowManager$BadTokenException,Unable to add window Android签名校验机制(数字证书) Eclipse使用中部分经验总结 Android内存耗用之VSS/RSS/PSS/USS adb Advanced Command URL编码中的空格(编码以后变为+) Android MD5后 bye数组转化为Hex字符串的坑(记一次为女神排忧解难的经历) Android学习之路 adb Base Command Android Log的那些坑…………

Google也看不下去被玩坏的悬浮窗了么?

2016年12月08日

现象

使用全局悬浮窗的应用,在Android 7.1.1 (Android N MR1)上会crash,crash 堆栈类似下面:

E/AndroidRuntime: FATAL EXCEPTION: main
     android.view.WindowManager$BadTokenException: Unable to add window -- window android.view.ViewRootImpl$W@32622a4 has already been added
         at android.view.ViewRootImpl.setView(ViewRootImpl.java:691)
         at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:342)
         at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
         at com.tencent.ysdk.module.icon.impl.a.g(Unknown Source)
         at com.tencent.ysdk.module.icon.impl.floatingviews.q.onAnimationEnd(Unknown Source)
         at android.view.animation.Animation$3.run(Animation.java:381)
         at android.os.Handler.handleCallback(Handler.java:751)
         at android.os.Handler.dispatchMessage(Handler.java:95)
         at android.os.Looper.loop(Looper.java:154)
         at android.app.ActivityThread.main(ActivityThread.java:6119)
         at java.lang.reflect.Method.invoke(Native Method)
         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

同时在堆栈附近有下面这样一句话:

Adding more than one toast window for UID at a time

背景

最近在开发一个悬浮窗功能,为了方便应用开发者的调用,个人采用了使用全局悬浮窗的方案;同时为了突破厂商的限制,同时又使用了将悬浮窗的type设置为Toast类型。下面是事例代码:

WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.format = PixelFormat.RGBA_8888;
params.gravity = Gravity.LEFT | Gravity.TOP;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
	params.type = WindowManager.LayoutParams.TYPE_TOAST;
} else {
	params.type = WindowManager.LayoutParams.TYPE_PHONE;
}

今天上午Google提示Android 7.1.1可以升级更新,然后就愉快的更新了系统,然后悲催的发现开发中的版本忽然crash了,其中上面的现象中已经说了问题现象。

解决思路

确定问题起因

根据crash的现象,感觉确定是在addView的时候出了问题。然后最近有调整的只有两个方面:

  • 最近对模块相关的代码有修改,但是没有修改view添加相关的内容

原则上不是这个问题。为了缩小范围排除问题范围,因此先使用代码调整前的版本验证。结果发现问题依然存在,因此确定不是因为代码引起的。

  • 今天上午升级了Android 7.1.1

使用另外一台同机型的 Android 7.0的设备验证,相同的包也不会出问题,因此基本上确认就是更新系统引起的。但是google应该不会把这么大的bug遗留下来,那就有可能是有一些变化和调整。

进一步分析原因

结合上面的crash堆栈和问题提示,个人感觉更有可能和Adding more than one toast window for UID at a time这句话有关,去google搜索一下,排在第一位的就是关于Android源码的说明:

  • Android源码关于Toast修改的说明:https://android.googlesource.com/platform/frameworks/base/+/dc24f93

  • 核心内容:

      Prevent apps to overlay other apps via toast windows
    	
      It was possible for apps to put toast type windows
      that overlay other apps which toast winodws aren't
      removed after a timeout.
    	
      Now for apps targeting SDK greater than N MR1 to add a
      toast window one needs to have a special token. The token
      is added by the notificatoion manager service only for
      the lifetime of the shown toast and is then removed
      including all windows associated with this token. This
      prevents apps to add arbitrary toast windows.
    	
      Since legacy apps may rely on the ability to directly
      add toasts we mitigate by allowing these apps to still
      add such windows for unlimited duration if this app is
      the currently focused one, i.e. the user interacts with
      it then it can overlay itself, otherwise we make sure
      these toast windows are removed after a timeout like
      a toast would be.
    	
      We don't allow more that one toast window per UID being
      added at a time which prevents 1) legacy apps to put the
      same toast after a timeout to go around our new policy
      of hiding toasts after a while; 2) modern apps to reuse
      the passed token to add more than one window; Note that
      the notification manager shows toasts one at a time.
    	
      bug:30150688
    	
      Change-Id: Icc8f8dbd060762ae1a7b1720e96c5afdb8aff3fd
    

恩,看来滥用悬浮窗的问题已经很严重了,基本确认这次遇到的异常就是这个问题引起的。

解决方案

根据上面官方的说明,这个变更应该只涉及到Toast,因此只需要保证在7.1.1以上不滥用Toast即可。

临时解决方案

在代码中添加对于7.1.1以上版本的判断,7.1.1以上版本用回phone。代码如下:

WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.format = PixelFormat.RGBA_8888;
params.gravity = Gravity.LEFT | Gravity.TOP;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    if(Build.VERSION.SDK_INT > 24){
        params.type = WindowManager.LayoutParams.TYPE_PHONE;
    }else{
        params.type = WindowManager.LayoutParams.TYPE_TOAST;
    }
} else {
    params.type = WindowManager.LayoutParams.TYPE_PHONE;
}

然后测试问题确实已经解决~

对应github地址:https://github.com/bihe0832/android-UCToast

最终解决方案

通过使用phone类型确实解决了crash的问题,但是没有解决厂商的限制,等厂商都升级到7.1.1以后,我们的悬浮窗弹出成功率又会大幅下降。由于我们的实际诉求本来就不是要添加全局的悬浮窗,之所以选择悬浮窗是为了降低第三方的接入成本。在目前这种前提下我们只好添加与第三方的交互,在新的版本调整实现方式,弃用全局悬浮窗,改为在应用内,通过应用添加悬浮窗实现。

题外话

目前对于全局的悬浮窗,不管是厂商还是官方,都已经出手开始限制,可见悬浮窗已经彻底被玩坏了~



PS:我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=10zhijuy24v4f

赞赏

取消
微信扫一扫,赞赏子勰
扫码支持
屌丝程序猿,鸡血攻城狮!努力学技术,潜心做精品!