A permissão do Android não funciona, mesmo que eu a tenha declarado

167

Estou tentando escrever um código para enviar um SMS de um aplicativo Android, mas quando tento enviar o SMS, ele retorna o erro:

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)

Eu verifiquei, mas tenho as permissões no manifesto, da seguinte maneira:

<?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>

Pesquisei na internet, mas todos os erros eram sobre a <uses-permission/>sintaxe, você poderia me ajudar, por favor?

Nathan Loudjani
fonte
Em qual versão do Android você está testando?
CommonsWare
Estou testando no Android 6.0
Nathan Loudjani
1
certamente funcionará em uma versão abaixo do android. Há uma nova filosofia de permissões no Android 6.0
Fakher
Existe uma sintaxe especial para o Android 6? Como posso ter certeza de que funciona na versão abaixo?
Nathan Loudjani
meu anterior targetsdkversionfoi 23atualizado para a permissão de 27atualização de aplicativo READ_SMSnão está funcionando, o que já está ativado. por favor ajude
Sagar

Respostas:

238

(o seguinte é extraído de uma publicação minha no blog sobre isso )

O grande motivo para não obter sua permissão hoje em dia é porque seu projeto tem targetSdkVersion23 ou mais, e a permissão que você está solicitando é "perigosa". No Android 6.0, isso inclui:

  • 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 essas permissões, o targetSdkVersionaplicativo mais de 23 anos não precisa apenas ter o <uses-permission>(s) elemento (s), mas você também precisa solicitar essas permissões em tempo de execução ao usuário em dispositivos Android 6.0+, usando métodos como checkSelfPermission()e requestPermissions().

Como solução temporária, reduza o número targetSdkVersionabaixo de 23.

No entanto, eventualmente, você terá algum motivo para querer targetSdkVersionter 23 anos ou mais. Nesse momento, você precisará ajustar seu aplicativo para usar o novo sistema de permissão de tempo de execução. A documentação do Android tem uma página dedicada a este tópico .

CommonsWare
fonte
2
Muito obrigado, usei os métodos requestPermissions () e
funcionei
Ok, eu tentei isso antes, mas não consegui obter os métodos ContextCompat.checkSelfPermission e ActivityCompat.requestPermissions, eles me deram um erro 'não encontrado' nos nomes dos métodos. Acho que tem a ver com uma biblioteca ausente, parece estar em um pacote v4, mas minha única dependência gradle é compile 'com.android.support:appcompat-v7:22.2.1'. Devo mudar isso para v4?
Ozzy
2
@ Ozzy: Você precisa estar em uma geração v23 das bibliotecas de suporte ( 23.x.ypara valores atuais de xey), em vez da v22 que você está usando no momento.
CommonsWare
Obrigado, para o futuro, eu acho. Por enquanto, mudei o destino de volta para v22 e, embora o armazenamento do cartão SD tenha sido definido como 200 MB no emulador, isso me deu um erro de não montar o cartão SD. Mas então conectei meu telefone no modo de desenvolvedor e tudo funciona. Por algum motivo, o armazenamento do cartão SD funciona no emulador executando a v23, mas não a v22.
Ozzy
3
@NathanLoudjani Você se importaria de compartilhar seu código que implementa isso? Estou exatamente no mesmo barco e estou lutando para colocar isso em minha atividade.
dschuett
29

Acima do nível 23 da API, você receberá programaticamente de forma pragmática:

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

        }
    }
user7176550
fonte
7

solicitar permissão pragmaticamente (após a 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
}

"Se o aplicativo tiver permissão, o método checkSelfPermission () retornará PERMISSION_GRANTED e o aplicativo poderá prosseguir com a operação.

Se o aplicativo não tiver permissão, o método retornará PERMISSION_DENIED e o aplicativo deverá solicitar explicitamente permissão ao usuário. Você precisa solicitar ao usuário essa permissão, conforme mostrado no código acima. Chamar requestPermissions () exibe uma caixa de diálogo padrão do Android, que você não pode personalizar. "

