程序猿如何从产品的角度去提升应用的体验之Android权限优化篇

简介:

前言:大家平时在开发的过程中是否会遇到这种情况:很多产品体验上的细节,特别是涉及到技术相关的细节,产品与设计可能并不会给出详细的解决方案,甚至可能并不太关注这方面的体验细节。例如,应用的缓存清理机制该怎么实现?权限申请的时机应该放在哪?用户没有给予应用必要的权限该怎么处理......这种时候,作为一个开发人员,特别是对自家产品的使用体验有追求的开发人员,其实完全可以充当一回产品,从产品的角度出发去思考,该怎样在技术实现的细节上,让自家的APP体验变得更好。千万不要小瞧这些细节,一个产品的极致体验,就是由无数的细节堆砌而成的。

1. 应用通知权限的优化

众所周知,推送对于一个APP来说是很重要的功能。推送在好的产品设计中可以有效地提高产品活跃度,增加用户的忠诚度以及留存率。但是,用户有可能会在无意中把应用的通知权限给禁止了,导致收不到推送(用户主动禁止应用的通知权限除外)。例如,华为手机会在通知中心直接提示用户是否关掉某个应用的通知权限。如果用户,特别是小白用户一不小心把通知权限给禁止了,导致应用收不到推送,反而可能还会把这种情况当做bug来向客服反馈(任何时候都千万不要高估用户对于智能手机使用的了解,尤其是你的APP的目标用户还包括中老年人的时候)。

华为手机的推送中心

如果大家有细心观察的话会发现,当应用的通知权限被禁止的时候,体验好的应用会在适当的时机以及场景下出现提示,告知用户通知在应用中起到的作用,尝试去消除用户的不信任和谨慎心理,并引导用户去打开通知权限。

那么,我们怎么知道自己的应用程序通知权限被禁止了呢?如果被禁止了又该怎么办呢?下面就来说一下解决方案。

1.1 检测应用的通知权限状态

检测应用的通知权限其实比较简单。通过查询 官方文档 可以发现,在support库的API 24.0.0 版本,已经有现成的方法可以直接查询应用的通知权限状态:

 
 
  1. NotificationManagerCompat.from(this).areNotificationEnable(); 

但是,这就意味着应用的 compileSdkVersion 也需要与support库的版本保持一致。如果应用目前所使用的compileSdkVersion 低于 24.0.0 或者由于某些历史原因而不能将compileSdkVersion 升到 24.0.0以上,那么就没有办法检测到应用的通知权限了吗?

