El permiso de Android no funciona incluso si lo he declarado

167

Estoy tratando de escribir código para enviar un SMS desde una aplicación de Android, pero cuando intento enviar el SMS, me devuelve el error:

09-17 18:37:29.974  12847-12847/**.**.****E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: **.**.****, PID: 12847
java.lang.SecurityException: Sending SMS message: uid 10092 does not have android.permission.SEND_SMS.
        at android.os.Parcel.readException(Parcel.java:1599)
        at android.os.Parcel.readException(Parcel.java:1552)
        at com.android.internal.telephony.ISms$Stub$Proxy.sendTextForSubscriber(ISms.java:768)
        at android.telephony.SmsManager.sendTextMessageInternal(SmsManager.java:310)
        at android.telephony.SmsManager.sendTextMessage(SmsManager.java:293)
        at **.**.****.MainActivity$3.onClick(MainActivity.java:70)
        at android.view.View.performClick(View.java:5198)
        at android.view.View$PerformClick.run(View.java:21147)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5417)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

Lo comprobé pero tengo los permisos en el manifiesto, de la siguiente manera:

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-feature android:name="android.hardware.telephony"
    android:required="true"/>

<application
    android:exported="true"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

Busqué en Internet pero todos los errores estaban relacionados con la <uses-permission/>sintaxis, ¿podrían ayudarme por favor?

Nathan Loudjani
fuente
¿En qué versión de Android estás probando?
CommonsWare
Estoy probando en Android 6.0
Nathan Loudjani
1
seguramente funcionará en una versión de Android a continuación. Hay una nueva filosofía de permisos en Android 6.0
Fakher
¿Existe una sintaxis especial para Android 6? ¿Cómo puedo estar seguro de que funciona en la versión siguiente?
Nathan Loudjani
mi anterior targetsdkversionse 23actualizó a 27después de que el READ_SMSpermiso de actualización de la aplicación no funciona, que ya está habilitado. por favor ayuda
Sagar

Respuestas:

238

(Lo siguiente se extrae de una publicación de blog mía sobre esto )

La gran razón para no obtener su permiso hoy en día es porque su proyecto tiene un targetSdkVersion23 o más, y el permiso que solicita es "peligroso". En Android 6.0, esto incluye:

  • ACCESS_COARSE_LOCATION
  • ACCESS_FINE_LOCATION
  • ADD_VOICEMAIL
  • BODY_SENSORS
  • CALL_PHONE
  • CAMERA
  • GET_ACCOUNTS
  • PROCESS_OUTGOING_CALLS
  • READ_CALENDAR
  • READ_CALL_LOG
  • READ_CELL_BROADCASTS
  • READ_CONTACTS
  • READ_EXTERNAL_STORAGE
  • READ_PHONE_STATE
  • READ_SMS
  • RECEIVE_MMS
  • RECEIVE_SMS
  • RECEIVE_WAP_PUSH
  • RECORD_AUDIO
  • SEND_SMS
  • USE_SIP
  • WRITE_CALENDAR
  • WRITE_CALL_LOG
  • WRITE_CONTACTS
  • WRITE_EXTERNAL_STORAGE

Para estos permisos, no solo su targetSdkVersionaplicación 23+ necesita tener los <uses-permission>elementos, sino que también debe solicitar esos permisos en tiempo de ejecución al usuario en dispositivos Android 6.0+, usando métodos como checkSelfPermission()y requestPermissions().

Como solución temporal, deje caer sus targetSdkVersion23 por debajo.

Sin embargo, eventualmente, tendrás alguna razón para querer targetSdkVersionque tengas 23 años o más. En ese momento, deberá ajustar su aplicación para usar el nuevo sistema de permisos de tiempo de ejecución. La documentación de Android tiene una página dedicada a este tema .

CommonsWare
fuente
2
Muchas gracias, utilicé los métodos requestPermissions () y trabajé bien
Nathan Loudjani
Bien, intenté esto antes pero no pude obtener los métodos ContextCompat.checkSelfPermission y ActivityCompat.requestPermissions, me dan un error 'no encontrado' en los nombres de los métodos. Supongo que tiene que ver con una biblioteca que falta, parece estar en un paquete v4 pero mi única dependencia de Gradle es compile 'com.android.support:appcompat-v7:22.2.1'. ¿Debo cambiar esto a v4?
Ozzy
2
@Ozzy: debe estar en una generación v23 de las bibliotecas de soporte ( 23.x.ypara los valores actuales de x e y), en lugar de la v22 que está utilizando actualmente.
CommonsWare
Gracias, por el futuro, supongo. Por ahora cambié el objetivo a v22 y aunque el almacenamiento de la tarjeta SD se configuró en 200 MB en el emulador, me dio un error de tarjeta SD no montada. Pero luego conecté mi teléfono en modo desarrollador y todo funciona. Por alguna razón, el almacenamiento de la tarjeta SD funciona en el emulador que ejecuta v23 pero no v22.
Ozzy
3
@NathanLoudjani ¿Te importaría compartir tu código que implementa esto? Estoy exactamente en el mismo barco y estoy luchando por poner esto en mi actividad.
dschuett
29

Por encima del nivel 23 de API, se le proporcionará mediante programación pragmáticamente como:

    private static final int PERMISSION_REQUEST_CODE = 1;

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {

        if (checkSelfPermission(Manifest.permission.SEND_SMS)
                == PackageManager.PERMISSION_DENIED) {

            Log.d("permission", "permission denied to SEND_SMS - requesting it");
            String[] permissions = {Manifest.permission.SEND_SMS};

            requestPermissions(permissions, PERMISSION_REQUEST_CODE);

        }
    }
usuario7176550
fuente
7

solicitar permiso pragmáticamente (después de API 23)

if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.SEND_SMS)
    != PackageManager.PERMISSION_GRANTED) {
    // Permission is not granted 
    // Ask for permision
    ActivityCompat.requestPermissions(this,new String[] { Manifest.permission.SEND_SMS}, 1); 
} 
else {
// Permission has already been granted
}

"Si la aplicación tiene el permiso, el método checkSelfPermission () devuelve PERMISSION_GRANTED, y la aplicación puede continuar con la operación.

Si la aplicación no tiene el permiso, el método devuelve PERMISSION_DENIED, y la aplicación tiene que pedirle permiso explícitamente al usuario. Debe solicitar al usuario ese permiso, como se muestra en el código anterior. Al llamar a requestPermissions (), aparece un cuadro de diálogo estándar de Android que no puede personalizar ".

Dan Alboteanu
fuente
¿Dónde pondríamos esta línea? ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SEND_SMS}, 1); ¿Y a qué se refiere el 1?
LizG
6

Si está utilizando SDK 23 o superior, debe verificar los permisos de tiempo de ejecución.

Dharmendra Pratap
fuente
6

cuando se declara permissonen Manifesty no de trabajo significa que usted esté realizando tareas en MarshMallowy para MarshMallowque haya configurado en permisson RunTime.

de esta manera

ActivityCompat.requestPermissions();
Harshad Pansuriya
fuente
6

Visite el siguiente enlace, https://developer.android.com/guide/topics/permissions/overview.html

Algunas muestras también están disponibles allí para comenzar con los permisos.

Para hacer que Android sea más seguro ahora, los desarrolladores deben mencionar el permiso en manifiesto, así como también deberían pedirle al usuario en tiempo de ejecución que realice el trabajo. Son permisos categorizados en la sección de permisos peligrosos que se mencionan a continuación

CALENDARIO

READ_CALENDAR

WRITE_CALENDAR

CÁMARA

CAMERA

CONTACTOS

READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS

UBICACIÓN

ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION

MICRÓFONO

RECORD_AUDIO

TELÉFONO

READ_PHONE_STATE
READ_PHONE_NUMBERS
CALL_PHONE
ANSWER_PHONE_CALLS (must request at runtime)
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
ANSWER_PHONE_CALLS

SENSORES

BODY_SENSORS

SMS

SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS

ALMACENAMIENTO

READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
Rishabh Saxena
fuente
2

Agregué esto a mi actividad principal, que resuelve mi problema

       int MY_PERMISSIONS_REQUEST_READ_CONTACTS=0;
// Here, thisActivity is the current activity
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

                // Show an expanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.

            } else {

                // No explanation needed, we can request the permission.

                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        MY_PERMISSIONS_REQUEST_READ_CONTACTS);

                // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
                // app-defined int constant. The callback method gets the
                // result of the request.
            }
        }
Masquitos
fuente
2

Si está utilizando la versión de Android "23" o "23+", la aplicación le mostrará errores cuando intente acceder a cualquier cosa que requiera permiso del usuario. Tiene que solicitar permisos en tiempo de ejecución, incluso si ha declarado esos permisos en el manifiesto de Android.

Verifique esto: https://developer.android.com/training/permissions/requesting.html

Pero si ha creado toda su aplicación y no quiere cambiar en cada lugar, entonces un poco de trampa será suficiente.

Vaya al archivo "Build.gradle" y cambie la versión de Sdk de destino a menos de 23, como 22, 21.

Zohaib Hassan
fuente
1

Junto con la respuesta de CommonsWare,

Hay una configuración de seguridad (verifiqué en CM13) para establecer el límite de mensajes SMS. Si establece esto en "Ninguno", el sistema operativo abrirá un cuadro de diálogo para cada SMS, incluso después de obtener el permiso SMS_SEND en el tiempo de ejecución. Lo mejor es configurar esto al máximo.

Si el máximo no es suficiente, hay formas de aumentar la tasa máxima en un dispositivo rooteado.

Dumi Jay
fuente
0

Puedes usar este código para acceder a tus mensajes

Abra un cuadro de diálogo con el siguiente código:

ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    1);

Obtenga el resultado de la actividad de la siguiente manera:

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case 1: {

          // If request is cancelled, the result arrays are empty.
          if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.          
            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
                Toast.makeText(MainActivity.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

o edite el archivo build.gradley el número de cambio targetSdkVersionmenos de 23
Y ya no necesita el código anterior

NOTA
Por supuesto, este no es el caso, y es solo un aspecto educativo

Amirhf
fuente
0

Así que tuve que crear una aplicación para enviar y recibir mensajes, pero la acción de envío se bloqueaba cada vez que hacía clic en enviar a pesar de que se me concedió el permiso. Solicité permisos de tiempo de ejecución y los permití, pero me enfrenté a un bloqueo que el proceso no tiene el permiso solicitado para enviar SMS. Verifiqué los permisos otorgados de:

adb shell dumpsys package <package-name>

El orden de mi solicitud de permisos fue

  1. RECIBIR_SMS
  2. ENVIAR SMS

Revertí el orden de solicitud y funciona bien. Esto se probó con una nueva aplicación completa (desinstalar-> instalar -> probar). La respuesta puede parecer extraña, pero solo inténtalo.

(Si funciona de la manera mostrada en un cierto orden, ¡entonces Android podría tener un error!)

Partha Sarathi Murmu
fuente
0

Espero que la solución para escribir en almacenamiento externo también sea útil

public  boolean checkPermission() {
        if (Build.VERSION.SDK_INT >= 23) {
            if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED) {
                Timber.tag(LOG_TAG).e("Permission error. You have permission");
                return true;
            } else {
                Timber.tag(LOG_TAG).e("Permission error. You have asked for permission");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                return false;
            }
        }
        else { 
            // for a stuff below api level 23
            Timber.tag(LOG_TAG).e("Permission error. You already have the permission");
            return true;
        }
    }
SergeyUr
fuente