Autorizzazioni M Android: onRequestPermissionsResult () non chiamato


291

Sto aggiornando la nostra app per utilizzare il nuovo sistema di autorizzazioni di runtime M. Funziona tutto tranne onRequestPermissionsResult (). Devo controllare un'autorizzazione alla pressione di un pulsante e, se ha esito positivo, inviare un messaggio di testo. Quando concedo l'autorizzazione per farlo, la finestra di dialogo si chiude, ma non attiva il messaggio di invio finché non premo di nuovo il pulsante.

Ho eseguito il debug e impostato i punti di interruzione nel metodo onRequestPermissionsResult () ma non è mai entrato.

Questo metodo viene chiamato per primo:

    private void askForPermission() {
    String[] permissions = new String[]{Manifest.permission.SEND_SMS};
    ActivityCompat.requestPermissions(getActivity(), permissions, PERMISSIONS_CODE);
}

E poi il mio callback assomiglia a questo:

    @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (requestCode == PERMISSIONS_CODE) {
        for (int i = 0; i < permissions.length; i++) {
            String permission = permissions[i];
            int grantResult = grantResults[i];

            if (permission.equals(Manifest.permission.SEND_SMS)) {
                if (grantResult == PackageManager.PERMISSION_GRANTED) {
                    onPPSButtonPress();
                } else {
                    requestPermissions(new String[]{Manifest.permission.SEND_SMS}, PERMISSIONS_CODE);
                }
            }
        }
    }
}

Qualcuno ha riscontrato un problema simile? Apprezzo qualsiasi aiuto con questo. Grazie

Risposte:


576

Ho riscontrato lo stesso problema e ho appena trovato la soluzione. Quando si utilizza la libreria di supporto, è necessario utilizzare le chiamate di metodo corrette. Per esempio:

  • In AppCompatActivity , è necessario utilizzare ActivityCompat.requestPermissions ;
  • Quando sei in android.support.v4.app.Fragment , dovresti usare semplicemente requestPermissions (questo è un metodo di istanza di android.support.v4.app.Fragment)

Se si chiama ActivityCompat.requestPermissions in un frammento, il callback onRequestPermissionsResult viene chiamato sull'attività e non sul frammento.

Spero che questo ti aiuti!


13

11
"Quando sei in android.support.v4.app.Fragment, dovresti usare semplicemente requestPermissions" - grazie!
Tigran Sarkisian,

5
@AnthonyBobenrieth quindi qual è la soluzione qui per le attività noHistory? Semplicemente non possiamo richiedere loro le autorizzazioni?
Dean Wild,

2
Il collegamento è interrotto @AnthonyBobenrieth. C'è qualche soluzione per nessuna storia?
Fersarr,

3
Durante l'utilizzo Fragment.requestPermissions(), l'attività principale sta effettivamente ricevendo il file onRequestPermissionsResult(). (Questo è con la libreria di supporto 23.3.0)
Someone Somewhere

101

Puoi provare questo:

requestPermissions(permissions, PERMISSIONS_CODE);

Se stai chiamando questo codice da un frammento ha il suo metodo requestPermissions. Credo che il problema sia che stai chiamando il metodo statico.

Suggerimento Pro se si desidera il onRequestPermissionsResult() in un frammento: FragmentCompat.requestPermissions(Fragment fragment, String[] permissions, int requestCode)


Grazie per l'aiuto. Ho notato che esiste un metodo requestPermissions se è in un frammento. Sono in un frammento e ho provato a chiamare solo requestPermissions, purtroppo non ha funzionato. Ho anche provato quello che hai menzionato e non ha funzionato.
AndyOHart,

Questo ha funzionato per me in Android M. Ma ti stai solo chiedendo se potrebbe causare problemi nei dispositivi Pre-M?
Bala Vishnu,

4
@goodgamerguy assicurati di non utilizzare il codice di richiesta in onRequestPermissionsResult of activity. se la tua attività utilizza anche il callback onRequestPermissionsResult, devi fornire le impostazioni predefinite: super.onRequestPermissionsResult (requestCode, autorizzazioni, grantResults);
Timmy Simons,

68

Spero che funzioni bene

Per attività:

 ActivityCompat.requestPermissions(this,permissionsList,REQUEST_CODE);

