Android
Разрешения времени выполнения в API-23 +
Поиск…
Вступление
Android Marshmallow представила модель разрешения Runtime Permission . Разрешения подразделяются на две категории: нормальные и опасные . где опасные разрешения теперь предоставляются пользователем во время выполнения.
замечания
Из sdk 23 Android требуется разрешение на запуск для разрешений на устройствах под управлением Android 6.0 и выше, в том, что классифицируется как опасные группы разрешений. Опасные группы разрешений - это те, которые, как считается, ставят под угрозу конфиденциальность и / или безопасность пользователя.
Ниже приведен список опасных групп разрешений:
Опасные группы разрешений
Группа разрешений
КАЛЕНДАРЬ
КАМЕРЫ
КОНТАКТЫ
МЕСТО НАХОЖДЕНИЯ
МИКРОФОН
ТЕЛЕФОН
ДАТЧИКИ
смс
МЕСТО ХРАНЕНИЯ
Любые разрешения этих групп требуют управления разрешениями времени выполнения для устройств на Android 6.0 и выше с целевым sdk 23 или выше.
Обычные разрешения
Ниже приведен список обычных разрешений. Они не считаются опасными для конфиденциальности или безопасности пользователя и поэтому не требуют разрешений времени выполнения для sdk 23 и выше.
ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
БЛЮТУЗ
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
ИНТЕРНЕТ
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
REQUEST_INSTALL_PACKAGES
УСТАНОВИТЬ БУДИЛЬНИК
SET_TIME_ZONE
УСТАНОВКА ОБОЕВ
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
Множественные разрешения для Android 6.0
В этом примере показано, как проверять разрешения во время выполнения в Android 6 и более поздних версиях.
public static final int MULTIPLE_PERMISSIONS = 10; // code you want.
String[] permissions = new String[] {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
};
@Override
void onStart() {
if (checkPermissions()){
// permissions granted.
} else {
// show dialog informing them that we lack certain permissions
}
}
private boolean checkPermissions() {
int result;
List<String> listPermissionsNeeded = new ArrayList<>();
for (String p:permissions) {
result = ContextCompat.checkSelfPermission(getActivity(),p);
if (result != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MULTIPLE_PERMISSIONS:{
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
// permissions granted.
} else {
// no permissions granted.
}
return;
}
}
}
Применение разрешений в трансляции, URI
Вы можете выполнить проверку разрешений при отправке намерения зарегистрированному широковещательному приемнику. Отправленные разрешения перекрестно проверены с теми, которые зарегистрированы в теге. Они ограничивают, кто может отправлять трансляции соответствующему получателю.
Чтобы отправить запрос широковещательной передачи с разрешениями, укажите разрешение как строку в Context.sendBroadcast(Intent intent, String permission)
, но имейте в виду, что приложение получателя ДОЛЖНО иметь это разрешение для получения вашей трансляции. Приемник должен быть установлен первым перед отправителем.
Подпись метода:
void sendBroadcast (Intent intent, String receiverPermission)
//for example to send a broadcast to Bcastreceiver receiver
Intent broadcast = new Intent(this, Bcastreceiver.class);
sendBroadcast(broadcast, "org.quadcore.mypermission");
и вы можете указать в своем манифесте, что отправитель вещания должен включать запрашиваемое разрешение, отправленное через sendBroadcast:
<!-- Your special permission -->
<permission android:name="org.quadcore.mypermission"
android:label="my_permission"
android:protectionLevel="dangerous"></permission>
Также объявите разрешение в манифесте приложения, которое должно получить эту трансляцию:
<!-- I use the permission ! -->
<uses-permission android:name="org.quadcore.mypermission"/>
<!-- along with the receiver -->
<receiver android:name="Bcastreceiver" android:exported="true" />
Примечание. Как приемник, так и вещатель могут потребовать разрешения, и когда это произойдет, обе проверки разрешений должны пройти для того, чтобы Intent был доставлен связанному целевому объекту. Сначала необходимо установить приложение, определяющее разрешение.
Найдите полную документацию здесь, в разделе «Разрешения».
Несколько разрешений времени выполнения от одинаковых групп разрешений
В манифесте у нас есть четыре опасных разрешения во время выполнения из двух групп.
<!-- Required to read and write to shredPref file. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- Required to get location of device. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
В том случае, когда требуются разрешения. Обратите внимание, что важно проверить разрешения в любой деятельности, требующей разрешений, поскольку разрешения могут быть отменены, когда приложение находится в фоновом режиме, и приложение затем выйдет из строя.
final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_layout);
// A simple check of whether runtime permissions need to be managed
if (Build.VERSION.SDK_INT >= 23) {
checkMultiplePermissions();
}
Нам нужно только запрашивать разрешение для одного из них из каждой группы, и все другие разрешения из этой группы предоставляются, если пользователь не отменяет разрешение.
private void checkMultiplePermissions() {
if (Build.VERSION.SDK_INT >= 23) {
List<String> permissionsNeeded = new ArrayList<String>();
List<String> permissionsList = new ArrayList<String>();
if (!addPermission(permissionsList, android.Manifest.permission.ACCESS_FINE_LOCATION)) {
permissionsNeeded.add("GPS");
}
if (!addPermission(permissionsList, android.Manifest.permission.READ_EXTERNAL_STORAGE)) {
permissionsNeeded.add("Read Storage");
}
if (permissionsList.size() > 0) {
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
return;
}
}
}
private boolean addPermission(List<String> permissionsList, String permission) {
if (Build.VERSION.SDK_INT >= 23)
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(permission);
// Check for Rationale Option
if (!shouldShowRequestPermissionRationale(permission))
return false;
}
return true;
}
Это связано с тем, что пользователь разрешает или не разрешает разрешения. В этом примере, если разрешения не разрешены, приложение будет убито.
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS: {
Map<String, Integer> perms = new HashMap<String, Integer>();
// Initial
perms.put(android.Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
perms.put(android.Manifest.permission.READ_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
// Fill with results
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
if (perms.get(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
&& perms.get(android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
// All Permissions Granted
return;
} else {
// Permission Denied
if (Build.VERSION.SDK_INT >= 23) {
Toast.makeText(
getApplicationContext(),
"My App cannot run without Location and Storage " +
"Permissions.\nRelaunch My App or allow permissions" +
" in Applications Settings",
Toast.LENGTH_LONG).show();
finish();
}
}
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
Дополнительная информация https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en
Использование PermissionUtil
PermissionUtil - простой и удобный способ запроса разрешений в контексте. Вы можете легко обеспечить, что должно произойти в случае всех разрешенных разрешений ( onAllGranted()
), любой запрос был отклонен ( onAnyDenied()
) или в случае необходимости рационального ( onRational()
).
В любом месте вашего AppCompatActivity или Fragment, который вы хотите запросить для разрешения пользователя
mRequestObject = PermissionUtil.with(this).request(Manifest.permission.WRITE_EXTERNAL_STORAGE).onAllGranted(
new Func() {
@Override protected void call() {
//Happy Path
}
}).onAnyDenied(
new Func() {
@Override protected void call() {
//Sad Path
}
}).ask(REQUEST_CODE_STORAGE);
И добавьте это в onRequestPermissionsResult
if(mRequestObject!=null){
mRequestObject.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
Добавьте запрошенное разрешение на ваш AndroidManifest.xml, а также
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Включите весь код, связанный с правами доступа, в абстрактный базовый класс и расширьте активность этого базового класса, чтобы получить более чистый / многоразовый код
public abstract class BaseActivity extends AppCompatActivity {
private Map<Integer, PermissionCallback> permissionCallbackMap = new HashMap<>();
@Override
protected void onStart() {
super.onStart();
...
}
@Override
public void setContentView(int layoutResId) {
super.setContentView(layoutResId);
bindViews();
}
...
@Override
public void onRequestPermissionsResult(
int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
PermissionCallback callback = permissionCallbackMap.get(requestCode);
if (callback == null) return;
// Check whether the permission request was rejected.
if (grantResults.length < 0 && permissions.length > 0) {
callback.onPermissionDenied(permissions);
return;
}
List<String> grantedPermissions = new ArrayList<>();
List<String> blockedPermissions = new ArrayList<>();
List<String> deniedPermissions = new ArrayList<>();
int index = 0;
for (String permission : permissions) {
List<String> permissionList = grantResults[index] == PackageManager.PERMISSION_GRANTED
? grantedPermissions
: ! ActivityCompat.shouldShowRequestPermissionRationale(this, permission)
? blockedPermissions
: deniedPermissions;
permissionList.add(permission);
index ++;
}
if (grantedPermissions.size() > 0) {
callback.onPermissionGranted(
grantedPermissions.toArray(new String[grantedPermissions.size()]));
}
if (deniedPermissions.size() > 0) {
callback.onPermissionDenied(
deniedPermissions.toArray(new String[deniedPermissions.size()]));
}
if (blockedPermissions.size() > 0) {
callback.onPermissionBlocked(
blockedPermissions.toArray(new String[blockedPermissions.size()]));
}
permissionCallbackMap.remove(requestCode);
}
/**
* Check whether a permission is granted or not.
*
* @param permission
* @return
*/
public boolean hasPermission(String permission) {
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED;
}
/**
* Request permissions and get the result on callback.
*
* @param permissions
* @param callback
*/
public void requestPermission(String [] permissions, @NonNull PermissionCallback callback) {
int requestCode = permissionCallbackMap.size() + 1;
permissionCallbackMap.put(requestCode, callback);
ActivityCompat.requestPermissions(this, permissions, requestCode);
}
/**
* Request permission and get the result on callback.
*
* @param permission
* @param callback
*/
public void requestPermission(String permission, @NonNull PermissionCallback callback) {
int requestCode = permissionCallbackMap.size() + 1;
permissionCallbackMap.put(requestCode, callback);
ActivityCompat.requestPermissions(this, new String[] { permission }, requestCode);
}
}
Пример использования в деятельности
Действие должно расширять абстрактный базовый класс, определенный выше, следующим образом:
private void requestLocationAfterPermissionCheck() {
if (hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
requestLocation();
return;
}
// Call the base class method.
requestPermission(Manifest.permission.ACCESS_FINE_LOCATION, new PermissionCallback() {
@Override
public void onPermissionGranted(String[] grantedPermissions) {
requestLocation();
}
@Override
public void onPermissionDenied(String[] deniedPermissions) {
// Do something.
}
@Override
public void onPermissionBlocked(String[] blockedPermissions) {
// Do something.
}
});
}