Android获取设备隐私 忽略6.0权限管理

一.前言
(1).由于MIUI等部分国产定制系统也有权限管理,没有相关api,故无法判断用户是否允许获取联系人等隐私。在Android 6.0之后,新增权限管理可以通过官方api判断用户的运行状态;
(2).我们指定targetSdkVersion为23或者之后我们还需要在运行时请求这些所需的权限。这很重要,因为已经出现了很多开发者把targetSdkVersion飙到了最新,然后发现自己的app疯狂的崩溃,这是由于他们没有实现执行运行时权限请求的代码。当你已经把一个targeting API 为23或者之后的app发布到了Google Play上,这更是一个问题,你无法立即把那个apk的targeting API替换成更早的版本。

二.权限分析
从Android6.0开始,权限分为普通权限和许可权限。许可权限分类归组,一个权限授权之后,该组下的权限均可使用。
(1)普通权限
只需要在xml申请即可,使用方法和之前6.0以前的一样。在应用安装应用时,会默认获得许可。
(2)许可权限
可执行 $adb shell pm list permissions -d -g

同一组的任何一个权限被授权了,其他权限也自动被授权。例如,一旦WRITE_CONTACTS被授权了,app也有READ_CONTACTS和GET_ACCOUNTS了。
源码中被用来检查和请求权限的方法分别是Activity的checkSelfPermission和requestPermissions,这些方法api23引入。

三.相关方法
(1).ContextCompat.checkSelfPermission()
检查应用是否拥有该权限,被授权返回值为PERMISSION_GRANTED,否则返回PERMISSION_DENIED
(2).ActivityCompat.requestPermissions()
将弹出请求授权对话框,这个方法在M之前版本调用,OnRequestPermissionsResultCallback 直接被调用,带着正确的 PERMISSION_GRANTED或者 PERMISSION_DENIED 。
(3).AppCompatActivity.onRequestPermissionsResult()
该方法类似于Activity的OnActivityResult()的回调方法,主要接收请求授权的返回值

//版本判断 if (Build.VERSION.SDK_INT >= 23) { //减少是否拥有权限 int checkCallPhonePermission = ContextCompat.checkSelfPermission(getApplicationContext(), permission); if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) { //弹出对话框接收权限 ActivityCompat.requestPermissions(BaseActivity.this, new String[]{permission}, id); return; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { //TODO:已授权 } else { //TODO:用户拒绝 } }

(4).封装

