如何使用导航组件管理权限请求代码?

How to Manage the permission request code using Navigation Component?

如何使用导航组件管理权限请求代码?

我引用了太多网站和堆栈 link,其中 none 有效,仍然显示已弃用的 Waring

Google 参考 link: https://developer.android.com/training/permissions/requesting#manage-request-code-yourself

代码::在片段

中使用以下代码
  private fun checkMultiplePermissions() {
        // check permission first
        if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // request the permission
            requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 100)
        } else {
            proceedAfterPermission()  // has the permission.
        }
    }
    override fun onRequestPermissionsResult(requestCode: Int,
                                            permissions: Array<String>, grantResults: IntArray) {
        myLog("log", "location code : $requestCode")
        when (requestCode) {
            100 -> {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission was granted.
                    proceedAfterPermission() // permission was granted.
                    myLog("log", "location granted")
                } else {
                    // permission denied.
                    myLog("log", "location denied")
                }
                return
            }
        }
    }

Fragment.kt : 完整代码

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment

class FragmentPermission : Fragment() {
    private var binding: FragmentPermisionBinding ?= null

    // Kotlin
    //implementation "androidx.fragment:fragment-ktx:1.3.4"

    //https://developer.android.com/training/permissions/requesting#manage-request-code-yourself

    //    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View {
        binding = FragmentPermisionBinding.inflate(inflater, container, false)


        if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // request the permission
            requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 100)
        } else {
            //proceedAfterPermission()  // has the permission.
        }
        
        
        return binding!!.root
    }


    override fun onRequestPermissionsResult(requestCode: Int,
                                            permissions: Array<String>, grantResults: IntArray) {
        myLog("location3", "location code : $requestCode")
        when (requestCode) {
            100 -> {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission was granted.
                    //proceedAfterPermission() // permission was granted.
                    myLog("location3", "location granted")
                } else {
                    // permission denied.
                    myLog("location3", "location denied")
                }
                return
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        binding=null
    }
}
requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 100)

This method is deprecated. use registerForActivityResult(ActivityResultContract, ActivityResultCallback) passing in a ActivityResultContracts.RequestMultiplePermissions object for the ActivityResultContract and handling the result in the callback.

requestPermissions() API is deprecated, and replaced by registerForActivityResult(ActivityResultContract, ActivityResultCallback) 传入一个 ActivityResultContracts.RequestMultiplePermissions 对象 对于 ActivityResultContract 并在回调中处理结果。

首先 activity-ktx build.gradle 新的 API:

需要模块级依赖
implementation 'androidx.activity:activity-ktx:1.3.0-beta01'

然后 ActivityResultCallback 回调需要实现并作为 registerForActivityResult 的参数传递。此接口具有处理用户对权限请求对话框的响应的回调。

要显示权限对话框,请在 registerForActivityResult 函数返回的 ActivityResultLauncher 实例上调用 launch() 方法。

因此,创建 ActivityResultLauncher 的实例并实施回调以处理用户响应:

private val requestPermission =
    registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
        
        if (isGranted) { // Do something if permission granted
            Log.d("LOG_TAG", "permission granted by the user")

        } else { // Do something as the permission is not granted
            Log.d("LOG_TAG", "permission denied by the user")
        }
    }

然后使用launch函数请求权限:

if (ContextCompat.checkSelfPermission(
        requireContext(),
        Manifest.permission.ACCESS_FINE_LOCATION
    ) != PackageManager.PERMISSION_GRANTED
) {
    requestPermission.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}

更新

一次请求多个权限:您需要传递数组 启动()的权限。 ActivityResultCallback returns a Map<String, Boolean> 以权限为键,其授权状态为值:

然后使用ActivityResultContracts.RequestMultiplePermissions()如下:

private val requestMultiplePermissions =
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        permissions.entries.forEach {
            Log.e("LOG_TAG", "${it.key} = ${it.value}")
        }
    }

// Usage:
requestMultiplePermissions.launch(
    arrayOf(
        Manifest.permission.READ_CONTACTS,
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.CAMERA
    )
)

将其应用于共享代码:

class FragmentPermission : Fragment() {
    private var binding: FragmentPermisionBinding ?= null

    //...
    
    private val requestPermission =
    registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
        
        if (isGranted) { // permission is granted

            proceedAfterPermission()
            
        } else { 
            // handle permission denial 
        }
    }


    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View {
        binding = FragmentPermisionBinding.inflate(inflater, container, false)


    if (ContextCompat.checkSelfPermission(
            requireContext(),
            Manifest.permission.ACCESS_FINE_LOCATION
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        requestPermission.launch(Manifest.permission.ACCESS_FINE_LOCATION)
    } else {
        proceedAfterPermission()
    }      
        
        return binding!!.root
    }

//.... rest of your code

}

您缺少为下面的函数传递参数 Activity

 public static void requestPermissions(final @NonNull Activity activity,
            final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode)

如果没有请求权限,请检查您是否已经拥有权限。 在下面的代码中,您需要传递 activity.

            if (ContextCompat.checkSelfPermission(
                    this.applicationContext,
                    Manifest.permission.ACCESS_FINE_LOCATION
                )
                == PackageManager.PERMISSION_GRANTED
            ) {
//already you have permission
            } else {
                ActivityCompat.requestPermissions(
                    this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION
                )
            }

使用这个获取用户响应。

    /**
     * Handles the result of the request for location permissions.
     */
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        mLocationPermissionGranted = false
        when (requestCode) {
            PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION -> {

                // If request is cancelled, the result arrays are empty.
                if (grantResults.size > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED
                ) {
// user granted location call your function
                }
            }
        }
    }

带有 NavContoller 的 PermissionFragment。科特林

class PermissionFragment : Fragment() {
private val PERMISSIONS_REQUIRED = arrayOf(
    Manifest.permission.CAMERA,
    Manifest.permission.NFC,
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.ACCESS_COARSE_LOCATION
)
private var _binding: FragmentPermissionBinding? = null
private val binding get() = _binding!!

private val requestMultiplePermissions =
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        permissions.entries.forEach {
            val granted = it.value
            val permission = it.key
            if (!granted) {

                val neverAskAgain = !ActivityCompat.shouldShowRequestPermissionRationale(
                    requireActivity(),
                    permission
                )
                if (neverAskAgain) {
                    //user click "never ask again"
                } else {
                    //show explain dialog
                }
                return@registerForActivityResult
            }
        }
        goHome()
    }

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = FragmentPermissionBinding.inflate(inflater, container, false)
    return binding.root
}

override fun onViewStateRestored(savedInstanceState: Bundle?) {
    super.onViewStateRestored(savedInstanceState)

    /*don't call this in onCreateView(), NavController has not been created yet
    *
    * don't call this in onResume(), if user selected "never ask again" - checkAppPermission() can go to dead loop after dialog show */
    checkAppPermission()
}

private fun checkAppPermission() {
    PERMISSIONS_REQUIRED.forEach { permission ->
        if (ContextCompat.checkSelfPermission(requireContext(), permission) ==
            PackageManager.PERMISSION_DENIED
        ) {
            requestMultiplePermissions.launch(PERMISSIONS_REQUIRED)
            return
        }
    }
    goHome()
}

private fun goHome() {
    val navController = requireActivity().findNavController(R.id.nav_host_fragment_content_main)
    navController.navigate(R.id.nav_home)
}

}