Permissões do Android M: onRequestPermissionsResult () não sendo chamado


291

Estou atualizando nosso aplicativo para usar o novo sistema de permissões de tempo de execução M. Está tudo funcionando, exceto onRequestPermissionsResult (). Preciso verificar uma permissão pressionando o botão e, se tiver êxito, enviar uma mensagem de texto. Quando concedo permissão para fazê-lo, a caixa de diálogo é fechada, mas não aciona o envio de texto até que eu pressione o botão novamente.

Depurei e defini pontos de interrupção no método onRequestPermissionsResult (), mas ele nunca entra nele.

Este método é chamado primeiro:

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

E então meu retorno de chamada fica assim:

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

Alguém já teve um problema semelhante? Agradeço qualquer ajuda com isso. obrigado

Respostas:


576

Encontrei o mesmo problema e encontrei a solução. Ao usar a biblioteca de Suporte, você deve usar as chamadas de método corretas. Por exemplo:

  • Quando em AppCompatActivity , você deve usar ActivityCompat.requestPermissions ;
  • Quando em android.support.v4.app.Fragment , você deve usar simplesmente requestPermissions (este é um método de instância de android.support.v4.app.Fragment)

Se você chamar ActivityCompat.requestPermissions em um fragmento, o retorno de chamada onRequestPermissionsResult será chamado na atividade e não no fragmento.

Espero que isto ajude!



11
"No android.support.v4.app.Fragment, você deve usar simplesmente requestPermissions" - obrigado!
Tigran Sarkisian

5
@AnthonyBobenrieth, então, qual é a solução aqui para atividades sem história? Simplesmente não podemos solicitar permissões deles?
Dean selvagem

2
O link está quebrado @AnthonyBobenrieth. Existe alguma solução para nenhum histórico?
22816 fersarr # 02:

3
Ao usar Fragment.requestPermissions(), a Atividade pai realmente está recebendo o onRequestPermissionsResult(). (Isso é com a biblioteca de suporte 23.3.0)
Alguém em algum lugar

101

Você pode tentar isso:

requestPermissions(permissions, PERMISSIONS_CODE);

Se você está chamando esse código de um fragmento, ele possui seu próprio método requestPermissions. Acredito que o problema é que você está chamando método estático.

Dica profissional, se você quiser o onRequestPermissionsResult()fragmento: FragmentCompat.requestPermissions(Fragment fragment, String[] permissions, int requestCode)


Obrigado pela ajuda. Percebi que existe um método requestPermissions se estiver em um fragmento. Estou em um fragmento e tentei chamar apenas requestPermissions, infelizmente não funcionou. Eu também tentei o que você mencionou e também não funcionou.
precisa saber é o seguinte

Isso funcionou para mim no Android M. Mas só me pergunto se isso causaria problemas nos dispositivos Pre-M?
Bala Vishnu

4
@goodgamerguy certifique-se de não usar o código de solicitação no onRequestPermissionsResult of activity. se sua atividade também usa o retorno de chamada onRequestPermissionsResult, você deve fornecer o padrão: super.onRequestPermissionsResult (requestCode, permissões, grantResults);
Timmy Simons

68

Espero que funcione bem

Para atividade:

 ActivityCompat.requestPermissions(this,permissionsList,REQUEST_CODE);

Para Fragmento:

 requestPermissions(permissionsList,REQUEST_CODE);

E o SDK 15 e inferior?
Zulkarnain shah

4
Você não precisa de permissão sobre SDK 15, apenas a Marshmallow e necessidade versão acima ..
Sanjay Mangaroliya

50

Eu também encontrei esse problema. Se você deseja que a atividade que lida com permissões não esteja no histórico / recentes, será tentada a alterar sua AndroidManifest.xmlentrada.

Se você definir a atividade que você chama requestPermissionsou AppCompatActivity.requestPermissionscom

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

no seu AndroidManifest.xmlentão onRequestPermissionsResult()não será chamado. Isso é verdade se sua atividade é derivada de Activityou AppCompatActivity.

