web-dev-qa-db-fra.com

Android M Permissions: onRequestPermissionsResult () n'étant pas appelé

Je met à jour notre application pour utiliser le nouveau système d'autorisations M. Tout fonctionne en dehors de onRequestPermissionsResult (). J'ai besoin de vérifier une permission sur un bouton, et si c'est réussi, envoyer un message texte. Lorsque j'accorde la permission de le faire, la boîte de dialogue se ferme, mais le texte envoyé ne se déclenche que lorsque j'appuie de nouveau sur le bouton.

J'ai débogué et défini des points d'arrêt dans la méthode onRequestPermissionsResult (), mais elle n'y va jamais.

Cette méthode s'appelle d'abord:

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

Et puis mon rappel ressemble à ceci:

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

Quelqu'un at-il rencontré un problème similaire? Apprécier toute aide avec cela. Merci

268
AndyOHart

Ce problème était en réalité causé par NestedFragments. Fondamentalement, la plupart des fragments que nous avons étend un HostedFragment qui étend à son tour un CompatFragment Ces fragments imbriqués ont provoqué des problèmes qui ont finalement été résolus par un autre développeur du projet.

Il faisait des choses de bas niveau, comme changer de bits pour que cela fonctionne, alors je ne suis pas trop sûr de la solution finale.

10
AndyOHart

J'ai rencontré le même problème et je viens de trouver la solution. Lorsque vous utilisez la bibliothèque de support, vous devez utiliser les appels de méthode corrects. Par exemple:

  • Dans AppCompatActivity, vous devez utiliser ActivityCompat.requestPermissions;
  • Dans Android.support.v4.app.Fragment, vous devez utiliser simplement requestPermissions (il s'agit d'une méthode d'instance de Android.support.v4.app.Fragment)

Si vous appelez ActivityCompat.requestPermissions dans un fragment, le rappel onRequestPermissionsResult est appelé pour l'activité et non pour le fragment.

J'espère que cela t'aides!

556
yavor87

Vous pouvez essayer ceci:

requestPermissions(permissions, PERMISSIONS_CODE);

Si vous appelez ce code depuis un fragment, il a sa propre méthode requestPermissions. Je crois que le problème est que vous appelez la méthode statique.

Conseil professionnel si vous voulez la onRequestPermissionsResult() dans un fragment: FragmentCompat.requestPermissions(Fragment fragment, String[] permissions, int requestCode)

94
Tieru

J'espère que ça fonctionne bien

Pour l'activité:

 ActivityCompat.requestPermissions(this,permissionsList,REQUEST_CODE);

Pour le fragment:

 requestPermissions(permissionsList,REQUEST_CODE);
63
Sanjay Mangaroliya

J'ai rencontré ce problème aussi. Si vous souhaitez que l'activité qui gère les autorisations ne soit pas dans l'historique/récents, vous serez tenté de modifier votre entrée AndroidManifest.xml.

Si vous définissez l'activité que vous appelez requestPermissions ou AppCompatActivity.requestPermissions avec

Android:noHistory="true"
Android:excludeFromRecents="true"

dans votre AndroidManifest.xml alors onRequestPermissionsResult() ne sera pas appelé. Cela est vrai si votre activité est dérivée de Activity ou AppCompatActivity.

Ce problème peut être résolu en supprimant les deux indicateurs de 'AndroidManifest.xml' et en terminant votre activité avec finishAndRemoveTask().

50

Si vous avez onRequestPermissionsResult à la fois dans l'activité et dans le fragment, veillez à appeler super.onRequestPermissionsResult dans l'activité. Ce n'est pas requis en fragment, mais c'est en activité.

36
Dusan Zivkovic

Dans le fragment, vous devez appeler:

FragmentCompat.requestPermissions(permissionsList, RequestCode)

Ne pas:

ActivityCompat.requestPermissions(Activity, permissionsList, RequestCode);
31
Ben.Slama.Jihed

Si vous utilisez requestPermissions en fragment, il accepte 2 paramètres au lieu de 3.

Vous devriez utiliser requestPermissions(permissions, PERMISSIONS_CODE);

15
AkKi

Si, pour une raison quelconque, vous avez étendu une activité personnalisée située dans une bibliothèque externe qui n'appelle pas le super, vous devrez appeler manuellement le fragment super.onRequestPermissionsResultez-vous dans votre activité 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);
    }
