Android
Autorisations d'exécution dans API-23 +
Recherche…
Introduction
Android Marshmallow a introduit le modèle d' autorisation d'exécution . Les autorisations sont classées en deux catégories, à savoir les autorisations normales et dangereuses . où les autorisations dangereuses sont désormais accordées par l'utilisateur au moment de l'exécution.
Remarques
Depuis sdk 23, Android requiert des autorisations d'exécution pour les autorisations sur les appareils fonctionnant sous Android 6.0 et les versions ultérieures, au sein de ce que l'on appelle les groupes d'autorisations dangereuses. Les groupes de permission dangereux sont ceux qui sont considérés comme compromettant la confidentialité et / ou la sécurité de l'utilisateur.
Voici une liste des groupes de permissions dangereux:
Groupes de permissions dangereux
Groupe de permission
CALENDRIER
CAMÉRA
CONTACTS
EMPLACEMENT
MICROPHONE
TÉLÉPHONE
CAPTEURS
SMS
ESPACE DE RANGEMENT
Toutes les autorisations de ces groupes requièrent la gestion des autorisations d'exécution pour les périphériques sous Android 6.0 et les versions ultérieures avec un SDK cible de 23 ou supérieur.
Autorisations normales
Voici une liste des autorisations normales. Ceux-ci ne sont pas considérés comme dangereux pour la confidentialité ou la sécurité de l'utilisateur et ne nécessitent donc pas d'autorisations d'exécution pour sdk 23 et versions ultérieures.
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_SHORTCUT
L'INTERNET
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
RÉGLER L'ALARME
SET_TIME_ZONE
DÉFINIR LE PAPIER PEINT
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRER
VERROUILLAGE DE RÉVEIL
WRITE_SYNC_SETTINGS
Android 6.0 autorisations multiples
Cet exemple montre comment vérifier les autorisations à l'exécution dans Android 6 et versions ultérieures.
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;
}
}
}
Application des autorisations dans les diffusions, URI
Vous pouvez effectuer une vérification des autorisations lors de l'envoi d'une intention à un récepteur de diffusion enregistré. Les autorisations que vous envoyez sont vérifiées avec celles enregistrées sous la balise. Ils restreignent qui peut envoyer des émissions au récepteur associé.
Pour envoyer une demande de diffusion avec des autorisations, spécifiez l'autorisation en tant que chaîne dans l' Context.sendBroadcast(Intent intent, String permission)
, mais gardez à l'esprit que l'application du destinataire DOIT avoir cette autorisation pour recevoir votre diffusion. Le récepteur doit être installé avant l'expéditeur.
La signature de la méthode est la suivante:
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");
et vous pouvez spécifier dans votre manifeste que l'expéditeur de la diffusion doit inclure l'autorisation demandée envoyée via sendBroadcast:
<!-- Your special permission -->
<permission android:name="org.quadcore.mypermission"
android:label="my_permission"
android:protectionLevel="dangerous"></permission>
Déclarez également l'autorisation dans le manifeste de l'application censée recevoir cette diffusion:
<!-- I use the permission ! -->
<uses-permission android:name="org.quadcore.mypermission"/>
<!-- along with the receiver -->
<receiver android:name="Bcastreceiver" android:exported="true" />
Remarque: à la fois un récepteur et un diffuseur peuvent demander une autorisation et, lorsque cela se produit, les deux contrôles d'autorisation doivent être transmis pour que l'intention soit transmise à la cible associée. L'application qui définit l'autorisation doit être installée en premier.
Retrouvez la documentation complète ici sur les autorisations.
Autorisations d'exécution multiples à partir des mêmes groupes d'autorisations
Dans le manifeste, nous avons quatre autorisations d'exécution dangereuses provenant de deux groupes.
<!-- 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"/>
Dans l'activité où les autorisations sont requises. Notez qu'il est important de vérifier les autorisations dans toute activité nécessitant des autorisations, car les autorisations peuvent être révoquées lorsque l'application est en arrière-plan et l'application se bloque ensuite.
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();
}
Il suffit de demander une autorisation pour l'un de ces groupes et toutes les autres autorisations de ce groupe sont accordées, sauf si l'utilisateur les révoque.
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;
}
Cela concerne le résultat de l'utilisateur autorisant ou non les autorisations. Dans cet exemple, si les autorisations ne sont pas autorisées, l'application est supprimée.
@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);
}
}
Plus d'informations https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en
Utiliser PermissionUtil
PermissionUtil est un moyen simple et pratique de demander des autorisations en contexte. Vous pouvez facilement fournir ce qui doit arriver dans le cas de toutes les autorisations demandées ( onAllGranted()
), toute demande a été refusée ( onAnyDenied()
) ou si un rationnel est nécessaire ( onRational()
).
N'importe où dans votre AppCompatActivity ou Fragment que vous souhaitez demander à l'utilisateur
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);
Et ajoutez ceci à onRequestPermissionsResult
if(mRequestObject!=null){
mRequestObject.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
Ajoutez également l'autorisation demandée à votre AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Inclure tout le code lié aux permissions dans une classe de base abstraite et étendre l'activité de cette classe de base pour obtenir un code plus propre / réutilisable
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);
}
}
Exemple d'utilisation dans l'activité
L'activité doit étendre la classe de base abstraite définie ci-dessus comme suit:
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.
}
});
}