Per frammento:

 requestPermissions(permissionsList,REQUEST_CODE);

Che dire di SDK 15 e versioni precedenti?
Zulkarnain Shah,

4
Non hai bisogno dell'autorizzazione per l'SDK 15, solo Marshmallow e la versione precedente necessitano ..
Sanjay Mangaroliya,

50

Ho riscontrato anche questo problema. Se si desidera l'attività che gestisce le autorizzazioni non nella cronologia / recenti, si sarà tentati di modificare la AndroidManifest.xmlvoce.

Se si imposta l'attività che si chiama requestPermissionso AppCompatActivity.requestPermissionscon

android:noHistory="true"
android:excludeFromRecents="true"

nel tuo AndroidManifest.xmlallora onRequestPermissionsResult()non verrà chiamato. Questo è vero se la tua attività è derivata da Activityo AppCompatActivity.

Questo può essere risolto rimuovendo entrambi i flag da "AndroidManifest.xml" e terminando invece l'attività finishAndRemoveTask().


Avrei preferito non rimuovere l'attributo noHistory, ma questa era la soluzione che funzionava per me. Grazie!
Eric Schlenz,

1
Ho avuto il problema su Marshmallow ma non su Nougat, grazie ha funzionato per me
Yohan Dahmani,

37

Se hai onRequestPermissionsResultsia attività che frammento, assicurati di richiamare l' super.onRequestPermissionsResultattività. Non è richiesto in frammenti, ma è in attività.


Inoltre, tieni presente che se scegli come target un'API (come ad esempio 19), rimarrai comunque sotto il vecchio sistema del modello di autorizzazione e, quindi, non riceverai le chiamate di funzione relative all'autorizzazione della richiesta
Bonatti,

vedi la mia risposta se hai esteso un'altra attività che non chiama super
TouchBoarder il

3
Ci siamo imbattuti in questo. FragmentActivity.onRequestPermissionsResult(..)è dove onRequestPermissionsResult(..)viene inoltrata la chiamata al frammento .
JanPl

@Bonatti Quindi se provo a richiedere un permesso in Android 4.4.2 non otterrò un risultato? Quindi non posso modificare le autorizzazioni, solo vederle?
Alex Fragotsis,

@AlexanderFragotsis Otterrai un risultato. L'unica differenza è che non ti verrà chiesto di concedere l'autorizzazione, invece ti verrà automaticamente concesso dal sistema.
Dusan Zivkovic,

33

Risposta deprecata, fare riferimento a: https://developer.android.com/training/permissions/requesting

All'interno del frammento, devi chiamare:

FragmentCompat.requestPermissions(permissionsList, RequestCode)

Non:

ActivityCompat.requestPermissions(Activity, permissionsList, RequestCode);

2
Si riferisce a android.support.v13.app.FragmentCompat
Udi Oshi,

1
FragmentCompat è obsoleto a partire dall'API 27.1.0.
Big McLarge: enorme

la mia risposta è deprecata, consultare: developer.android.com/training/permissions/requesting
Ben.Slama.Jihed

15

Se stai usando requestPermissions in frammento, accetta 2 parametri invece di 3.

Dovresti usare requestPermissions(permissions, PERMISSIONS_CODE);


1
In realtà fornisce una risposta alla domanda. Chiamando requestPermissions (metodo di frammentazione dell'istanza) invece di ActivityCompat.requestPermissions, viene attivato il metodo del risultato. Qual è il problema principale qui. Grazie Don
Waclock,

15

Se per qualche motivo hai esteso un'attività personalizzata situata in una libreria esterna che non chiama il super, dovrai chiamare manualmente il frammento super.onRequestPermissionsRisultati nella tua attività onRequestPermissionsResult.

YourActivity extends SomeActivityNotCallingSuperOnRequestPermissionsResult{
Fragment requestingFragment;//the fragment requesting the permission
...
@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestingFragment!=null)
            requestingFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
...

12

Hai la funzione checkPermissions per i dispositivi pre Marshmallow in FragmentCompat . Io uso così:

FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);

2
Funziona solo se viene richiesta l'autorizzazione all'interno di android.app.fragment e devi importare la libreria support-v13!
MohammadReza,

4
FragmentCompat.requestPermissions () non funziona con android.support.v4.app.Fragment. Qualcuno sa come gestirlo.
Jutikorn,