其实,办法还是有的。通过查看系统源码,可以发现,NotificationManagerCompat.from(this).areNotificationEnable() 这个方法在不同版本的SDK上会有不同的实现。

 
 
  1. /** 
  2.  
  3. Returns whether notifications from the calling package are not blocked. 
  4.  
  5. */ 
  6.  
  7. public boolean areNotificationsEnabled() {  
  8.     return IMPL.areNotificationsEnabled(mContext, mNotificationManager); 
  9.  
  10.  

IMPL是一个实现了Impl接口的实现类对象,而且在静态代码块中通过判断手机系统所使用的版本号来初始化不同的实现类:

 
 
  1. static {    if (BuildCompat.isAtLeastN()) { 
  2.         IMPL = new ImplApi24(); 
  3.     } else if (Build.VERSION.SDK_INT >= 19) { 
  4.         IMPL = new ImplKitKat(); 
  5.     }  else if (Build.VERSION.SDK_INT >= 14) { 
  6.         IMPL = new ImplIceCreamSandwich(); 
  7.     } else { 
  8.         IMPL = new ImplBase(); 
  9.     } 
  10.     SIDE_CHANNEL_BIND_FLAGS = IMPL.getSideChannelBindFlags(); 
  11.  

当手机系统Android版本小于4.4.0的时候, areNotificationEnable()方法会默认返回true。所以,此方法只有在4.4.0以上的手机系统上才能返回准确的结果。

 
 
  1. /** 
  2.  * Returns whether notifications from the calling package are blocked. 
  3.  */ 
  4. public boolean areNotificationsEnabled() { 
  5.     INotificationManager service = getService(); 
  6.     try {        return service.areNotificationsEnabled(mContext.getPackageName()); 
  7.     } catch (RemoteException e) { 
  8.         throw e.rethrowFromSystemServer(); 
  9.     } 
  10.  

这种反射的方式实际上就是通过AppOpsManager和AppOpsService去获取位于/data/system/目录下的文件Appops.xml里的数据。所以,这个系统源码里的方法可以单独抽取出来作为一个通用的检测通知权限状态的方法。有关AppOpsManager,这里先不做展开,等下在1.4章节单独说一下。

1.2 引导用户跳转到通知权限设置界面

既然已经能检测到应用的通知权限状态,当应用的通知权限被禁止的时候,应该出现提示告知用户通知在应用中起到的作用,并引导用户去打开通知权限。以下为跳转到通知权限设置的通用方法:

 
 
  1. public void toNotificationSetting() {    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
  2.         Intent intent = new Intent(); 
  3.         intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); 
  4.         intent.putExtra("app_package", this.getPackageName()); 
  5.         intent.putExtra("app_uid", this.getApplicationInfo().uid); 
  6.         startActivity(intent); 
  7.     } else if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { 
  8.         Intent intent = new Intent(); 
  9.         intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 
  10.         intent.addCategory(Intent.CATEGORY_DEFAULT); 
  11.         intent.setData(Uri.parse("package:" + this.getPackageName())); 
  12.         startActivity(intent); 
  13.     } 
  14.  

在5.0以上,可以直接跳转到某个应用的通知权限快捷设置界面。但是在5.0以下,暂时还没有找到可以直接跳转到通知权限设置界面的方法,所以目前的做法是跳转某个应用的设置界面,在设置界面列表中应该会有通知权限管理的入口。如果你有更好的做法,欢迎在评论中指出来。这里再另外抛出一个问题,供大家思考:关于通知权限提示的方案,应该在什么时机或场景下出现好?出现提示的频率为多少好呢?是只提示一次呢,还是只要用户没打开通知权限就一直提示呢?欢迎大家在留言中说出自己的看法。

1.3 当通知权限被关闭后,Toast可能无法正常工作的问题

虽然跟通知权限的优化没什么关系,不过在这里还是要提一下。这个是在调研通知权限优化问题的时候偶然发现的坑:在大部分的机型上,当应用的通知权限被关闭后,系统的 Toast会直接无法正常工作。

以下是我测试过的数据:

可以看出,这个坑影响的机型范围还是挺大的。为什么会这样呢?

查阅源码后可以发现 Toast 里也用到了NotificationManagerService。在Toast执行show()方法后,执行到enqueueToast()的时候如下:

 
 
  1. if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {    if (!isSystemToast) { 
  2.         Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");        return
  3.     } 
  4.  

原来这里也用到了检测通知权限的方法noteNotificationOp()。如果通知权限被禁止了,那么Toast也就无法正常工作。

对于Android手机来说,Toast在应用中随处可见,如果因为通知权限导致Toast不工作那么影响还是挺大的。所以,在这里建议大家寻找一下Toast的替代方案,不要在项目中直接使用系统自带的Toast。同样的,如果大家有什么好的解决方案,也欢迎在留言中指出来。

1.4 AppOpsManager的工作原理

既然上面提到了AppOpsManager,那么这里来简单地介绍一下它的工作原理。AppOpsManager的工作框架图如下:

Setting UI通过AppOpsManager与AppOpsService 交互,给用户提供入口管理各个app的操作。

AppOpsService具体处理用户的各项设置,用户的设置项存储在 /data/system/appops.xml文件中。

AppOpsService也会被注入到各个相关的系统服务中,进行权限操作的检验。

各个权限操作对应的系统服务(比如定位相关的Location Service,Audio相关的Audio Service等)中注入AppOpsService的判断。如果用户做了相应的设置,那么这些系统服务就要做出相应的处理。比如,LocationManagerSerivce的定位相关接口在实现时,会有判断调用该接口的app是否被用户设置成禁止该操作,如果有该设置,就不会继续进行定位。

2. 应用权限的提示优化

由于篇幅的原因,这里就拿相机权限来举例。假设需求如下:

在需要使用相机的场景下,先提前检测相机权限是否打开,如果没有打开,则尝试申请相机权限,如果用户还是拒绝,则出现权限提示,引导用户去开启相机权限。下面是微信的处理方式:

(1)6.0系统以上,先尝试申请相机权限,用户点击禁止后弹出引导界面

(2)6.0系统以下,用户点击保持禁止后弹出引导界面

在6.0以上,我们一般可以通过系统自带的方法来检测某个权限是否被允许:

 
 
  1. ActivityCompat.checkSelfPermission(context, permission) 

但是,在6.0以下,如果想检测相机权限,却没有一个很好的方法。最后,经过查阅各种资料,发现好像只能通过一种简单粗暴的方式去检测相机权限:

 
 
  1. /** 
  2.  * 在6.0系统以下,通过尝试打开相机的方式判断有无拍照权限 
  3.  * 
  4.  * @return 
  5.  */ 
  6. private boolean checkCameraPermissionUnderM() { 
  7.     boolean isCanUse = true
  8.     Camera mCamera = null
  9.     try { 
  10.         mCamera = Camera.open(); 
  11.         Camera.Parameters mParameters = mCamera.getParameters(); 
  12.         mCamera.setParameters(mParameters); 
  13.     } catch (Exception e) { 
  14.         isCanUse = false
  15.     }    if (mCamera != null) { 
  16.         try { 
  17.             mCamera.release(); 
  18.         } catch (Exception e) { 
  19.             e.printStackTrace();            return isCanUse; 
  20.         } 
  21.     }    return isCanUse; 
  22.  

当使用这个方法的时候,在6.0以下的手机,一般调用 Camera.open()方法,如果相机权限没打开,会先弹出相机权限申请弹框。如果点击允许,那么该方法就会返回true,点击禁止则返回false。这里需要指出的是,如果你使用相机的方式是通过Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE)来跳转到系统的相机界面的话,那么即使应用的相机权限被禁止了,也还是可以正常使用相机来拍照的。这种情况下要不要做权限检查,就看个人的看法了。

不知道大家有没注意到,微信在6.0以上和6.0以下弹出的提示对话框有点不同。在6.0以上提供“去设置”的选项,点击会跳转到设置里的应用列表界面,在6.0以下仅仅是提示。这也是一个产品的细节。个人看法,因为在6.0以下,有些国产系统的权限管理根本就不在设置里面,而是需要到官方提供的手机管家类型应用里面才可以进行权限的管理。那么多的国产系统,需要适配有点困难,如果没有很好的解决方案,那么还不如不要擅自帮用户做决定。可以看得出微信在跳转到权限设置界面的适配上也经过了一番考量,最后选择了这种折中的方案。

说到这里,既然权限提示优化的思路已经有了,大家也可以在自己的项目中封装一个权限管理类,“检查权限-被禁止-尝试申请权限-被拒绝-弹出提示框-引导用户去打开权限”通过一个方法一气呵成。

3. 总结

本文涉及到的知识点可能并不深奥,更多的是想向大家展示一下,假如开发人员从产品的角度去提升应用的体验,可以从什么角度去切入。如果能给大家带来一些启发就好了。看完文章后,不凡思考一下,自己的应用在权限提示上的体验是否做到最好了呢?如果还有可以改善的地方,那么赶紧根据自家应用的实际情况,改善一下权限提示的体验吧。相信我,做了这件事,你的用户会感激你的。





本文作者:佚名
来源:51CTO
目录
相关文章
|
16天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
17天前
|
数据库 Android开发 开发者
构建高效Android应用:Kotlin协程的实践指南
【4月更文挑战第2天】随着移动应用开发的不断进步,开发者们寻求更流畅、高效的用户体验。在Android平台上,Kotlin语言凭借其简洁性和功能性赢得了开发社区的广泛支持。特别是Kotlin协程,作为一种轻量级的并发处理方案,使得异步编程变得更加简单和直观。本文将深入探讨Kotlin协程的核心概念、使用场景以及如何将其应用于Android开发中,以提高应用性能和响应能力。通过实际案例分析,我们将展示协程如何简化复杂任务,优化资源管理,并为最终用户提供更加流畅的体验。
|
17天前
|
开发框架 安全 Android开发
探索安卓系统的新趋势:智能家居应用的蓬勃发展
随着智能家居概念的兴起,安卓系统在智能家居应用领域的应用日益广泛。本文将探讨安卓系统在智能家居应用开发方面的最新趋势和创新,以及其对用户生活的影响。
13 2
|
20天前
|
缓存 监控 Java
构建高效Android应用:从优化用户体验到提升性能
在竞争激烈的移动应用市场中,为用户提供流畅和高效的体验是至关重要的。本文深入探讨了如何通过多种技术手段来优化Android应用的性能,包括UI响应性、内存管理和多线程处理。同时,我们还将讨论如何利用最新的Android框架和工具来诊断和解决性能瓶颈。通过实例分析和最佳实践,读者将能够理解并实施必要的优化策略,以确保他们的应用在保持响应迅速的同时,还能够有效地利用系统资源。
|
21天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0
|
18天前
|
Java Android开发 开发者
构建高效Android应用:Kotlin协程的实践与优化
在响应式编程范式日益盛行的今天,Kotlin协程作为一种轻量级的线程管理解决方案,为Android开发带来了性能和效率的双重提升。本文旨在探讨Kotlin协程的核心概念、实践方法及其在Android应用中的优化策略,帮助开发者构建更加流畅和高效的应用程序。通过深入分析协程的原理与应用场景,结合实际案例,本文将指导读者如何优雅地解决异步任务处理,避免阻塞UI线程,从而优化用户体验。
|
1天前
|
缓存 移动开发 Android开发
构建高效Android应用:从优化用户体验到提升性能表现
【4月更文挑战第18天】 在移动开发的世界中,打造一个既快速又流畅的Android应用并非易事。本文深入探讨了如何通过一系列创新的技术策略来提升应用性能和用户体验。我们将从用户界面(UI)设计的简约性原则出发,探索响应式布局和Material Design的实践,再深入剖析后台任务处理、内存管理和电池寿命优化的技巧。此外,文中还将讨论最新的Android Jetpack组件如何帮助开发者更高效地构建高质量的应用。此内容不仅适合经验丰富的开发者深化理解,也适合初学者构建起对Android高效开发的基础认识。
2 0
|
1天前
|
移动开发 Android开发 开发者
构建高效Android应用:采用Kotlin进行内存优化的策略
【4月更文挑战第18天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,由于设备和版本的多样性,确保应用流畅运行且占用资源少是一大挑战。本文将探讨使用Kotlin语言开发Android应用时,如何通过内存优化来提升应用性能。我们将从减少不必要的对象创建、合理使用数据结构、避免内存泄漏等方面入手,提供实用的代码示例和最佳实践,帮助开发者构建更加高效的Android应用。
4 0
|
3天前
|
缓存 移动开发 Java
构建高效的Android应用:内存优化策略
【4月更文挑战第16天】 在移动开发领域,尤其是针对资源有限的Android设备,内存优化是提升应用性能和用户体验的关键因素。本文将深入探讨Android应用的内存管理机制,分析常见的内存泄漏问题,并提出一系列实用的内存优化技巧。通过这些策略的实施,开发者可以显著减少应用的内存占用,避免不必要的后台服务,以及提高垃圾回收效率,从而延长设备的电池寿命并确保应用的流畅运行。
|
5天前
|
搜索推荐 开发工具 Android开发
安卓即时应用(Instant Apps)开发指南
【4月更文挑战第14天】Android Instant Apps让用户体验部分应用功能而无需完整下载。开发者需将应用拆分成模块,基于已上线的基础应用构建。使用Android Studio的Instant Apps Feature Library定义模块特性,优化代码与资源以减小模块大小,同步管理即时应用和基础应用的版本。经过测试,可发布至Google Play Console,提升用户便利性,创造新获客机会。