Isso pode ser corrigido removendo os dois sinalizadores de 'AndroidManifest.xml' e finalizando sua atividade finishAndRemoveTask().


Preferia não ter que remover o atributo noHistory, mas essa foi a solução que funcionou para mim. Obrigado!
Eric Schlenz

1
Eu tive o problema no Marshmallow mas não em Nougat, obrigado funcionou para mim
Yohan Dahmani

37

Se você possui onRequestPermissionsResultatividade e fragmento, lembre-se de chamar a super.onRequestPermissionsResultatividade. Não é necessário no fragmento, mas está em atividade.


Além disso, observe que, se você direcionar uma API (como 19 por exemplo), ainda estará no antigo sistema de modelo de permissão e, portanto, não receberá as chamadas de função relacionadas à permissão de solicitação.
Bonatti

veja a minha resposta se estenderam outra atividade que não chama de super
TouchBoarder

3
Tropeçou em um presente. FragmentActivity.onRequestPermissionsResult(..)é para onde a chamada para o fragmento onRequestPermissionsResult(..)é encaminhada.
JanPl

@ Bonatti Então, se eu tentar solicitar uma permissão no Android 4.4.2, não obterá um resultado? Portanto, não posso alterar as permissões, apenas vê-las?
Alex Fragotsis 27/03

@AlexanderFragotsis Você obterá um resultado. A única diferença é que você não precisará conceder permissão; em vez disso, você será automaticamente concedido pelo sistema.
Dusan Zivkovic

33

Resposta descontinuada, consulte: https://developer.android.com/training/permissions/requesting

Fragmento interno, você precisa chamar:

FragmentCompat.requestPermissions(permissionsList, RequestCode)

Não:

ActivityCompat.requestPermissions(Activity, permissionsList, RequestCode);

2
Relaciona-se com android.support.v13.app.FragmentCompat
Udi Oshi,

1
FragmentCompat foi descontinuado a partir da API 27.1.0.
Big McLargeHuge

minha resposta foi descontinuada, consulte: developer.android.com/training/permissions/requesting
Ben.Slama

15

Se você estiver usando requestPermissions no fragmento, ele aceitará 2 parâmetros em vez de 3.

Você deveria usar requestPermissions(permissions, PERMISSIONS_CODE);


1
Na verdade, ele fornece uma resposta para a pergunta. Chamando requestPermissions (método da instância de fragmento) em vez de ActivityCompat.requestPermissions, o método do resultado é acionado. Qual é o principal problema aqui. Obrigado Don
Waclock 06/06/16

15

Se, por algum motivo, você estendeu uma Atividade personalizada localizada em alguma biblioteca externa que não chama o super, precisará chamar manualmente o Fragmento super.onRequestPermissionsResult na sua Atividade 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

Você tem a função checkPermissions para dispositivos anteriores ao Marshmallow no FragmentCompat . Eu uso assim:

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

2
Isso funcionará apenas se a permissão for solicitada no android.app.fragment e você precisará importar a biblioteca support-v13!
MohammadReza

4
FragmentCompat.requestPermissions () não funciona com android.support.v4.app.Fragment. Alguém sabe como lidar com isso.
Jutikorn

12

Eu descobri que é importante onde você chama android.support.v4.app.Fragment.requestPermissions .

Se você fizer isso onCreate(),onRequestPermissionsResult() nunca será chamado.

Solução: Ligue 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
Estou enfrentando o mesmo problema, mas não consigo entrar onActivityCreated()no meu código. SDK 23.
kAmol 23/02


Eu não estou no fragmento, eu estou tentando fazê-lo em onCreate de uma atividade
Kamol

Hmm, ou usar onPause()?
Almisoft

10

Esse problema estava realmente sendo causado por NestedFragments. Basicamente, na maioria dos fragmentos, estendemos um HostedFragment que, por sua vez, estende um CompatFragment. A presença desses fragmentos aninhados causou problemas que foram resolvidos por outro desenvolvedor no projeto.