12

Ho scoperto che è importante dove chiami android.support.v4.app.Fragment.requestPermissions.

Se lo fai onCreate(), onRequestPermissionsResult()non viene mai chiamato.

Soluzione: chiamalo onActivityCreated();

@Override
public void onActivityCreated(Bundle savedInstanceState) {

    super.onActivityCreated(savedInstanceState);

    if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_DENIED) 
        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 0);

}

1
Sto affrontando lo stesso problema ma non riesco a inserire il onActivityCreated()mio codice. SDK 23.
kAmol


Non sono in frammenti, sto provando a farlo su onCreate di un'attività
kAmol

Hmm, o usare onPause()?
almisoft,

10

Questo problema è stato effettivamente causato da NestedFragments. Fondamentalmente la maggior parte dei frammenti abbiamo esteso un HostedFragment che a sua volta estende un CompatFragment. La presenza di questi frammenti nidificati ha causato problemi che alla fine sono stati risolti da un altro sviluppatore nel progetto.

Stava facendo alcune cose di basso livello come il cambio di bit per farlo funzionare, quindi non sono troppo sicuro della soluzione finale effettiva


Questo mi ha aiutato a risolvere il mio problema: ho dovuto reindirizzare il risultato onRequestPermissionsResult dal frammento genitore al frammento figlio (nidificato). Grazie per il consiglio!
Murphy,

9
 /* use the object of your fragment to call the 
 * onRequestPermissionsResult in fragment after
 * in activity and use different request Code for 
 * both Activity and Fragment */

   if (isFragment)
    mFragment.requestPermissions(permissions.toArray(new
    String[permissions.size()]),requestPermission);

   else
    ActivityCompat.requestPermissions(mActivity,permissions.toArray(new
    String[permissions.size()]),requestPermission);

6

Questo funzionerà ..

@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

la super implementazione chiama l'implementazione dei frammenti non il suo framework
Mohammad Yahia il

5

Se stai chiamando questo codice da un frammento ha il suo metodo requestPermissions.

Quindi il concetto di base è: Se sei in un'attività, chiama

ActivityCompat.requestPermissions(this,
                            permissionsList,
                            permissionscode);

e se in un frammento, basta chiamare

requestPermissions(permissionsList,
                            permissionscode);

1
Richiede il livello API 23 ... Su quelli precedenti utilizzare FragmentCompat.requestPermissions().
Minas Mina,

5

Ho avuto un problema simile tranne che stavo premendo un pulsante per effettuare una chiamata, che attiva il callIntent. Ho controllato prima l'autorizzazione, se non concesso chiedo l'autorizzazione e onRequestPermissionResult chiamo l'autorizzazione di controllo e chiamo di nuovo.

 @Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case Constants.PERMISSIONS_REQUEST_CALL_PHONE: {
            if ( grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                checkPermissionsAndCall();
            }
        }
    }
}

public void checkPermissionsAndCall(){
    if (Build.VERSION.SDK_INT > 22) {
        if(ContextCompat.checkSelfPermission(getContext(),
                Manifest.permission.CALL_PHONE)
                != PackageManager.PERMISSION_GRANTED){
            requestPermissions( new String[]{Manifest.permission.CALL_PHONE}, Constants.PERMISSIONS_REQUEST_CALL_PHONE);
        }
        else{
            callIntent();
        }
    }
}


2

Prima di controllare tutto in base alle risposte precedenti, assicurati che il codice della tua richiesta non sia 0 !!!

controlla il codice di onRequestPermissionsResult () in FragmentActivity.java:

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) {
    int index = (requestCode>>16)&0xffff;
    if (index != 0) {
        index--;

        String who = mPendingFragmentActivityResults.get(index);
        mPendingFragmentActivityResults.remove(index);
        if (who == null) {
            Log.w(TAG, "Activity result delivered for unknown Fragment.");
            return;
        }
        Fragment frag = mFragments.findFragmentByWho(who);
        if (frag == null) {
            Log.w(TAG, "Activity result no fragment exists for who: " + who);
        } else {
            frag.onRequestPermissionsResult(requestCode&0xffff, permissions, grantResults);
        }
    }
}

2
private void showContacts() {
    if (getActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
    } else {
        doShowContacts();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        doShowContacts();
    }
}

