Buscar..


Introducción

Android Marshmallow introdujo el modelo Runtime Permission . Los permisos se clasifican en dos categorías, es decir, permisos normales y peligrosos . donde ahora el usuario otorga permisos peligrosos en tiempo de ejecución.

Observaciones

Desde el SDK 23, Android requiere permisos de tiempo de ejecución para permisos en dispositivos que ejecutan Android 6.0 y superior, dentro de lo que se clasifica como los Grupos de permisos peligrosos. Los grupos de permisos peligrosos son aquellos que se considera que comprometen la privacidad y / o seguridad del usuario.

La siguiente es una lista de grupos de permisos peligrosos:

Grupos de permisos peligrosos

Grupo de permisos
CALENDARIO
CÁMARA
CONTACTOS
UBICACIÓN
MICRÓFONO
TELÉFONO
Sensores
SMS
ALMACENAMIENTO

Cualquier permiso de estos grupos requiere la administración de permisos de tiempo de ejecución para dispositivos en Android 6.0 y superior con un sdk de destino de 23 o superior.

Permisos normales

La siguiente es una lista de permisos normales. Estos no se consideran peligrosos para la privacidad o seguridad del usuario, por lo que no requieren permisos de tiempo de ejecución para sdk 23 y superior.

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
AJUSTAR ALARMA
SET_TIME_ZONE
ESTABLECER FONDO DE PANTALLA
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRAR
WAKE_LOCK
WRITE_SYNC_SETTINGS

Android 6.0 permisos múltiples

Este ejemplo muestra cómo verificar los permisos en tiempo de ejecución en Android 6 y versiones posteriores.

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;
        }
    }
}

Cumplimiento de permisos en difusiones, URI

Puede realizar una verificación de permisos al enviar un Intent a un receptor de difusión registrado. Los permisos que envía se cotejan con los registrados bajo la etiqueta. Restringen quién puede enviar transmisiones al receptor asociado.

Para enviar una solicitud de difusión con permisos, especifique el permiso como una cadena en la Context.sendBroadcast(Intent intent, String permission) , pero tenga en cuenta que la aplicación del receptor DEBE tener ese permiso para recibir su transmisión. El receptor debe instalarse primero antes que el remitente.

La firma del método es:

 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");

y puede especificar en su manifiesto que el remitente de difusión debe incluir el permiso solicitado enviado a través de sendBroadcast:

 <!--  Your special permission -->
 <permission android:name="org.quadcore.mypermission" 
    android:label="my_permission" 
    android:protectionLevel="dangerous"></permission>

También declare el permiso en el manifiesto de la aplicación que debe recibir esta transmisión:

 <!--  I use the permission ! -->
 <uses-permission android:name="org.quadcore.mypermission"/>
 <!-- along with the receiver -->
 <receiver android:name="Bcastreceiver" android:exported="true" />

Nota: Tanto un receptor como una emisora ​​pueden requerir un permiso, y cuando esto sucede, ambas comprobaciones de permisos deben pasar para que la Intención se entregue al destino asociado. La aplicación que define el permiso se debe instalar primero.

Encuentra la documentación completa aquí en Permisos.

Permisos de tiempo de ejecución múltiples de los mismos grupos de permisos

En el manifiesto tenemos cuatro permisos de tiempo de ejecución peligrosos de dos grupos.

<!-- 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"/>

En la actividad donde se requieren los permisos. Tenga en cuenta que es importante verificar los permisos en cualquier actividad que requiera permisos, ya que los permisos se pueden revocar mientras la aplicación está en segundo plano y la aplicación se bloqueará.

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();
    }

Solo necesitamos pedir permiso para uno de estos de cada grupo y todos los demás permisos de este grupo se otorgan a menos que el usuario revoque el permiso.

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;
}

Se trata del resultado de que el usuario permita o no permita permisos. En este ejemplo, si los permisos no están permitidos, la aplicación se cancela.

@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);
    }
}

Más información https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en

Usando PermissionUtil

PermissionUtil es una forma simple y conveniente de solicitar permisos en contexto. Puede proporcionar fácilmente lo que debería suceder en el caso de todos los permisos solicitados concedidos ( onAllGranted() ), cualquier solicitud fue denegada ( onAnyDenied() ) o en caso de que se necesite un racional ( onRational() ).

En cualquier lugar de su AppCompatActivity o Fragmento, desea solicitar la autorización del usuario.

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);

Y agregar esto a onRequestPermissionsResult

if(mRequestObject!=null){
    mRequestObject.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

Agrega el permiso solicitado a tu AndroidManifest.xml también

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Incluya todo el código relacionado con permisos para una clase base abstracta y extienda la actividad de esta clase base para lograr un código más limpio / reutilizable

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);
    }
}

Ejemplo de uso en la actividad.

La actividad debe ampliar la clase base abstracta definida anteriormente de la siguiente manera:

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.
        }
    });
}


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow