Uprawnienie Androida nie działa, nawet jeśli to zadeklarowałem


167

Próbuję napisać kod, aby wysłać SMS-a z aplikacji na Androida, ale kiedy próbuję wysłać SMS-a, odsyła mi błąd:

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)

Sprawdziłem ale mam uprawnienia w manifeście, jak następuje:

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

Przeszukałem Internet, ale wszystkie błędy dotyczyły <uses-permission/>składni, czy możesz mi pomóc?


Na jakiej wersji Androida testujesz?
CommonsWare


1
na pewno będzie działać na niższej wersji Androida. Istnieje nowa filozofia uprawnień w
Androidzie

Czy istnieje specjalna składnia dla Androida 6? Jak mogę się upewnić, że działa w poniższej wersji?
Nathan Loudjani

mój poprzedni targetsdkversionzostał 23zaktualizowany do uprawnienia 27po aktualizacji aplikacji, które READ_SMSnie działa, które jest już włączone. proszę o pomoc
Sagar

Odpowiedzi:


237

(poniższy fragment pochodzi z mojego wpisu na blogu na ten temat )

Obecnie głównym powodem, dla którego nie otrzymujesz pozwolenia, jest to, że Twój projekt ma wartość targetSdkVersion23 lub wyższą, a pozwolenie, o które prosisz, jest „niebezpieczne”. W systemie Android 6.0 obejmuje to:

  • 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

Aby uzyskać te uprawnienia, nie tylko Twoja targetSdkVersionaplikacja 23+ musi mieć <uses-permission>element (y), ale musisz także poprosić o te uprawnienia w czasie wykonywania od użytkownika na urządzeniach z Androidem 6.0+, używając metod takich jak checkSelfPermission()i requestPermissions().

Jako tymczasowe obejście, upuść targetSdkVersionponiżej 23.

Jednak w końcu będziesz miał jakiś powód, aby chcieć, abyś miał targetSdkVersion23 lub więcej lat. W tym czasie będziesz musiał dostosować swoją aplikację do korzystania z nowego systemu uprawnień wykonawczych. Dokumentacja systemu Android zawiera stronę poświęconą temu tematowi .


2
Dziękuję bardzo, użyłem metody requestPermissions () i pracowałem dobrze
Nathan Loudjani

Okay, próbowałem tego wcześniej, ale nie mogłem uzyskać metod ContextCompat.checkSelfPermission i ActivityCompat.requestPermissions, podają mi błąd „nie znaleziono” w nazwach metod. Domyślam się, że ma to związek z brakującą biblioteką, wydaje się, że znajduje się w pakiecie v4, ale moja jedyna zależność od gradle to compile 'com.android.support:appcompat-v7:22.2.1'. Czy powinienem to zmienić na v4?
Ozzy,

2
@Ozzy: Musisz być w wersji 23 obsługujących bibliotek ( 23.x.ydla bieżących wartości x i y), a nie w wersji 22, której obecnie używasz.
CommonsWare

Dzięki, chyba na przyszłość. Na razie zmieniłem cel z powrotem na v22 i mimo że pamięć karty SD była ustawiona na 200MB na emulatorze, dało mi to błąd karty SD nie zamontowanej. Ale potem podłączyłem telefon w trybie programisty i wszystko działa. Z jakiegoś powodu pamięć na karcie SD działa na emulatorze z wersją 23, ale nie w wersji 22.
Ozzy,

3
@NathanLoudjani Czy mógłbyś udostępnić swój kod, który to implementuje? Jestem na tej samej łodzi i walczę, aby wprowadzić to do mojej działalności.
dschuett

29

Powyżej poziomu API 23 otrzymasz programowo pragmatycznie, jak:

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

        }
    }

7

żądanie uprawnień pragmatycznie (po 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
}

Jeśli aplikacja ma to uprawnienie, metoda checkSelfPermission () zwraca PERMISSION_GRANTED, a aplikacja może kontynuować operację.

Jeśli aplikacja nie ma uprawnień, metoda zwraca PERMISSION_DENIED, a aplikacja musi jawnie poprosić użytkownika o pozwolenie. Musisz poprosić użytkownika o to pozwolenie, jak pokazano w powyższym kodzie. Wywołanie requestPermissions () powoduje wyświetlenie standardowego okna dialogowego systemu Android, którego nie można dostosować. "


Gdzie umieścilibyśmy tę linię? ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SEND_SMS}, 1); i do czego odnosi się 1?
LizG


6

Kiedy deklarujesz permissonsię Manifesti nie pracują środki wykonujesz zadanie w MarshMallowi MarshMallowustawiono Permisson u RunTime.

w ten sposób

ActivityCompat.requestPermissions();

6

Skorzystaj z poniższego linku, https://developer.android.com/guide/topics/permissions/overview.html

Dostępnych jest tam również kilka próbek, aby rozpocząć od uprawnień.

Aby uczynić Androida bezpieczniejszym, programiści muszą teraz wspomnieć o zezwoleniu w manifeście, a także powinni poprosić użytkownika w czasie wykonywania o wykonanie pracy. Są to zezwolenia sklasyfikowane w sekcji zezwoleń niebezpiecznych, o których mowa poniżej

KALENDARZ

READ_CALENDAR

WRITE_CALENDAR

APARAT FOTOGRAFICZNY

CAMERA

ŁĄCZNOŚĆ

READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS

LOKALIZACJA

ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION

MIKROFON

RECORD_AUDIO

TELEFON

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

CZUJNIKI

BODY_SENSORS

SMS

SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS

PRZECHOWYWANIE

READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

2

Dodałem to do mojej MainActivity, aby rozwiązać mój problem

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

2

Jeśli używasz Androida w wersji „23” lub „23+”, aplikacja pokaże Ci błędy, gdy próbujesz uzyskać dostęp do czegokolwiek, co wymaga zgody użytkownika. Musisz poprosić o uprawnienia w czasie wykonywania, nawet jeśli zadeklarowałeś te uprawnienia w manifeście systemu Android.

Sprawdź: https://developer.android.com/training/permissions/requesting.html

Ale jeśli stworzyłeś całą aplikację i nie chcesz zmieniać w każdym miejscu, wystarczy mały cheat.

Przejdź do pliku „Build.gradle” i zmień docelową wersję Sdk na mniejszą niż 23, na przykład 22, 21.


1

Wraz z odpowiedzią CommonsWare,

Istnieje ustawienie zabezpieczeń (sprawdziłem na CM13), aby ustawić limit wiadomości SMS. Jeśli ustawisz to na „Brak”, system operacyjny wyświetli okno dialogowe dla każdego SMS-a, nawet po uzyskaniu pozwolenia SMS_SEND w środowisku wykonawczym. Najlepiej ustawić to na maksimum.

Jeśli maksimum nie wystarczy, istnieją sposoby na zwiększenie maksymalnej stawki na zrootowanym urządzeniu.


0

Możesz użyć tego kodu, aby uzyskać dostęp do swoich wiadomości

Otwórz okno dialogowe, używając poniższego kodu:

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

Uzyskaj wynik działania, jak poniżej:

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

lub edytuj plik build.gradlei numer chanche targetSdkVersionmniej niż 23
I nie potrzebujesz już powyższego kodu

UWAGA
Oczywiście tak nie jest i jest to tylko aspekt edukacyjny


0

Musiałem więc utworzyć aplikację do wysyłania i odbierania wiadomości, ale akcja wysyłania zawieszała się za każdym razem, gdy kliknąłem opcję Wyślij, mimo że pozwolenie zostało udzielone. Poprosiłem o uprawnienia wykonawcze i pozwoliłem im, nadal miałem awarię, że proces nie ma wymaganych uprawnień do wysyłania SMS-ów. Sprawdziłem nadane uprawnienia od:

adb shell dumpsys package <package-name>

Kolejność mojej prośby o uprawnienia była

  1. RECEIVE_SMS
  2. WYŚLIJ SMS

Cofnąłem kolejność żądań i działa dobrze. Zostało to przetestowane z kompletną nową aplikacją (odinstaluj-> zainstaluj -> test). Odpowiedź może wydawać się dziwna, ale po prostu daj jej szansę.

(Jeśli działa w pokazany sposób w określonej kolejności, Android może mieć błąd !!)


0

Mam nadzieję, że przyda się też rozwiązanie do zapisu na pamięci zewnętrznej

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.