1、电源管理
App Standby(应用待机)
- 检测:当设备未充电,且在这段时间內用户没有直接或者间接的启动该应用。
- 退出:当应用激活时,或者设备充电时,系统将应用移除此状态。
Doze
- 检测:当设备未充电,且当设备静止或灭屏一段时间
- 周期:平台尝试让系统处于休眠状态,周期性地进入在一个维持窗口恢复正常操作,然后进入更长的休眠状态
(理解:如果用户不操作手机,android先进入一个休眠状态,过段时间再检测还是未操作,就进入下一级休眠状态,以此类推,知道进入最高级别的休眠状态,以达到省电)
2、App Link(非新,加强力度)
- 全称为 应用程序链接
- 技术点: 就是隐式启动Intent
- android更加鼓励应用程序间的关联而不再是单一的应用同浏览器的交互
指纹识别
- 6.0以前一直由各手机制造厂商去研发,导致指纹识别不同的手机差异巨大
- 6.0以后将由android系统提供api,硬件厂商只需提供相应的硬件支持即可
3、应用程序权限管理
权限机制
- 5.0以前,只需要manifest.xml中注册声明即可
- 5.0以后,用户可以在安装的时候关闭某些权限
- 6.0及以后,对于一些用户隐私权限总是会在第一次提示用户是否授予权限(类似iPhone)
运行时权限的优势
- 新的权限机制更好的保护了用户的隐私
- 给了程序向用户说明权限的作用
- 可以防止一些恶意程序盗取用户或者手机信息,增强了android系统的安全性
运行时权限的分类
- Normal Premission
一些不涉及隐私的权限,不需要单独去申请,只需要在manifest申请就可以
- Dangerous Permission & Dangerous Premission Group
涉及隐私的权限,会在运行时向用户申请。并且会分单独的权限和权限组的形式。例如:读sd卡和写sd卡可以合并成操作sd卡的组形式的权限组
权限组的概念
- 如果你申请某个危险的权限,假设你的app早已被用户授权了同一个组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权
新权限使用实例
新增API
- ContextCompact.checkSelfPermission()
检测app是否拥有此权限
- ActivityCompat.requestPermissions()
申请某个权限
- onRequestPermissionsResult()
申请权限的回调,处理申请权限成功失败
- ActivityCompat.shouldShowRequestPermissionRationale
用于给用户解释申请改权限是用于做什么的。用户拒绝我们的申请之后才会出现
使用流程
在AndroidManifest中添加需要的权限(不可省)
-
检查权限
shell命令: adb shell pm list permissions -d -g
申请授权
处理申请回调
代码实战
-
运用上述流程实现一个拨打电话的权限请求过程
1、先在AndroidManifest.xml中注册权限
<uses-permission android:name="android.permission.CALL_PHONE"/>
2、在MainActivity中检查权限,如果有直接执行拨打电话。如果没有权限,请求权限
if(ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){ // 做权限申请处理 ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, Constants.CALL_PHONE); }else{ // 已经有改权限 doCallPhone();// 拨打电话的具体实现 }
3、处理onRequestPermissionsResult回调
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case Constants.CALL_PHONE: if(grantResults[0] == PackageManager.PERMISSION_GRANTED){ doCallPhone(); }else{ // 请求被拒绝,提示用户 Snackbar.make(fabCall, "拨打电话权限被拒绝", Snackbar.LENGTH_SHORT).show(); } break; } }
-
当前我们只添加了一个权限,代码就很臃肿了,所以可以考虑封装我们请求权限的代码到BaseActivity中。
BaseActivity.java
public class BaseActivity extends AppCompatActivity { public boolean hasPermission(String... permissions){ for(String per : permissions){ if(ContextCompat.checkSelfPermission(this, per) != PackageManager.PERMISSION_GRANTED){ return false; } } return true; } public void requestPermission(int code, String... permissions){ ActivityCompat.requestPermissions(this, permissions, code); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch(requestCode){ case Constants.WRITE_EXTERNAL_CODE: if(isAllGranted(grantResults)){ onWriteExternalGranted(); }else{ onWriteExternalDenied(); } break; } } private boolean isAllGranted(int[] grantResults) { for(int result : grantResults){ if(result != PackageManager.PERMISSION_GRANTED){ return false; } } return true; } protected void onWriteExternalDenied() {} protected void onWriteExternalGranted(){}; }
-
MainActivity 继承 BaseActivity,实现在download目录下新建一个文件
判断是否有权限。有,直接操作,没有,请求权限。
if(hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)){ doCreateFile(); // 新建文件具体实现 }else{ requestPermission(Constants.WRITE_EXTERNAL_CODE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE); }
复写成功失败方法
@Override protected void onWriteExternalDenied() { Snackbar.make(fabSD, "获取文件权限失败", Snackbar.LENGTH_SHORT).show(); } @Override protected void onWriteExternalGranted() { doCreateFile(); }
这样虽然没有一个权限申请都需要复写一套成功失败的回调,但已经简洁了很多,而且加上注释逻辑也很清晰
-
第三方库实现 录音权限申请
也可以借用第三方的库来实现,这里采用的是一个注解库
-
使用方法
加入引用
compile 'com.lovedise:permissiongen:0.0.6'
请求权限
PermissionGen.needPermission(this, Constants.RECORD_AUDIO, new String[]{ Manifest.permission.RECORD_AUDIO });
在onRequestPermissionsResult注册该库的方法。
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); PermissionGen.onRequestPermissionsResult(this, requestCode, permissions, grantResults); }
成功回调
@PermissionSuccess(requestCode = Constants.RECORD_AUDIO) public void doRecordSounds(){ Snackbar.make(fabMic, "录音中...", Snackbar.LENGTH_SHORT).show(); }
失败回调
@PermissionFail(requestCode = Constants.RECORD_AUDIO) public void onPremissionDenied(){ Snackbar.make(fabMic, "没有录音权限", Snackbar.LENGTH_SHORT).show(); }
最后,第三方库虽然使用方便,但注解时反射会影响运行时的速度。使用时需要考虑。
Constants.java
public class Constants {
public static final int WRITE_EXTERNAL_CODE = 0x000;
public static final int CALL_PHONE = 0x001;
public static final int RECORD_AUDIO = 0x002;
}