Android 6.0动态权限
android 6.0权限需要动态申请,分为两种,普通权限和高危权限,主要目的是保护用户隐私。
新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。
Normal Permissions(普通权限)
ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUTINTERNETKILL_BACKGROUND_PROCESSESMODIFY_AUDIO_SETTINGSNFCREAD_SYNC_SETTINGSREAD_SYNC_STATSRECEIVE_BOOT_COMPLETEDREORDER_TASKSREQUEST_INSTALL_PACKAGESSET_ALARMSET_TIME_ZONESET_WALLPAPERSET_WALLPAPER_HINTSTRANSMIT_IRUNINSTALL_SHORTCUTUSE_FINGERPRINTVIBRATEWAKE_LOCKWRITE_SYNC_SETTINGS
Dangerous Permission(高危权限)
该权限分为一组一组,申请一组里其中一个,相当于拥有了一组里所有权限,但还是建议把需要的权限都申请一下,避免因权限分组的变化,而引起不要的代码修改
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
相应的ApI
1.、在AndroidManifest文件中添加需要的权限。
这个步骤和我们之前的开发并没有什么变化,试图去申请一个没有声明的权限会导致程序崩溃。(动态申请的权限也需要申明)
2.、检查权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) !=
PackageManager.PERMISSION_GRANTED) {
//没有权限
} else {
//有权限
}
这里涉及到一个API,ContextCompat.checkSelfPermission
,主要用于检测某个权限是否已经被授予,方法返回值为PackageManager.PERMISSION_DENIED
或者PackageManager.PERMISSION_GRANTED
。当返回DENIED就需要进行申请授权了。
3、权限申请
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE},
MY_PERMISSIONS_REQUEST_CALL_PHONE);
三个参数,第一个上下文,第二个,需要申请的权限,String数组,可以进行多权限同时申请,第三个参数为requestCode,主要用于回调的时候检测
4.、处理权限申请回调
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
callPhone();
} else {
Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show(); }
return;
}
}
ok,对于权限的申请结果,首先验证requestCode定位到你的申请,然后验证grantResults对应于申请的结果,这里的数组对应于申请时的第二个权限字符串数组。如果你同时申请两个权限,那么grantResults的length就为2,分别记录你两个权限的申请结果。如果申请成功,就可以做你的事情了
5.、再次申请
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS))
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
}
注意事项
- 注意申请结果回调的数组进行非空判断
- 注意动态申请的权限,也要申明,且申明不要使用
uses-permission-sdk-23这种方式申明的在底版本不可用 - 蓝牙权限无需动态,但需要位置权限,且位置权限需要动态
实例一
java代码
public class MainActivity extends AppCompatActivity {
private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testCall();
}
public void testCall() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)!=
PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_PHONE_STATE},
MY_PERMISSIONS_REQUEST_CALL_PHONE);
} else {
callPhone();
}
}
public void callPhone() {
Intent intent = new Intent(Intent.ACTION_CALL);
Uri data = Uri.parse("tel:" + "10086");
intent.setData(data);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) !=
PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return; }
startActivity(intent);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[]
grantResults){super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE){
if (grantResults[0] == PackageManager.PERMISSION_GRANTED){
callPhone();
} else {
Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
}
return;
}
}
}
xml文件
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission-sdk-23 android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission-sdk-23 android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
实例二
Java代码
public void get() {
int phone = ContextCompat.checkSelfPermission(this,
Manifest.permission.READ_PHONE_STATE);
int fineLocation = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
int coarseLocation = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION); int readStorage = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE); int writeStorage = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if ((phone != PackageManager.PERMISSION_GRANTED) ||(fineLocation !=
PackageManager.PERMISSION_GRANTED) ||(coarseLocation !=
PackageManager.PERMISSION_GRANTED) ||(readStorage !=
PackageManager.PERMISSION_GRANTED) ||(writeStorage !=
PackageManager.PERMISSION_GRANTED)){
Log.i("testCall", "testCall: into");
ActivityCompat.requestPermissions(this, new String[
{Manifest.permission.READ_PHONE_STATE,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
MY_PERMISSIONS_REQUEST_LOCATION);
} else {
init();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) {case MY_PERMISSIONS_REQUEST_LOCATION:Log.i("TAG-->", "onRequestPermissionsResult: " + grantResults.length); if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {init(); } else {// Permission Denied Toast.makeText(SplashActivity.this, "没有权限,本应用无法使用", Toast.LENGTH_SHORT).show();
finishAll();
}
break;
}
}
xml文件
<!--Normal Permission-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.INTERNET" />
<!--Dengon Permission-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>