java - studio - Permisos de Android M: no se llama a onRequestPermissionsResult()
requestpermissions android example (23)
Estoy actualizando nuestra aplicación para usar el nuevo sistema de permisos M. Todo funciona además de onRequestPermissionsResult (). Necesito verificar un permiso al presionar un botón y, si tiene éxito, enviar un mensaje de texto. Cuando otorgo permiso para hacerlo, el cuadro de diálogo se cierra, pero no activa el envío de texto hasta que vuelva a presionar el botón.
He depurado y establecido puntos de interrupción en el método onRequestPermissionsResult () pero nunca entra en él.
Este método se llama primero:
private void askForPermission() {
String[] permissions = new String[]{Manifest.permission.SEND_SMS};
ActivityCompat.requestPermissions(getActivity(), permissions, PERMISSIONS_CODE);
}
Y luego mi devolución de llamada se ve así:
@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);
}
}
}
}
}
¿Alguien ha tenido un problema similar? Agradezco cualquier ayuda con esto. Gracias
Detalles
- Kotlin 1.2.70
- verificado en minSdkVersion 19
- Android studio 3.1.4
Algoritmo
módulo - cámara, ubicación, ....
- Compruebe si hasSystemFeature (si existe un módulo en el teléfono)
- Compruebe si el usuario tiene acceso al módulo
- Enviar solicitud de permisos (pedir al usuario que permita el uso del módulo )
Caracteristicas
- Trabajar con actividades y fragmentos
- Tiene solo una respuesta de resultado
- Puede verificar varios módulos en una sola solicitud
Solución
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 en actividad (en fragmento igual)
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 -> {
// }
// }
}
}
}
¡Antes de verificar todo de acuerdo con las respuestas anteriores, asegúrese de que su código de solicitud no sea 0!
verifique el código de onRequestPermissionsResult () en 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);
}
}
}
Aquí quiero mostrar mi código cómo logré esto.
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;
}
}
Aquí en esta clase quiero verificar el permiso otorgado o no. Es entonces cuando llamaré al permiso de mi 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;
}
}
}
}
Ahora, en el método onCreate, debe llamar a la función requestForPermission ().
Eso es todo, también puedes solicitar permisos múltiples a la vez.
Dentro del fragmento, debe llamar:
FragmentCompat.requestPermissions(permissionsList, RequestCode)
No:
ActivityCompat.requestPermissions(Activity, permissionsList, RequestCode);
Descubrí que es importante cuando llamas a
android.support.v4.app.Fragment.requestPermissions
.
Si lo hace en
onCreate()
, nunca se llama a
onRequestPermissionsResult()
.
Solución:
onActivityCreated()
en
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);
}
Encontré este problema también.
Si desea la actividad que maneja los permisos que no están en el historial / recientes, entonces tendrá la tentación de cambiar su entrada
AndroidManifest.xml
.
Si configura la actividad a la que llama
requestPermissions
o
AppCompatActivity.requestPermissions
con
android:noHistory="true"
android:excludeFromRecents="true"
en su
AndroidManifest.xml
entonces no se llamará a
onRequestPermissionsResult()
.
Esto es cierto si su Actividad se deriva de
Activity
o
AppCompatActivity
.
Esto se puede solucionar eliminando ambos indicadores de ''AndroidManifest.xml'' y finalizando su actividad con
finishAndRemoveTask()
lugar.
Espero que funcione bien
Para la actividad:
ActivityCompat.requestPermissions(this,permissionsList,REQUEST_CODE);
Para el fragmento:
requestPermissions(permissionsList,REQUEST_CODE);
Este problema fue causado realmente por NestedFragments. Básicamente, en la mayoría de los fragmentos hemos extendido un HostedFragment que a su vez extiende un CompatFragment. Tener estos fragmentos anidados causó problemas que finalmente fueron resueltos por otro desarrollador en el proyecto.
Estaba haciendo algunas cosas de bajo nivel, como el cambio de bits para que esto funcione, así que no estoy muy seguro de la solución final real
Esto funcionará ...
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
Me encontré con el mismo problema y acabo de encontrar la solución. Al usar la biblioteca de soporte, debe usar las llamadas de método correctas. Por ejemplo:
- Cuando esté en AppCompatActivity , debe usar ActivityCompat.requestPermissions ;
- Cuando esté en android.support.v4.app.Fragment , debe usar simplemente requestPermissions (este es un método de instancia de android.support.v4.app.Fragment)
Si llama a ActivityCompat.requestPermissions en un fragmento, la devolución de llamada onRequestPermissionsResult se llama a la actividad y no al fragmento.
¡Espero que esto ayude!
Puede usar
requestPermissions(PERMISSIONS, MULTIPLE_PERMISSIONS_CODE);
.
No use FragmentCompat si está usando v4.
Puedes probar esto:
requestPermissions(permissions, PERMISSIONS_CODE);
Si está llamando a este código desde un fragmento, tiene su propio método requestPermissions. Creo que el problema es que estás llamando al método estático.
Consejo profesional si desea
onRequestPermissionsResult()
en un fragmento:
FragmentCompat.requestPermissions(Fragment fragment, String[] permissions, int requestCode)
Según la respuesta de goodgamerguy, la solución es:
myFragment.this.requestPermissions(....)
Si está llamando a este código desde un fragmento, tiene su propio método requestPermissions.
Entonces, el concepto básico es: si está en una actividad, llame al
ActivityCompat.requestPermissions(this,
permissionsList,
permissionscode);
y si está en un fragmento, solo llame
requestPermissions(permissionsList,
permissionscode);
Si está utilizando requestPermissions en fragmentos, acepta 2 parámetros en lugar de 3.
Debe usar
requestPermissions(permissions, PERMISSIONS_CODE);
Si por alguna razón ha extendido una actividad personalizada ubicada en alguna biblioteca externa que no llama al super, deberá llamar manualmente al Fragment super.onRequestPermissionsResult usted mismo en su Activity 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);
}
...
Si tiene
onRequestPermissionsResult
tanto en actividad como en fragmento, asegúrese de llamar a
super.onRequestPermissionsResult
en actividad.
No se requiere en fragmentos, pero está en actividad.
Tengo una solución increíble para lograr esto, hacer una 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();
}
}
}
}
}
Ahora puedes llamar al código para pedir permiso como este
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
Ahora, cada vez que esto sucede en cualquier parte, ya sea en su fragmento o en cualquier actividad, se llamaría la actividad base.
Gracias
Tiene la función checkPermissions para dispositivos pre Marshmallow en FragmentCompat . Yo uso así:
FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
Tuve un problema similar, excepto que estaba presionando un botón para hacer una llamada, lo que activa el callIntent. Primero verifiqué el permiso, si no me lo conceden, solicito permiso y en RequestPermissionResult llamo al permiso de verificación y llamo nuevamente.
@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();
}
}
}
ACTUALIZACIÓN:
vi la respuesta de otra persona sobre llamar a
super.onRequestPermissionResult()
en Activity y eso soluciona el problema del código de solicitud que mencioné y llama al
fragmento onRequestPermissionResult.
ignora estas cosas:
Para mí, estaba llamando a
onRequestPermissionResult
of the Activity a pesar de que llamaba a
fragment.requestPermission(...)
, PERO devolvió el resultado con un código de solicitud incorrecto (111 convertido en 65647 ¿por qué? Nunca lo sabré).
Afortunadamente, este es el único permiso que solicitamos en esa pantalla, así que simplemente ignoro el código de solicitud (no tengo tiempo para descubrir por qué no es correcto en este momento)
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();
}
}
/* 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);