public class BaseActivity extends AppCompatActivity { private Map<Integer, Runnable> allowablePermissionRunnables = new HashMap<>(); private Map<Integer, Runnable> disallowablePermissionRunnables = new HashMap<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } /** * 请求权限 * @param id 请求授权的id 唯一标识即可 * @param permission 请求的权限 * @param allowableRunnable 同意授权后的操作 * @param disallowableRunnable 禁止权限后的操作 */ protected void requestPermission(int id, String permission, Runnable allowableRunnable, Runnable disallowableRunnable) { if (allowableRunnable == null) { throw new IllegalArgumentException("allowableRunnable == null"); } allowablePermissionRunnables.put(id, allowableRunnable); if (disallowableRunnable != null) { disallowablePermissionRunnables.put(id, disallowableRunnable); } //版本判断 if (Build.VERSION.SDK_INT >= 23) { //减少是否拥有权限 int checkCallPhonePermission = ContextCompat.checkSelfPermission(getApplicationContext(), permission); if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) { //弹出对话框接收权限 ActivityCompat.requestPermissions(BaseActivity.this, new String[]{permission}, id); return; } else { allowableRunnable.run(); } } else { allowableRunnable.run(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { Runnable allowRun = allowablePermissionRunnables.get(requestCode); allowRun.run(); } else { Runnable disallowRun = disallowablePermissionRunnables.get(requestCode); disallowRun.run(); } } } public class MainActivity extends BaseActivity implements View.OnClickListener{ private Button btCallPhone; private Button btContact; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btCallPhone = (Button) findViewById(R.id.call_phone); btContact = (Button) findViewById(R.id.contact); btCallPhone.setOnClickListener(this); btContact.setOnClickListener(this); } @Override public void onClick(View v) { if(v == btCallPhone){ //拨打电话 requestPermission(1, Manifest.permission.CALL_PHONE, new Runnable() { @Override public void run() { callPhone(); } }, new Runnable() { @Override public void run() { callPhoneDenied(); } }); }else if(v == btContact){ //读取联系人信息 requestPermission(2, Manifest.permission.WRITE_CONTACTS, new Runnable() { @Override public void run() { readContact(); } }, new Runnable() { @Override public void run() { readContactDenied(); } }); } } private void callPhone() { Toast.makeText(MainActivity.this, "CALL_PHONE OK", Toast.LENGTH_SHORT) .show(); } private void callPhoneDenied() { Toast.makeText(MainActivity.this, "CALL_PHONE Denied", Toast.LENGTH_SHORT) .show(); } private void readContact() { ContentResolver cr = getContentResolver(); String str[] = {ContactsContract.CommonDataKinds.Phone.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.PHOTO_ID}; Cursor cur = cr.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, str, null, null, null); int count = cur.getCount(); cur.close(); Toast.makeText(MainActivity.this, String.format("发现%s条", count), Toast.LENGTH_SHORT) .show(); } private void readContactDenied() { Toast.makeText(MainActivity.this, "Contact Denied", Toast.LENGTH_SHORT) .show(); } }

以上就是本文的全部内容,希望对大家的学习有所帮助。

时间: 2024-10-24 12:05:33

Android获取设备隐私 忽略6.0权限管理的相关文章

浅谈android获取设备唯一标识完美解决方案

本文介绍了浅谈android获取设备唯一标识完美解决方案,分享给大家,具体如下: /** * deviceID的组成为:渠道标志+识别符来源标志+hash后的终端识别符 * * 渠道标志为: * 1,andriod(a) * * 识别符来源标志: * 1, wifi mac地址(wifi): * 2, IMEI(imei): * 3, 序列号(sn): * 4, id:随机码.若前面的都取不到时,则随机生成一个随机码,需要缓存. * * @param context * @return */ p

Android获取设备CPU核数、时钟频率以及内存大小的方法_Android

本文实例讲述了Android获取设备CPU核数.时钟频率以及内存大小的方法.分享给大家供大家参考,具体如下: 因项目需要,分析了一下 Facebook 的开源项目 - Device Year Class. Device Year Class 的主要功能是根据 CPU核数.时钟频率 以及 内存大小 对设备进行分级.代码很简单,只包含两个类: DeviceInfo -> 获取设备参数, YearClass -> 根据参数进行分级. 下表是 Facebook 公司提供的分级标准,其中 Year 栏表

android获取设备唯一码的问题

问题描述 android获取设备唯一码的问题 最近看了个项目,发现他验证码注册功能上写了个获取唯一码uuid的功能,我感觉是多余的,所以我想问什么情况下android项目需要获取唯一码? 解决方案 限制软件非法拷贝,跟踪用户信息,手机丢失找回,绑定用户信息和手机,安全支付等等. 解决方案二: 搞活动的时候,限制每部手机只能领一次,防止刷单.获取真实的用户数据信息. 解决方案三: 开发Android应用中,我们常常需要设备的唯一码来确定客户端. Android 中的几中方法,使用中常常不可靠 DE

android获取设备唯一标示

概述 有时需要对用户设备进行标识,所以希望能够得到一个稳定可靠并且唯一的识别码.虽然Android系统中提供了这样设备识别码,但是由于Android系统版本.厂商定制系统中的Bug等限制,稳定性和唯一性并不理想.而通过其他硬件信息标识也因为系统版本.手机硬件等限制存在不同程度的问题. 下面收集了一些"有能力"或"有一定能力"作为设备标识的串码. DEVICE_ID 这是Android系统为开发者提供的用于标识手机设备的串号,也是各种方法中普适性较高的,可以说几乎所有

Android 6.0 权限管理最佳实践

  博客: Android 6.0 运行时权限管理最佳实践 github: https://github.com/yanzhenjie/AndPermission  

Android获取设备采用的时间制式(12小时制式或24小时制式)

/** * 获取设备采用的时间制式(12小时制式或者24小时制式) * 注意: * 在模拟器上获取的时间制式为空 */ private void getTime_12_24(Context context){ ContentResolver contentResolver = context.getContentResolver(); String time_12_24 = Settings.System.getString(contentResolver,Settings.System.TIM

Shiro系列(0) - 权限管理在J2EE企业级开发中的应用与实战

其实也是应大家要求,讲一下权限管理,之前有讲过,但是没有拿出来细讲,这次索性录了视频从头到尾把shiro讲一遍.后续spring security会另外找个时间也讲一下.   主要内容会包括以下 1.了解基于角色/资源的权限管理方式 2.掌握权限数据模型,数据库表结构 3.了解基于url拦截的权限管理 4.shiro实现用户登录(认证) 5.shiro实现用户权限(授权) 6.J2EE中shiro与web项目的整合,主要是结合spring 7.项目实战:整合到LeeCX开源项目中,实现基于角色以

Android 获取设备屏幕大小的几种方法总结

1.通过WindowManager获取 DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); System.out.println("heigth : " + dm.heightPixels); System.out.println("width : " + dm.widthPixels); 2.通过Resources获取 Di

Android权限管理原理(含6.0)

前言 Android系统在MarshMallow之前,权限都是在安装的时候授予的,虽然在4.3时,Google就试图在源码里面引入AppOpsManager来达到动态控制权限的目的,但由于不太成熟,在Release版本中都是把这个功能给隐藏掉的.在6.0之后,Google为了简化安装流程且方便用户控制权限,正式引入了runtime-permission,允许用户在运行的时候动态控制权限.对于开发而言就是将targetSdkVersion设置为23,并且在相应的时机动态申请权限,在适配了Andro