Android
Autorizzazioni di runtime in API-23 +
Ricerca…
introduzione
Android Marshmallow ha introdotto il modello di autorizzazione di runtime . Le autorizzazioni sono suddivise in due categorie, ovvero Autorizzazioni normali e pericolose . dove le autorizzazioni pericolose sono ora concesse dall'utente in fase di esecuzione.
Osservazioni
Da sdk 23 Android richiede autorizzazioni di runtime per le autorizzazioni sui dispositivi con Android 6.0 e versioni successive, all'interno di quelli classificati come gruppi di permessi pericolosi. I gruppi di permessi pericolosi sono considerati compromessi dalla privacy e / o dalla sicurezza dell'utente.
Di seguito è riportato un elenco di gruppi di autorizzazioni pericolose:
Gruppi di permessi pericolosi
Gruppo di Permessi
CALENDARIO
TELECAMERA
CONTATTI
POSIZIONE
MICROFONO
TELEFONO
SENSORI
sms
CONSERVAZIONE
Qualsiasi autorizzazione da questi gruppi richiede la gestione delle autorizzazioni di runtime per i dispositivi su Android 6.0 e versioni successive con un sdk di destinazione di 23 o versione successiva.
Permessi normali
Di seguito è riportato un elenco di autorizzazioni normali. Questi non sono considerati pericolosi per la privacy o la sicurezza dell'utente e quindi non richiedono permessi di runtime per sdk 23 e successivi.
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
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
IMPOSTA SVEGLIA
SET_TIME_ZONE
IMPOSTA SFONDO
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRARE
WAKE_LOCK
WRITE_SYNC_SETTINGS
Autorizzazioni multiple di Android 6.0
Questo esempio mostra come verificare le autorizzazioni in fase di esecuzione in Android 6 e versioni successive.
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;
}
}
}
Applicazione delle autorizzazioni nelle trasmissioni, URI
È possibile eseguire un controllo delle autorizzazioni quando si invia un'intenzione a un destinatario di una trasmissione registrata. Le autorizzazioni inviate vengono confrontate con quelle registrate sotto il tag. Limitano chi può inviare trasmissioni al ricevitore associato.
Per inviare una richiesta di trasmissione con autorizzazioni, specifica l'autorizzazione come stringa nella chiamata Context.sendBroadcast(Intent intent, String permission)
, ma tieni presente che l'app del ricevente DEVE avere tale autorizzazione per ricevere la tua trasmissione. Il ricevitore dovrebbe essere installato prima del mittente.
La firma del metodo è:
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");
ed è possibile specificare nel manifest che il mittente broadcast è necessario per includere l'autorizzazione richiesta inviata attraverso sendBroadcast:
<!-- Your special permission -->
<permission android:name="org.quadcore.mypermission"
android:label="my_permission"
android:protectionLevel="dangerous"></permission>
Dichiara inoltre il permesso nel manifest dell'applicazione che si suppone di ricevere questa trasmissione:
<!-- I use the permission ! -->
<uses-permission android:name="org.quadcore.mypermission"/>
<!-- along with the receiver -->
<receiver android:name="Bcastreceiver" android:exported="true" />
Nota: sia un ricevitore che un broadcaster possono richiedere un'autorizzazione e, quando ciò accade, entrambi i controlli delle autorizzazioni devono passare affinché l'intent venga consegnato alla destinazione associata. L'app che definisce l'autorizzazione deve essere installata per prima.
Trova la documentazione completa qui su Autorizzazioni.
Più autorizzazioni di runtime dagli stessi gruppi di autorizzazioni
Nel manifest abbiamo quattro pericolose autorizzazioni di runtime da due gruppi.
<!-- 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"/>
Nell'attività in cui sono richieste le autorizzazioni. Nota è importante verificare le autorizzazioni in qualsiasi attività che richiede autorizzazioni, poiché le autorizzazioni possono essere revocate mentre l'app è in background e l'app si arresta in modo anomalo.
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();
}
Abbiamo solo bisogno di chiedere il permesso per uno di questi da ciascun gruppo e tutte le altre autorizzazioni da questo gruppo sono concesse a meno che l'autorizzazione non venga revocata dall'utente.
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;
}
Questo riguarda il risultato dell'utente che consente o non autorizza le autorizzazioni. In questo esempio, se le autorizzazioni non sono consentite, l'app viene uccisa.
@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);
}
}
Ulteriori informazioni https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en
Utilizzando PermissionUtil
PermissionUtil è un modo semplice e conveniente di chiedere permessi nel contesto. È possibile fornire facilmente ciò che dovrebbe accadere in caso di tutte le autorizzazioni richieste concesse ( onAllGranted()
), qualsiasi richiesta è stata negata ( onAnyDenied()
) o nel caso in cui sia necessario un razionale ( onRational()
).
Ovunque nel tuo AppCompatActivity o Framment che vuoi chiedere la permisssion dell'utente
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);
E aggiungilo a onRequestPermissionsResult
if(mRequestObject!=null){
mRequestObject.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
Aggiungi anche l'autorizzazione richiesta al tuo AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Includere tutti i codici relativi alle autorizzazioni a una classe di base astratta ed estendere l'attività di questa classe base per ottenere un codice più pulito / riutilizzabile
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);
}
}
Esempio di utilizzo nell'attività
L'attività dovrebbe estendere la classe base astratta definita sopra come segue:
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.
}
});
}