Dan Alboteanu
fonte
Onde colocaríamos essa linha? ActivityCompat.requestPermissions (este, novo String [] {Manifest.permission.SEND_SMS}, 1); e a que o 1 se refere?
LizG
6

Se você estiver usando o sdk 23 ou superior, verifique as permissões de tempo de execução.

Dharmendra Pratap
fonte
6

quando você declarar permissonno Manifeste não é trabalho significa que você está executando tarefas no MarshMallowe para MarshMallowvocê definiu permisson no RunTime.

assim

ActivityCompat.requestPermissions();
Harshad Pansuriya
fonte
6

Por favor, acesse o link abaixo, https://developer.android.com/guide/topics/permissions/overview.html

Algumas amostras também estão disponíveis lá para começar com as permissões.

Para tornar o android mais seguro, agora os desenvolvedores precisam mencionar a permissão no manifesto e também devem solicitar ao usuário, em tempo de execução, que faça o trabalho. Eles são permissão categorizada na seção de permissão perigosa, mencionada abaixo

CALENDÁRIO

READ_CALENDAR

WRITE_CALENDAR

CÂMERA

CAMERA

CONTATOS

READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS

LOCALIZAÇÃO

ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION

MICROFONE

RECORD_AUDIO

TELEFONE

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

ARMAZENAMENTO

READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
Rishabh Saxena
fonte
2

Adicionei isso ao meu MainActivity, que resolve meu 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
fonte
2

Se você estiver usando a versão Android "23" ou "23+", o aplicativo mostrará erros quando você estiver tentando acessar qualquer coisa que exija a permissão do usuário. Você precisa solicitar permissões em tempo de execução, mesmo se tiver declarado essas permissões no manifesto do Android.

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

Mas se você criou todo o seu aplicativo e não deseja mudar em todos os lugares, um pequeno truque será suficiente.

Vá para o arquivo "Build.gradle" e altere a versão do Sdk de destino para menos de 23, como 22, 21.

Zohaib Hassan
fonte
1

Juntamente com a resposta do CommonsWare,

Há uma configuração de segurança (verifiquei no CM13) para definir o limite de mensagens SMS. Se você definir como "Nenhum", o SO abrirá uma caixa de diálogo para cada SMS, mesmo após a obtenção da permissão SMS_SEND no tempo de execução. O melhor é definir isso para o máximo.

Se o máximo não for suficiente, existem maneiras de aumentar a taxa máxima em um dispositivo raiz.

Dumi Jay
fonte
0

Você pode usar esse código para acessar suas mensagens

Abra uma caixa de diálogo usando o código abaixo:

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

Obtenha o resultado da atividade como abaixo:

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

ou edite o build.gradlenúmero do arquivo e do chanche targetSdkVersionmenor que 23
E não precisa mais do código acima

NOTA
É claro que esse não é o caso, e é apenas um aspecto educacional

Amirhf
fonte
0

Então, eu tive que criar um aplicativo para enviar e receber mensagens, mas a ação de envio falhava sempre que eu clicava em enviar, mesmo com a permissão concedida. Eu havia solicitado permissões de tempo de execução e permitido, ainda assim eu enfrentei uma falha que o processo não tem a permissão solicitada para enviar SMS. Eu verifiquei as permissões concedidas em:

adb shell dumpsys package <package-name>

A ordem do meu pedido de permissões foi

  1. RECEIVE_SMS
  2. ENVIAR SMS

Reverti a ordem do pedido e funciona bem. Isso foi testado com um novo aplicativo completo (desinstalar-> instalar -> testar). A resposta pode parecer estranha, mas apenas tente.

(Se funcionar da maneira mostrada em uma determinada ordem, o Android poderá ter um erro!)

Partha Sarathi Murmu
fonte
0

Espero que a solução para gravar no armazenamento externo seja útil também

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
fonte