Android - onRequestPermissionsResult() 已弃用。还有其他选择吗?

问题描述 投票:0回答:10

我尝试实现从存储中写入和读取的请求权限。一切都运行良好,但今天 Android 向我展示了 onRequestPermissionsResult(...) 方法已被弃用。 StackOverflow 中有很多关于这个主题的问题,但不幸的是,它们已经过时了。

我在片段中调用了以下方法。

建议只需致电:

requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
StorageKeys.STORAGE_PERMISSION_CODE)

而不是我的方法:

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

但是它们都表明 onRequestPermissionsResult(...) 已被弃用。

这是我的 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();
      }
    }
  }

这是一个简单的警报对话框,我在其中调用 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();
  }

我可以使用 onRequestPermissionsResult(...) 的替代方案吗?

java android permissions request deprecated
10个回答
110
投票

onRequestPermissionsResult()
方法在
androidx.fragment.app.Fragment
中已弃用。

所以你可以使用

registerForActivityResult()
方法而不是
onRequestPermissionsResult()

您可以参考这个网址

以下是Kotlin代码,大家可以参考一下:

val requestPermissionLauncher = registerForActivityResult(
    ActivityResultContracts.RequestPermission()
) { isGranted ->
    if (isGranted) {
        // PERMISSION GRANTED
    } else {
        // PERMISSION NOT GRANTED
    }
}

// Ex. Launching ACCESS_FINE_LOCATION permission.
private fun startLocationPermissionRequest() {
    requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}

我从以下 URL 添加了 java 代码。
如何在新的ActivityResult API(1.3.0-alpha05)中获取权限请求?

private ActivityResultLauncher<String> requestPermissionLauncher = registerForActivityResult(
    new ActivityResultContracts.RequestPermission(),
    new ActivityResultCallback<Boolean>() {
        @Override
        public void onActivityResult(Boolean result) {
            if (result) {
                // PERMISSION GRANTED
            } else {
                // PERMISSION NOT GRANTED
            }
        }
    }
);

// Ex. Launch the permission window -- this is in onCreateView()
floatingActionButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION);    
    }
});

您还可以请求多个权限:

val requestMultiplePermissions = registerForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->

    // To log permissions:
    permissions.entries.forEach {
        Log.d("DEBUG", "${it.key} = ${it.value}")
    }

    // To check for permissions:
    val a: Boolean = permissions[Manifest.permission.READ_CONTACTS] as Boolean
    val b: Boolean = permissions[Manifest.permission.ACCESS_FINE_LOCATION] as Boolean
    if (a && b) {
        Log.d("LOG_TAG", "Has permissions: READ_CONTACTS, ACCESS_FINE_LOCATION.")
    }
}

requestMultiplePermissions.launch(
    arrayOf(
        Manifest.permission.READ_CONTACTS,
        Manifest.permission.ACCESS_FINE_LOCATION
    )
)

40
投票

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

9
投票
替代registerForActivityResult

使用示例:

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

4
投票
在您的 Activity 或 Fragment 中注册权限回调。处理用户权限 示例-存储权限

private final ActivityResultLauncher<String> requestPermissionLauncher = registerForActivityResult( new ActivityResultContracts.RequestPermission(), result -> { if (result) { //Permission granted } else { //permission denied if (ActivityCompat.shouldShowRequestPermissionRationale(activity, WRITE_EXTERNAL_STORAGE)) { //show permission snackbar } else { //display error dialog } } });
请求权限。注册的ActivityResultCallback获取本次请求的结果。

if (checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PermissionChecker.PERMISSION_GRANTED) { requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE); } else { //Permission already granted }
    

4
投票
假设我们需要获取一些权限,例如音频和摄像头。然后我们可以将它放在数组变量中。

private val REQUESTED_PERMISSIONS = arrayOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA)
当我们使用多个权限数组启动时,此 

registerForActivityResult

 会调用。

private val requestMultiplePermissions = registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions() ) { permissions -> permissions.entries.forEach { Log.d("DEBUG", "${it.key} = ${it.value}") if (!it.value){ return@registerForActivityResult } } init() }
现在我们创建一个函数来检查是否已授予权限。

private fun checkSelfPermission(): Boolean { return !(ContextCompat.checkSelfPermission( requireContext(), REQUESTED_PERMISSIONS[0] ) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission( requireContext(), REQUESTED_PERMISSIONS[1] ) != PackageManager.PERMISSION_GRANTED) }
现在我们通过 

onCreate

 方法检查是否授予权限。如果未授予权限,则我们调用 
requestMultiplePermissions.launch(REQUESTED_PERMISSIONS)
 like

super.onCreate(savedInstanceState) if (!checkSelfPermission()) { requestMultiplePermissions.launch(REQUESTED_PERMISSIONS) } }
    

1
投票
这对我有用 - (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") } }
    

1
投票
大多数答案都满足了 OP 要求。但我发现缺少一些东西,所以我想提供一个完整的例子(在 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() } } } }
缺少的东西是

A)Fragment 在创建之前必须调用 registerForActivityResult()(即初始化、onAttach() 或 onCreate())。否则它将无法工作并且应用程序会崩溃。

错误:

java.lang.IllegalStateException:片段ProfileFragment {bf12414}(210ad5a1-3286-4586-a48f-deac1d8e3eef id=0x7f09008b) 正在尝试注册ForActivityResult 后 创建的。片段必须在调用之前调用 registerForActivityResult() 被创建(即初始化、onAttach() 或 onCreate())。

B) 建议在确实需要时请求许可。 在我的示例中,当用户单击 id 为

Button

locBtn
 时,将显示权限对话框,而不是显示创建活动/片段的时间。


1
投票
请参考官方文档:

https://developer.android.com/training/permissions/requesting

查看以下内容,可以在文档中找到。

// 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. } }
之后,发起请求

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

0
投票
您可以使用一些外部库进行权限处理,以减少一些样板代码。我使用

Dexter 库。如果您使用 RxJava2,Rx Permissions 也是不错的选择。


-2
投票
在 pubspec.yamal 的 flutter 部分尝试一下:

plugin: androidPackage: com.ly.permission pluginClass: PermissionPlugin
它对我有用。

© www.soinside.com 2019 - 2024. All rights reserved.