2

Ho una soluzione straordinaria per raggiungere questo obiettivo. BaseActivity come questo.

public class BaseActivity extends AppCompatActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this));


}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    switch (requestCode) {
        case 1: {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                CustomToast.getInstance().setCustomToast("Now you can share the Hack.");

            } else {
                Toast.makeText(this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

}

Ora puoi chiamare il codice per chiedere l'autorizzazione in questo modo

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

Ora ogni volta che questo accade ovunque, sia nel tuo frammento che in qualsiasi attività, l'attività di base viene chiamata.

Grazie


1

È possibile utilizzare requestPermissions(PERMISSIONS, MULTIPLE_PERMISSIONS_CODE);. Non utilizzare FragmentCompat se si utilizza v4.


Per favore, spiega perché.
Posizionabile il

1

Dettagli

  • Kotlin 1.2.70
  • check in minSdkVersion 19
  • Android studio 3.1.4

Algoritmo

modulo - telecamera, posizione, ....

  1. Controlla se hasSystemFeature (se il modulo esiste nel telefono)
  2. Controlla se l'utente ha accesso al modulo
  3. Invia richiesta autorizzazioni (chiedi all'utente di consentire l' utilizzo del modulo )

Caratteristiche

  1. Lavora con attività e frammenti
  2. Ha solo una risposta al risultato
  3. Può controllare più moduli in una richiesta

Soluzione

class PermissionType(val manifest_permission: String, val packageManager: String) {
    object Defined {
        val camera = PermissionType(Manifest.permission.CAMERA, PackageManager.FEATURE_CAMERA)
        val currentLocation = PermissionType(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.FEATURE_LOCATION_GPS)
    }
}

class  Permission {

    enum class PermissionResult {
        ACCESS_ALLOWED, ACCESS_DENIED, NO_SYSTEM_FEATURE;
    }

    interface ManagerDelegate {
        fun permissionManagerDelegate(result: Array<Pair<String, PermissionResult>>)
    }

    class Manager internal constructor(private val delegate: ManagerDelegate?) {

        private var context: Context? = null
        private var fragment: Fragment? = null
        private var activity: AppCompatActivity? = null
        private var permissionTypes: Array<PermissionType> = arrayOf()
        private val REQUEST_CODE = 999
        private val semaphore = Semaphore(1, true)
        private var result: Array<Pair<String, PermissionResult>> = arrayOf()


        constructor(permissionType: PermissionType, delegate: ManagerDelegate?): this(delegate) {
            permissionTypes = arrayOf(permissionType)
        }

        constructor(permissionTypes: Array<PermissionType>, delegate: ManagerDelegate?): this(delegate) {
            this.permissionTypes = permissionTypes
        }

        init {
            when (delegate) {
                is Fragment -> {
                    this.fragment = delegate
                    this.context = delegate.context
                }

                is AppCompatActivity -> {
                    this.activity = delegate
                    this.context = delegate
                }
            }
        }

        private fun hasSystemFeature(permissionType: PermissionType) : Boolean {
            return context?.packageManager?.hasSystemFeature(permissionType.packageManager) ?: false
        }

        private fun hasAccess(permissionType: PermissionType) : Boolean {
            return if (Build.VERSION.SDK_INT < 23) true else {
                context?.checkSelfPermission(permissionType.manifest_permission) == PackageManager.PERMISSION_GRANTED
            }
        }

        private fun sendRequest(permissionTypes: Array<String>) {

            if (fragment != null) {
                fragment?.requestPermissions(permissionTypes, REQUEST_CODE)
                return
            }

            if (activity != null){
                ActivityCompat.requestPermissions(activity!!, permissionTypes, REQUEST_CODE)
            }
        }

        fun check() {

            semaphore.acquire()
            AsyncTask.execute {
                var permissionsForSendingRequest: Array<String> = arrayOf()
                this.result = arrayOf()

                for (it in permissionTypes) {
                    if (!hasSystemFeature(it)) {
                        result += Pair(it.manifest_permission, PermissionResult.NO_SYSTEM_FEATURE)
                        continue
                    }

                    if (hasAccess(it)) {
                        result += Pair(it.manifest_permission, PermissionResult.ACCESS_ALLOWED)
                    } else {
                        permissionsForSendingRequest += it.manifest_permission
                    }
                }

                if (permissionsForSendingRequest.isNotEmpty()) {
                    sendRequest(permissionsForSendingRequest)
                } else {
                    delegate?.permissionManagerDelegate(result)
                }
            }
        }

        fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
            when (requestCode) {
                REQUEST_CODE -> {
                    if (grantResults.isEmpty()) {
                        return
                    }
                    for ((i,permission) in permissions.withIndex()) {
                        for (item in this.permissionTypes) {
                            if (permission == item.manifest_permission && i < grantResults.size) {
                                result += if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                                    Pair(item.manifest_permission, PermissionResult.ACCESS_ALLOWED)
                                } else {
                                    Pair(item.manifest_permission, PermissionResult.ACCESS_DENIED)
                                }
                                break
                            }
                        }
                    }
                    delegate?.permissionManagerDelegate(result)
                }
            }
            semaphore.release()
        }
    }
}

