Los receptores de difusión no funcionan en Android 6.0 Marshmallow

Acabo de actualizar mi Nexus 5 a android 6, hasta ahora mi aplicación funcionaba bien, pero ahora los receptores de difusión no funcionan. ¿Ha cambiado algo en la nueva versión? Aquí está el código que probé que estaba trabajando en versiones anteriores pero no en marshmallow –

Manifiesto de Android

     

Receptor de radiodifusión

 public String TAG ="someClass"; private static String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED"; public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equalsIgnoreCase(ACTION_SMS_RECEIVED)) { Log.d(TAG, "Received..."); } } 

Servicio

 Broadcast_receiver broadcast_receiver = new Broadcast_receiver(); IntentFilter filter1 = new IntentFilter(); filter1.addAction("android.provider.Telephony.SMS_RECEIVED"); registerReceiver(broadcast_receiver, filter1); 

Del mismo modo, el receptor de difusión para PHONE_STATE tampoco funciona.

El nivel de API de destino de su aplicación es 23, es decir, Android M (6.0). En Android M hay grandes cambios relacionados con los permisos de usuario. Aquí hay un buen artículo explicando los cambios.

Como se indica en Android – Solicitud de permisos

A partir de Android 6.0 (nivel de API 23), los usuarios conceden permisos a las aplicaciones mientras se ejecuta la aplicación, no cuando instalan la aplicación … El usuario puede revocar los permisos en cualquier momento …

También se afirma que:

Los permisos del sistema se dividen en dos categorías, normales y peligrosos:

  1. Los permisos normales no ponen en riesgo directamente la privacidad del usuario. Si su aplicación enumera un permiso normal en su manifiesto, el sistema otorga el permiso automáticamente

  2. Los permisos peligrosos pueden dar acceso a la aplicación a los datos confidenciales del usuario. Si enumera un permiso peligroso, el usuario tiene que aprobar explícitamente su aplicación

Aquí hay una lista completa de permisos peligrosos y permisos normales

Todo eso básicamente significa que debe solicitar manualmente cualquier permiso peligroso, cuando realmente se necesita.

Dado que es posible que se necesite varias veces en el código, puede crear un método reutilizable que compruebe si ya se ha otorgado un permiso específico y, en caso contrario, solicitarlo al usuario.

Aquí un ejemplo:

Java

 public class PermissionManager { //A method that can be called from any Activity, to check for specific permission public static void check(Activity activity, String permission, int requestCode){ //If requested permission isn't Granted yet if (ActivityCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) { //Request permission from user ActivityCompat.requestPermissions(activity,new String[]{permission},requestCode); } } } 

Kotlin

 object PermissionManager { //A method that can be called from any Activity, to check for specific permission fun check(activity: Activity, permission: String, requestCode: Int) { //If requested permission isn't Granted yet if (ActivityCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) { //Request permission from user ActivityCompat.requestPermissions(activity, arrayOf(permission), requestCode) } } } 

Uso:

Java

 //Inside your activity: //1. Define static constant for each permission request public static final int REQUEST_CODE_FOR_SMS=1; //2. When needed (for example inside .onStart event) use method PermissionManager.check for requested permission @Override protected void onStart() { super.onStart(); PermissionManager.check(this, Manifest.permission.RECEIVE_SMS, REQUEST_CODE_FOR_SMS); } //3. Handle User's response for your permission request @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if(requestCode==REQUEST_CODE_FOR_SMS){//response for SMS permission request if(grantResults[0]==PackageManager.PERMISSION_GRANTED){ //What to do if User allowed SMS permission }else{ //What to do if user disallowed requested SMS permission } } } 

Kotlin

 //Inside your activity: //1. Define static constant for each permission request val REQUEST_CODE_FOR_SMS = 1 //2. When needed (for example inside .onStart event) use method PermissionManager.check for requested permission override fun onStart() { super.onStart() PermissionManager.check(this, Manifest.permission.RECEIVE_SMS, REQUEST_CODE_FOR_SMS) } //3. Handle User's response for your permission request override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { if (requestCode == REQUEST_CODE_FOR_SMS) {//response for SMS permission request if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { //What to do if User allowed SMS permission } else { //What to do if user disallowed requested SMS permission } } } 

Nota:

  1. Si necesita usar PermissionManager.check dentro de la instancia de Fragment , use: getActivity() como su primer parámetro.

  2. Puede usar checkSelfPermission dentro Service instancia del Service , para verificar si ya se ha otorgado algún permiso, pero no solicitar requestPermissions para solicitarlo. Porque checkSelfPermission se puede usar para cualquier Context , pero requestPermissions solo para Activity

Marshmallow está bloqueando los permisos peligrosos.

Esto no se aplica al escenario enumerado, pero podría ayudar a otra persona. Seguí llegando a este SO por qué algunos de nuestros Receptores de Difusión no estaban funcionando. Tenemos una configuración de permisos personalizada y tenía el android:protectionLevel="dangerous" . Se lo cambió a android:protectionLevel= "signature" y todo comenzó a funcionar.