Ele estava fazendo algumas coisas de baixo nível, como troca de bits, para que isso funcionasse, então não tenho certeza da solução final real


Isso me ajudou a resolver meu problema: tive que redirecionar o onRequestPermissionsResult do fragmento pai para o fragmento filho (aninhado). Obrigado pela dica!
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

Isso vai funcionar ..

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

o super implementação chama a implementação fragmentos não framework hte
Mohammad Yahia

5

Se você está chamando esse código de um fragmento, ele possui seu próprio método requestPermissions.

O conceito básico é que, se você estiver em uma atividade, chame

ActivityCompat.requestPermissions(this,
                            permissionsList,
                            permissionscode);

e se em um fragmento, basta ligar

requestPermissions(permissionsList,
                            permissionscode);

1
Requer API nível 23 ... Nos mais antigos, use FragmentCompat.requestPermissions().
Minas Mina

5

Eu tive um problema semelhante, exceto que estava pressionando um botão para fazer uma chamada, o que aciona o callIntent. Verifiquei a permissão primeiro, se não for concedida, peço permissão e onRequestPermissionResult chamo a permissão de verificação e ligo novamente.

 @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

Antes de verificar tudo de acordo com as respostas acima, verifique se o seu código de solicitação não é 0 !!!

verifique o código de onRequestPermissionsResult () em 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

Eu tenho uma solução incrível para conseguir isso, faça uma BaseActivity como esta.

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

}

Agora você pode chamar o código para pedir permissão como esta

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

Agora, toda vez que isso acontece em qualquer lugar, seja no seu fragmento ou em qualquer atividade, a atividade base seria chamada.

obrigado


1

Você pode usar requestPermissions(PERMISSIONS, MULTIPLE_PERMISSIONS_CODE);. Não use FragmentCompat se você estiver usando a v4.


Por favor, explique o porquê.
Placeable

1

Detalhes

  • Kotlin 1.2.70
  • verificado minSdkVersion 19
  • Android studio 3.1.4

Algoritmo

módulo - câmera, localização, ....

  1. Verifique se hasSystemFeature (se o módulo existir no telefone)
  2. Verifique se o usuário tem acesso ao módulo
  3. Enviar solicitação de permissão (peça ao usuário para permitir o uso do módulo )

Recursos

  1. Trabalhar com atividades e fragmentos
  2. Tem apenas uma resposta de resultado
  3. Pode verificar vários módulos em uma solicitação

Solução

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()
        }
    }
}

Uso em atividade (no mesmo fragmento)

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

Aqui eu quero mostrar meu código como eu gerenciei isso.

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

Aqui nesta classe, quero verificar a permissão concedida ou não. Não é, então irei chamar a permissão da minha MainActivity como

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

Agora, no método onCreate, você precisa chamar a função requestForPermission ().

Além disso, você também pode solicitar várias permissões de cada vez.


1

UPDATE: vi a resposta de outra pessoa sobre chamar super.onRequestPermissionResult()Activity e isso corrige o problema do código de solicitação que mencionei e chama o onRequestPermissionResult do fragmento.

ignore essas coisas:

Para mim, estava chamando o onRequestPermissionResultde Activity, apesar de eu ter chamadofragment.requestPermission(...) , mas retornou o resultado com um requestCode incorreto (111 se transformou em 65647 por que ??? eu nunca vou saber).

Felizmente, esta é a única permissão que solicitamos nessa tela, então eu simplesmente ignoro o código de solicitação (não tenha tempo para descobrir por que não está correto no momento)


Adicione 65536 e 111 e você o receberá. Isso ocorre por causa de máscaras de bits. Veja alguns tópicos.
CoolMind

0

Também encontrei um problema que, mesmo se você chamar requestPermissions, ainda poderá ter esse problema. O problema é que a atividade pai pode substituir esse método sem chamar super. Adicione super e será corrigido.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.