Android M 6.0特性及适配

一、前言

Android M(6.0,API 级别 23)提供诸多新特性和功能,并且对系统和 API 行为做出了一些变更。

网上也有很多相关博客,都写得很详细,也有很不错的文章。

这里就不照搬献丑了,仅做一下总结,作为自己学习记录,便于日后查阅。

二、重要特性

相比5.0,Android M 并没有带来Android系统质的飞跃,不过在人性化功能和安全性上做了一些更新。

关于一些体验上的优化和UI对比,请戳 -> 如何评价 Android M

1、动态权限

Android M 最大的特性在于权限管理上的改进。对用户的权限分为了两类:普通权限、危险权限。

1)普通权限

不会直接给用户隐私权带来风险。只需要在AndroidManifest.xml中申请,即可自动获取到对应权限 。

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
  android.permission.ACCESS_NETWORK_STATE
  android.permission.ACCESS_NOTIFICATION_POLICY
  android.permission.ACCESS_WIFI_STATE
  android.permission.ACCESS_WIMAX_STATE
  android.permission.BLUETOOTH
  android.permission.BLUETOOTH_ADMIN
  android.permission.BROADCAST_STICKY
  android.permission.CHANGE_NETWORK_STATE
  android.permission.CHANGE_WIFI_MULTICAST_STATE
  android.permission.CHANGE_WIFI_STATE
  android.permission.CHANGE_WIMAX_STATE
  android.permission.DISABLE_KEYGUARD
  android.permission.EXPAND_STATUS_BAR
  android.permission.FLASHLIGHT
  android.permission.GET_ACCOUNTS
  android.permission.GET_PACKAGE_SIZE
  android.permission.INTERNET
  android.permission.KILL_BACKGROUND_PROCESSES
  android.permission.MODIFY_AUDIO_SETTINGS
  android.permission.NFC
  android.permission.READ_SYNC_SETTINGS
  android.permission.READ_SYNC_STATS
  android.permission.RECEIVE_BOOT_COMPLETED
  android.permission.REORDER_TASKS
  android.permission.REQUEST_INSTALL_PACKAGES
  android.permission.SET_TIME_ZONE
  android.permission.SET_WALLPAPER
  android.permission.SET_WALLPAPER_HINTS
  android.permission.SUBSCRIBED_FEEDS_READ
  android.permission.TRANSMIT_IR
  android.permission.USE_FINGERPRINT
  android.permission.VIBRATE
  android.permission.WAKE_LOCK
  android.permission.WRITE_SYNC_SETTINGS
  com.android.alarm.permission.SET_ALARM
  com.android.launcher.permission.INSTALL_SHORTCUT
  com.android.launcher.permission.UNINSTALL_SHORTCUT

2)危险权限

涉及用户隐私信息的数据或资源。可能对用户存储的数据或其他应用的操作产生影响。例如,读取sd卡,读取通讯录。危险权限需要动态申请,即在使用时需要向用户进行请求权限的弹窗提醒。

group:android.permission-group.CONTACTS
  permission:android.permission.WRITE_CONTACTS
  permission:android.permission.GET_ACCOUNTS
  permission:android.permission.READ_CONTACTS
 
group:android.permission-group.PHONE
  permission:android.permission.READ_CALL_LOG
  permission:android.permission.READ_PHONE_STATE
  permission:android.permission.CALL_PHONE
  permission:android.permission.WRITE_CALL_LOG
  permission:android.permission.USE_SIP
  permission:android.permission.PROCESS_OUTGOING_CALLS
  permission:com.android.voicemail.permission.ADD_VOICEMAIL
 
group:android.permission-group.CALENDAR
  permission:android.permission.READ_CALENDAR
  permission:android.permission.WRITE_CALENDAR
 
group:android.permission-group.CAMERA
  permission:android.permission.CAMERA
 
group:android.permission-group.SENSORS
  permission:android.permission.BODY_SENSORS
 
group:android.permission-group.LOCATION
  permission:android.permission.ACCESS_FINE_LOCATION
  permission:android.permission.ACCESS_COARSE_LOCATION
 
group:android.permission-group.STORAGE
  permission:android.permission.READ_EXTERNAL_STORAGE
  permission:android.permission.WRITE_EXTERNAL_STORAGE
 
group:android.permission-group.MICROPHONE
  permission:android.permission.RECORD_AUDIO
 
group:android.permission-group.SMS
  permission:android.permission.READ_SMS
  permission:android.permission.RECEIVE_WAP_PUSH
  permission:android.permission.RECEIVE_MMS
  permission:android.permission.RECEIVE_SMS
  permission:android.permission.SEND_SMS
  permission:android.permission.READ_CELL_BROADCASTS

在此,有个权限组的概念。任何权限都可属于一个权限组,包括正常权限和应用定义的权限。但权限组仅当权限危险时才影响用户体验。可以忽略正常权限的权限组。

