Traté de implementar permisos de solicitud para escribir y leer desde el almacenamiento. Todo funcionó bien, pero hoy Android me mostró que el método onRequestPermissionsResult(...) está en desuso. Hay tantas preguntas sobre este tema en StackOverflow, pero desafortunadamente están desactualizadas.
Llamé a los métodos a continuación en un fragmento.
Se sugirió simplemente llamar a:
requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, StorageKeys.STORAGE_PERMISSION_CODE)en lugar de mi enfoque:
ActivityCompat.requestPermissions(getActivity(), new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, StorageKeys.STORAGE_PERMISSION_CODE))Pero ambos muestran que onRequestPermissionsResult(...) está en desuso.
Aquí está mi método onRequestPermissionsResult(...):
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == StorageKeys.STORAGE_PERMISSION_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { exportBibTex.createBibFile(); exportBibTex.writeBibFile(exportBibTex .getBibDataLibrary(libraryModel, bookDao, noteDao)); Toast.makeText(getContext(), getString(R.string.exported_file_stored_in) + '\n' + File.separator + StorageKeys.DOWNLOAD_FOLDER + File.separator + fileName + StorageKeys.BIB_FILE_TYPE, Toast.LENGTH_LONG).show(); } else { Toast.makeText(getContext(), R.string.storage_permission_denied, Toast.LENGTH_SHORT).show(); } } }Aquí hay un cuadro de diálogo de alerta simple, en el que llamo onRequestPermissionsResult (...):
private void showRequestPermissionDialog() { AlertDialog.Builder reqAlertDialog = new AlertDialog.Builder(getContext()); reqAlertDialog.setTitle(R.string.storage_permission_needed); reqAlertDialog.setMessage(R.string.storage_permission_alert_msg); reqAlertDialog.setPositiveButton(R.string.ok, (dialog, which) -> ActivityCompat.requestPermissions(getActivity(), new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, StorageKeys.STORAGE_PERMISSION_CODE)); reqAlertDialog.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); reqAlertDialog.create().show(); }¿Hay alguna alternativa para onRequestPermissionsResult(...), que pueda usar?
El método onRequestPermissionsResult() está obsoleto en androidx.fragment.app.Fragment .
Entonces usa el método registerForActivityResult() en lugar onRequestPermissionsResult() .
Puedes referirte a esta URL .
El siguiente es el código kotlin. pero puedes consultarlo.
val permReqLuncher = registerForActivityResult(ActivityResultContracts.RequestPermission()){ if (it) { // Good pass } else { // Failed pass } } Agregué el código java de la siguiente URL.
¿Cómo obtener una solicitud de permiso en la nueva API de ActivityResult (1.3.0-alpha05)?
private ActivityResultLauncher<String> mPermissionResult = registerForActivityResult( new ActivityResultContracts.RequestPermission(), new ActivityResultCallback<Boolean>() { @Override public void onActivityResult(Boolean result) { if(result) { Log.e(TAG, "onActivityResult: PERMISSION GRANTED"); } else { Log.e(TAG, "onActivityResult: PERMISSION DENIED"); } } }); // Launch the permission window -- this is in onCreateView() floatingActionButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mPermissionResult.launch(Manifest.permission.ACCESS_BACKGROUND_LOCATION); } });Puede solicitar varios permisos.
val requestMultiplePermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> permissions.entries.forEach { Log.e("DEBUG", "${it.key} = ${it.value}") } } requestMultiplePermissions.launch( arrayOf( Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION ) )Puede usar alguna biblioteca externa para el manejo de permisos para reducir algunos códigos repetitivos. Yo uso la biblioteca Dexter . Rx Permissions también es una buena opción si está utilizando RxJava2.
Esto funciona para mí - (kotlin):
private fun checkPermissions() { if (mContext?.let { ContextCompat.checkSelfPermission( it, READ_EXTERNAL_STORAGE ) } != PackageManager.PERMISSION_GRANTED) { Log.d(TAG, "Request Permissions") requestMultiplePermissions.launch( arrayOf(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE)) } else { Log.d(TAG, "Permission Already Granted") } } private val requestMultiplePermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> permissions.entries.forEach { Log.d(TAG, "${it.key} = ${it.value}") } if (permissions[READ_EXTERNAL_STORAGE] == true && permissions[WRITE_EXTERNAL_STORAGE] == true) { Log.d(TAG, "Permission granted") } else { Log.d(TAG, "Permission not granted") } }Una forma sencilla en Kotlin
import android.Manifest import android.content.Context import android.content.pm.PackageManager import android.os.Build import androidx.activity.result.contract.ActivityResultContracts import androidx.core.app.ActivityCompat import androidx.fragment.app.Fragment class MyFragment : Fragment() { companion object { val TAG: String = MyFragment::class.java.simpleName var PERMISSIONS = arrayOf( Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE ) } private val permReqLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> val granted = permissions.entries.all { it.value == true } if (granted) { displayCameraFragment() } } private fun takePhoto() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { displayCameraFragment() } activity?.let { if (hasPermissions(activity as Context, PERMISSIONS)) { displayCameraFragment() } else { permReqLauncher.launch( PERMISSIONS ) } } } // util method private fun hasPermissions(context: Context, permissions: Array<String>): Boolean = permissions.all { ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED } private fun displayCameraFragment() { // open camera fragment } }RegisterForActivityResult alternativo
Ejemplo de uso:
private fun permissionSetup() { val permission = ContextCompat.checkSelfPermission( requireContext(), Manifest.permission.READ_CONTACTS) if (permission != PackageManager.PERMISSION_GRANTED) { permissionsResultCallback.launch(Manifest.permission.READ_CONTACTS) } else { println("Permission isGranted") } } private val permissionsResultCallback = registerForActivityResult( ActivityResultContracts.RequestPermission()){ when (it) { true -> { println("Permission has been granted by user") } false -> { Toast.makeText(requireContext(), "Permission denied", Toast.LENGTH_SHORT).show() dialog.dismiss() } } }La mayoría de las respuestas abordan el requisito de OP. Pero he encontrado algunas cosas que faltan, así que pensé en dar un ejemplo completo (en Koltin)
class ProfileFragment : Fragment(){ private lateinit var permissionRequest : ActivityResultLauncher<Array<String>> companion object { val LOCATION_PERMISSIONS = arrayOf( Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION ) } private fun getGpsLocation() { if(activity != null){ permissionRequest.launch(LOCATION_PERMISSIONS) } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.locBtn.setOnClickListener { getGpsLocation() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) registerPermissionRequest() } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { binding = DataBindingUtil.inflate(inflater, R.layout.fragment_profile, container, false) return binding.root } private fun registerPermissionRequest(){ var permissionCount = 0 permissionRequest = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> permissions.entries.forEach { if(it.value){ permissionCount++ } } if(permissionCount == 2){ getMyLocation() } } } }Las cosas que faltan son
A) Los fragmentos deben llamar a registerForActivityResult() antes de que se creen (es decir, inicialización, onAttach() o onCreate()). De lo contrario, no funcionará y la aplicación se bloqueará.
Error:
java.lang.IllegalStateException: Fragment ProfileFragment{bf12414} (210ad5a1-3286-4586-a48f-deac1d8e3eef id=0x7f09008b) está intentando registrarse paraActivityResult después de ser creado. Los fragmentos deben llamar a registerForActivityResult() antes de que se creen (es decir, inicialización, onAttach() o onCreate()).
B) Se recomienda solicitar permiso cuando realmente se necesite. En mi ejemplo, cuando el usuario hace clic en el Button con id locBtn , se muestra el cuadro de diálogo de permiso en lugar de mostrar cuando se crea la actividad/fragmento.
Consulte la documentación oficial: https://developer.android.com/training/permissions/requesting
Revise lo siguiente, que se puede encontrar en la documentación.
// Register the permissions callback, which handles the user's response to the // system permissions dialog. Save the return value, an instance of // ActivityResultLauncher. You can use either a val, as shown in this snippet, // or a lateinit var in your onAttach() or onCreate() method. val requestPermissionLauncher = registerForActivityResult(RequestPermission() ) { isGranted: Boolean -> if (isGranted) { // Permission is granted. Continue the action or workflow in your // app. } else { // Explain to the user that the feature is unavailable because the // features requires a permission that the user has denied. At the // same time, respect the user's decision. Don't link to system // settings in an effort to convince the user to change their // decision. } }Después de lo cual, inicie la solicitud.
when { ContextCompat.checkSelfPermission( CONTEXT, Manifest.permission.REQUESTED_PERMISSION ) == PackageManager.PERMISSION_GRANTED -> { // You can use the API that requires the permission. } //Is not needed for it to work, but is a good practice as it plays a role //in letting user know why the permission is needed. shouldShowRequestPermissionRationale(...) -> { // In an educational UI, explain to the user why your app requires this // permission for a specific feature to behave as expected. In this UI, // include a "cancel" or "no thanks" button that allows the user to // continue using your app without granting the permission. showInContextUI(...) } else -> { // You can directly ask for the permission. // The registered ActivityResultCallback gets the result of this request. requestPermissionLauncher.launch( Manifest.permission.REQUESTED_PERMISSION) } }