我现在真的羡慕iOS开发程序员,他们既不用考虑应用升级,更不用处理机型适配这些令人头疼而无意义的问题。
——题记
本文将从以下几个方面详解Android开发版本更新及自定义通知的那些坑。
- Service下载文件要注意的小细节
- Android高版本通知图标无法显示(出现白框)
- 通知图标只能显示中间的一部分,无法显示完整
- 高版本通知提示无法在状态栏中显示
- 自定义通知文字颜色适配
Service下载文件要注意的小细节
国内Android应用市场繁杂,几乎没人使用Google Play下载和升级软件。所以,应用程序升级变成了每个APP开发者的任务。Android系统下载文件一般有三种方式:Activity中开启一个线程下载、利用系统DownloadManager下载 和 使用Service在后台下载。第一种方式下载时Activity无法关闭,使用起来非常不方便;系统提供的DownloadManager比较好用,开发者几乎不用考虑任何事情只需要提供下载链接就可以,但是DownloadManager的外观及细节实在做的太差。因此,大多数Android产品使用第三种下载方式——Service。
笔者在Service的 onHandleIntent() 方法中接收到MainActivity传入的下载链接,并使用 HttpURLConnection 进行文件下载,业务流程非常简单,此处不再赘述。
一个小细节:在MainActivity中应判断下载文件的Service是否运行,如果已经在下载则提示版本更新弹窗,一方面提高用户体验,另一方面防止Service被多次开启引发程序异常。
1 | public boolean isWorked() { |
自定义Notification
使用了Service下载,为了不影响用户操作就不应该使用Activity或是Dialog等更新下载进度,那么我使用在 Notification 加入 ProgressBar 来更新下载进度并通知用户是否更新。而为了显示更全面的信息,如下载进度、当前下载速度等等,我选择使用自定义Notification来完成。(由于产品设计APP主要以iOS系统为参照,安卓版本更新部分并没有任何涉猎,于是这部分功能全权交给我去设计完成,我便走上了一条自己给自己挖坑的 不归路。)
笔者设计的通知布局如下:左侧显示应用程序的图标;右侧上部显示“xx程序正在下载”,下载结束后显示“下载完成,请点击安装”;后侧中部显示进度条;
右侧下部包含两个文本框,分别显示当前下载速度和当前下载进度百分比。
Android高版本通知图标无法显示(出现白框)
做好这一切后,笔者迫不及待地在测试机跑了一遍程序,遇到了自定义Notification的第一个坑——在Android 5.0版本以前通知可以正常显示,但5.0及以后的版本状态栏中只能显示出一个白色方框,如下图所示:
究其原因,是Android系统开发者为了统一UI样式,限定在Android 5.0版本之后,状态栏显示的图标必须只能是 白色 的。这显然为难不了我,甚至不需要跟产品和美工提需求,自己三下五除二用PS抠好了图。
在构造Notification的时候判断版本,SDK低于21 选用 彩色图标,大于等于21 选用 纯白色图标,最终结果如下:
通知图标只能显示中间的一部分,无法显示完整
如果直接把程序图标(ic_launcher)设置为Notification的SmallIcon,某些机型出现的问题是状态栏只能显示图标的中间一部分,无法显示完整。
原因是原图标(144* 144)过大,将其 重命名 并改为 48* 48 并放在 xhdpi 即可显示正常。这个问题在网上很普遍并且较易解决,在此不予演示。
高版本通知提示无法在状态栏中显示
通知时提示的文字在Android 5.0之后不显示了。跟上述图标白框问题相似,Android系统开发者在5.0之后 禁用状态栏显示文字(setTicker()方法),相仿iOS系统在手机上部出现 通知弹窗 。因此,需要在构造通知时判断版本,SDK低于21 使用 setTicker() 方法,大于等于21 使用 setFullScreenIntent() 方法,最终结果如下:
自定义通知文字颜色适配
最后一个坑也是最让人头疼的坑,则是不同的Android手机的自定义Notification的文字颜色适配。市场上流通的Android手机有无数种样式的通知栏,如果指定了文字颜色会出现与特殊机型的背景颜色相近而影响美观的问题。而这个问题一般有两种解决方式:
- 干脆连同通知背景颜色也指定,保证黑底白字或白底黑字,不考虑通知栏的背景颜色。
- 获取到当前系统通知栏及通知的颜色数据,根据不同版本做适配。
第一种解决方式显然并不完美,很容易在某些机型出现“极其违和”的通知样式,对于一个完美主义者来说这是无法容忍的,于是我义无反顾地选择了第二种解决方式。
为了给用户带来较好的使用感受,将自定义Notification的布局北京设置为 透明,这样无论图片文字还是进度条看起来都是“嵌入到通知栏背景”中。在Android 5.0版本前, 通知栏的背景以黑色(灰色)为主,而在其之后通知栏以白色为主。笔者灵机一动,不指定TextView的文字颜色,是否就是系统默认的颜色呢?经测试此方法在低版本机型成功率较高,高版本普遍出现了问题。因为TextView的背景颜色并不等同于通知栏的背景颜色,所以文字颜色(可以理解为背景颜色的相反颜色,即对比色)也并不一定相近。
第一种方式失败之后,笔者查阅资料,有另外一种解决方式是我们可以先构造一个Notification(并不发出通知)并获取其中title的 颜色,这样我们可以在自定义Notification沿用 该颜色,代码如下:
1 | private int getNotificationColor() { |
但在高版本机型依旧出现 空指针异常 的问题, Notification.contentView 为空,具体原因笔者没有深入研究,大概是低版本系统Notification也像是自定义Notification一样使用了 系统提供 的 RemoteViews,而高版本已经不再使用这种方式构造通知。
最终笔者选择的解决方式是设置TextView中的 textAppearance属性,SDK低于21 使用 android:TextAppearance.StatusBar.EventContent.Title 样式,大于等于21 使用 android:TextAppearance.Material.Notification.Title 样式,几乎能适配大部分系统。但仍有一部分手机开发者改变了原生Notification的背景,比如笔者的一款测试机——三星S5,黑色半透明通知栏+白色通知背景+黑色文字。
这样使用的 文字颜色(黑色)直接放在 通知栏 处(黑色)非常冲突,而这个问题笔者想了好久,尝试获取到通知栏背景色从根本上解决这一问题,但似乎官方并没有给出任何方法。何况很多手机更改了系统状态栏,背景颜色并不是一个值,而是有不同颜色的一幅图片,想去获取颜色恐怕只能用Bitmap去解析几个点的 ARGB 值了。
总结
希望Google官方以及各个手机厂商的开发者们能够在追求UI与众不同的时候,考虑一下其他Android开发者们做适配的难处,能够提供出通知栏的背景颜色(哪怕给出是深色还是浅色)就再好不过了。如果读到这篇文章的你恰巧知道获取通知栏背景颜色的方法,麻烦能分享给我,笔者不胜感激。