...
14
TouchBoarder

Vous avez la fonction checkPermissions pour les périphériques antérieurs à Marshmallow dans FragmentCompat. J'utilise comme ça:

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

J'ai découvert qu'il est important que vous appeliez Android.support.v4.app.Fragment.requestPermissions.

Si vous le faites dans onCreate(), onRequestPermissionsResult() n'est jamais appelé.

Solution: Appelez-le dans 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);

}
12
almisoft
 /* 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);
9
Shahab Rauf

Cela fonctionnera ..

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

Si vous appelez ce code depuis un fragment, il possède sa propre méthode requestPermissions.

Donc, le concept de base est, si vous êtes dans une activité, alors appelez

ActivityCompat.requestPermissions(this,
                            permissionsList,
                            permissionscode);

et si dans un fragment, il suffit d'appeler

requestPermissions(permissionsList,
                            permissionscode);
5

J'ai eu un problème similaire, sauf que j'appuyais sur un bouton pour effectuer un appel, ce qui déclenche l'appelant. J'ai d'abord vérifié l'autorisation, sinon, je demande l'autorisation et onRequestPermissionResult j'appelle l'autorisation de vérification et appelle à nouveau.

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

J'ai une solution étonnante pour y parvenir: créez une BaseActivity comme celle-ci.

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

}

Vous pouvez maintenant appeler le code pour demander une autorisation comme celle-ci.

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

Maintenant, chaque fois que cela se produit, que ce soit dans votre fragment ou dans une activité, l'activité de base est appelée.

Merci

2
Abhishek Dubey

Avant de tout vérifier en fonction des réponses ci-dessus, assurez-vous que votre code de demande n'est pas 0 !!!

vérifiez le code de onRequestPermissionsResult () dans 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
Chandler

Basé sur réponse de goodgamerguy , la solution est la suivante:

myFragment.this.requestPermissions(....)
2
Hamza Elmi
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
user2002721

UPDATE: a vu la réponse de quelqu'un d'autre à propos de l'appel de super.onRequestPermissionResult () dans Activity et corrige le problème de code de requête que j'ai mentionné et appelle le fragment onRequestPermissionResult.

ignorer ce genre de choses:

Pour moi, il appelait onRequestPermissionResult of Activity malgré mon appel à fragment.requestPermission (...), MAIS il a renvoyé le résultat avec un requestCode incorrect (111 transformé en 65647 pourquoi ??? je ne saurai jamais).

Heureusement, c’est la seule permission que nous demandons sur cet écran. J’ignore donc simplement le code de la requête (je n’ai pas le temps de comprendre pourquoi il n’est pas correct actuellement).

1
grgrssll

Détails

  • Kotlin 1.2.70
  • vérifié dans minSdkVersion 19
  • Android studio 3.1.4

Algorithme

module - caméra, emplacement, ....

  1. Vérifiez si hasSystemFeature (si module existe dans le téléphone)
  2. Vérifier si l'utilisateur a accès à module
  3. Envoyer une demande de permission (demander à l'utilisateur de permettre module usage)

Caractéristiques

  1. Travailler avec des activités et des fragments
  2. N'a qu'une réponse de résultat
  3. Peut vérifier plusieurs modules en une requête

Solution

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

Utilisation en activité (dans le même fragment)

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
Vasily Bodnarchuk

Vous pouvez utiliser requestPermissions(PERMISSIONS, MULTIPLE_PERMISSIONS_CODE);. N'utilisez pas FragmentCompat si vous utilisez v4.

1
Remario

Ici, je veux montrer à mon code comment j'ai géré cela.

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

Ici, dans cette classe, je veux vérifier l'autorisation accordée ou non. N’est-ce pas alors que je vais appeler la permission de mon MainActivity comme

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

Maintenant, dans la méthode onCreate, vous devez appeler la fonction requestForPermission ().

C'est ça.Vous pouvez également demander plusieurs autorisations à la fois.

0
pavel