如果应用请求其清单中列出的危险权限,而应用目前在权限组中没有拥有任何权限,则系统会向用户显示一个对话框,描述应用要访问的权限组。对话框不描述该组内的具体权限。 下次其他地方需要同一权限组的权限,系统将自动授予。

那么怎么动态申请呢?

1、targetSdkVersion设置为>=23

2、检查权限是否授予

public static int checkSelfPermission(@NonNull Context context, @NonNull String permission)

3、申请权限

public final void requestPermissions( new String[permission1,permission2,...], requestCode)

这个时候,会弹出系统授权弹窗 (不支持自定义)

4、权限回调

用户在系统弹窗里面选择后,结果会通过Activity的 onRequestPermissionsResult方法回调APP。

public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){
    //继续执行逻辑或者提示权限获取失败
}

5、权限说明

用户如果选择了拒绝,下一次在需要声明该权限的时候,Google建议APP开发者给予用户更多的说明,因此提供了下面这个API。

  • APP没有申请这个权限的话,返回false

  • 用户拒绝时,勾选了不再提示的话,返回false

  • 用户拒绝,但是没有勾选不再提示的话,返回true

因此如果想在第一次就给用户提示,需要记录权限是否申请过,没有申请过的话,强制弹窗提示,而不能根据这个方法的返回值来。

public boolean shouldShowRequestPermissionRationale(permission){   
}

 

注意:除以上普通权限和危险权限外,还有种特殊权限,大多数应用都不应该使用到,比如SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS  。如果某应用需要其中一种权限,必须在清单中声明该权限,并且发送请求用户授权的 intent(注意特殊权限和危险权限请求方式不一样) 。系统将向用户显示详细管理屏幕,以响应该 intent。

1、请求WRITE_SETTINGS 权限

/**
     * 测试请求WRITE_SETTINGS权限
     */
    @OnClick(R.id.request_write_setting)
    @TargetApi(android.os.Build.VERSION_CODES.M)
    public void requestWriteSetting() {
        if (!Settings.System.canWrite(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
                    Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, requestCodeWriteSetting);
        } else {
            Toast.makeText(PermissionTestActivity.this, "WRITE_SETTINGS 已经被授权", Toast.LENGTH_SHORT).show();
        }
    }
​
​
    @TargetApi(Build.VERSION_CODES.M)
    private void showToast() {
        if (Settings.System.canWrite(this)) {
            //检查返回结果
            Toast.makeText(PermissionTestActivity.this, "WRITE_SETTINGS 被授权", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(PermissionTestActivity.this, "WRITE_SETTINGS 没有被授权", Toast.LENGTH_SHORT).show();
        }
    }
​
 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == requestCodeWriteSetting) {
            showToast();
        }else if(requestCode==requestCodeAlertWindow){
            showToastAlerterWindow();
        }
    }

2、请求SYSTEM_ALERT_WINDOW权限

/**
     * 测试请求SYSTEM_ALERT_WINDOW权限
     */
    @OnClick(R.id.request_alert_window)
    @TargetApi(android.os.Build.VERSION_CODES.M)
    public void requestAlertWindow() {
        if (!Settings.canDrawOverlays(this)) {
            Intent intent = new Intent(Settings. ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, requestCodeAlertWindow);
        } else {
            Toast.makeText(PermissionTestActivity.this, "SYSTEM_ALERT_WINDOW 已经被授权", Toast.LENGTH_SHORT).show();
        }
    }
 @TargetApi(Build.VERSION_CODES.M)
    private void showToastAlerterWindow() {
        if (Settings.System.canWrite(this)) {
            //检查返回结果
            Toast.makeText(PermissionTestActivity.this, "SYSTEM_ALERT_WINDOW 被授权", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(PermissionTestActivity.this, "SYSTEM_ALERT_WINDOW 没有被授权", Toast.LENGTH_SHORT).show();
        }
    }

关于特殊权限,可以戳 ->  Android6.0权限适配   查看更多!

 

关于动态权限申请的其他适配建议:

1)不同权限,申请的时机不同。

应用可能用到的权限比较多,有些权限比较重要,影响整体功能和数据,比如读取设备信息,读取sd卡。这时比较可取的做法是:检查此类权限是否获取,防止基本功能或者初始化因为无权限就崩溃了;无此类权限时,友好地引导和向用户解释为何需要此类权限,再申请权限。

2)权限申请的地方可能比较多,最好有统一的管理类或接口。

 

2、休眠和应用待机模式(Doze and App Standby)

新的省电优化方案,在设备和应用空闲时起作用。此特性影响所有的应用 。

休眠模式(Doze) :无外接电源且息屏一段时间,设备将进入休眠模式 。设备周期性的短暂恢复正常操作,以使应用可以同步,系统执行一些必要操作 。

应用待机模式(App Standby) :在用户没有使用某应用的情况下,此模式允许系统判定此应用进入空闲状态。系统的判定依据则是用户在一定的时间内没有再点击此应用(译注:主要还是依据前台进程判定)。如果此时设备也没有连接充电器,系统将禁用该应用的网络连接、同步及任务调度 。