Utilizzo in attività (in frammenti uguali)

class BaseActivity : AppCompatActivity(), Permission.ManagerDelegate {

    private lateinit var permissionManager: Permission.Manager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.base_activity)

        permissionManager = Permission.Manager(arrayOf(PermissionType.Defined.camera, PermissionType.Defined.currentLocation), this)
        permissionManager.check()
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        permissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }


    override fun permissionManagerDelegate(result: Array<Pair<String, Permission.PermissionResult>>) {
        result.forEach {
            println("!!! ${it.first} ${it.second}")
//            when (it.second) {
//                Permission.PermissionResult.NO_SYSTEM_FEATURE -> {
//                }
//
//                Permission.PermissionResult.ACCESS_DENIED  -> {
//                }
//
//                Permission.PermissionResult.ACCESS_ALLOWED -> {
//                }
//            }
        }
    }
}

1

Qui voglio mostrare il mio codice come ho gestito questo.

public class CheckPermission {

public Context context;

public static final int PERMISSION_REQUEST_CODE =  200;

public CheckPermission(Context context){
    this.context = context;
}

public boolean isPermissionGranted(){
    int read_contact = ContextCompat.checkSelfPermission(context.getApplicationContext() , READ_CONTACTS);
    int phone = ContextCompat.checkSelfPermission(context.getApplicationContext() , CALL_PHONE);

    return read_contact == PackageManager.PERMISSION_GRANTED && phone == PackageManager.PERMISSION_GRANTED;
   }
}

Qui in questa classe voglio verificare l'autorizzazione concessa o meno. Non è allora che chiamerò il permesso dal mio MainActivity come

public void requestForPermission() {
       ActivityCompat.requestPermissions(MainActivity.this, new String[]    {READ_CONTACTS, CALL_PHONE}, PERMISSION_REQUEST_CODE);
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)) {
                    showMessageOKCancel("You need to allow access to both the permissions",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE},
                                                PERMISSION_REQUEST_CODE);
                                    }
                                }
                            });
                    return;
                }
            }
    }
}

Ora nel metodo onCreate è necessario chiamare la funzione requestForPermission ().

Questo è tutto. Puoi anche richiedere più autorizzazioni alla volta.


1

AGGIORNAMENTO: ho visto la risposta di qualcun altro sulla chiamata super.onRequestPermissionResult()in Attività e questo risolve il problema con il codice di richiesta che ho citato e chiama il frammento onRequestPermissionResult.

ignora questa roba:

Per me stava chiamando onRequestPermissionResultl'attività nonostante io stessi chiamandofragment.requestPermission(...) , MA ha restituito il risultato con un requestCode errato (111 trasformato in 65647 perché ??? Non lo saprò mai).

Fortunatamente questa è l'unica autorizzazione che chiediamo su quella schermata, quindi ignoro semplicemente il codice di richiesta (non ho tempo per capire perché non è corretto in questo momento)


Aggiungi 65536 e 111 e lo otterrai. Ciò è dovuto alle maschere di bit. Vedi alcuni argomenti.
CoolMind,

0

Ho anche riscontrato un problema che anche se chiami richieste richieste corrette, puoi ancora avere questo problema. Il problema è che l'attività principale può sovrascrivere questo metodo senza chiamare super. Aggiungi super e verrà risolto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.