3、移除HTTP client的支持

4、硬件标识符访问权

为给用户提供更严格的数据保护,从此版本开始,对于使用 WLAN API 和 Bluetooth API 的应用,Android 移除了对设备本地硬件标识符的编程访问权。WifiInfo.getMacAddress() 方法和 BluetoothAdapter.getAddress() 方法现在会返回常量值 02:00:00:00:00:00。

现在,要通过蓝牙和 WLAN 扫描访问附近外部设备的硬件标识符,您的应用必须拥有 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 权限。

  • WifiManager.getScanResults()

  • BluetoothDevice.ACTION_FOUND

  • BluetoothLeScanner.startScan()

注:当运行 Android 6.0(API 级别 23)的设备发起后台 WLAN 或蓝牙扫描时,在外部设备看来,该操作的发起来源是一个随机化 MAC 地址。

5、通知

移除了 Notification.setLatestEventInfo() 方法。请改用 Notification.Builder 类来构建通知。

要重复更新通知,请重复使用 Notification.Builder 实例。调用 build() 方法可获取更新后的 Notification 实例。

6、音频管理器变更

不再支持通过 AudioManager 类直接设置音量或将特定音频流静音。setStreamSolo() 方法已弃用,您应该改为调用 requestAudioFocus() 方法。类似地,setStreamMute() 方法也已弃用,请改为调用 adjustStreamVolume() 方法并传入方向值 ADJUST_MUTE 或 ADJUST_UNMUTE。

7、相机服务变更

在此发布版本上,访问相机服务模型将由原来的“先来先服务”方式,改为基于优先级的访问方式。服务行为的变化包括:

(1)客户端应用进程基于优先级的方式访问相机子系统,包括打开和配置设备相机。用户可见的应用进程通常被赋予高优先级,使得相机资源的获取和使用更可靠。

(2)高优先级的应用能够“驱逐”低优先级应用,而使用相机(译注:高优先级应用能以抢占方式使用相机)

(3)在有合适的相机的硬件上,多个应用进程可以同时且独立地使用相机设备。但是,多进程同时访问的情况下,会导致相机设备的性能显著降低,而现在相机服务会检测并不允许此种情况发生。这种变化导致低优先级的应用被“驱逐”,直到没有其它应用直接访问同一个相机设备。

(4)改变当前使用者(译注:多用户情况下的用户切换)后,引起之前使用者所拥有的应用无法再使用相机。访问相机被限制在设备的当前使用者上。实际上,这意味着一个“guest”用户账户在切换到其它用户账户时,不能再保留一个运行的进程访问相机服务。

8、运行时(Runtime)

ART运行时可以恰当的实现newInstance()的访问规则。这一变化修复了之前版本中,Dalvik不正确的检查访问规则的问题。如在你的app使用newInstance()方法,而且你想利用setAccessible()方法,输入参数为true,改变它的访问规则的情况。如果你的app使用 v7 appcompat library或 v7 recyclerview library,你必须使用这些库的最新版本来更新应用。另外,确保在XML中引用的自定义类也被更新,以便其构造函数能够被访问。

此版本更新了动态链接器(dynamic linker)的行为。动态链接器现在能够识别库的soname和它的路径(public bug 6670)的区别,而且实现了通过soname查找。之前错误使用DT_NEEDED entries(通常以绝地路径的形式在编译应用的设备文件系统中)的应用在加载时可能会失败。

dlopen(3) RTLD_LOCAL 标识现在已被正确实现。注意RTLD_LOCAL是默认的,因此如果调用dlopen(3)时,没有明确使用RTLD_LOCAL也受到影响(除非你的应用明确使用RTLD_GLOBAL)。在设置了RTLD_LOCAL,符号对于后来调用dlopen(3)加载的库是不可用的(与DT_NEED entries的引用不同)。

在Android之前的版本,如果你的应用通过text relocation的方式请求系统加载一个共享库,系统显示一个警告,但仍然允许这个库被加载。在此版本中,如果你的应用的目标版本是大于或等于23的话,系统拒绝加载这个库。为了帮助你检测一个库是否加载失败,你的应用应该记录dlopen(3)的失败日至,而且包括调用dlerror(3)返回的问题描述。查看这个指南了解更多关于text relocations。

9、APK 验证

现在执行的 APK 验证更为严格。如果在清单中声明的文件在 APK 中并不存在,该 APK 将被视为已损坏。移除任何内容后必须重新签署 APK。

10、USB 连接

默认情况下,现在通过 USB 端口进行的设备连接设置为仅充电模式。要通过 USB 连接访问设备及其内容,用户必须明确地为此类交互授予权限。如果您的应用支持用户通过 USB 端口与设备进行交互,请将必须显式启用交互考虑在内。

更多详细特性,可戳 -> Android 6.0 新特性详解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KWMax

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值