【问题标题】:Creating custom ActivityResultContract to ask for location permission创建自定义 ActivityResultContract 以请求位置权限
【发布时间】:2022-10-07 19:57:58
【问题描述】:

我想创建一个自定义 ActivityResultContract 来请求具有自定义响应的粗略和精细位置。

class LocationPermission : ActivityResultContract<Void?, LocationPermissionResult>() {
   override fun createIntent(context: Context, input: Array<String>): Intent {
      val requestPermissions = arrayOf(
         Manifest.permission.ACCESS_FINE_LOCATION,
         Manifest.permission.ACCESS_COARSE_LOCATION
      )

      return Intent(ActivityResultContracts.RequestMultiplePermissions.ACTION_REQUEST_PERMISSIONS)
         .putExtra(ActivityResultContracts.RequestMultiplePermissions.EXTRA_PERMISSIONS, requestPermissions)
   }

   ...
}

从活动中调用它:

private val reportLocationIntent = registerForActivityResult(LocationPermission()) { result ->
}

... reportLocationIntent.launch()

然而,这样做时 createIntent 永远不会被调用。我究竟做错了什么?

【问题讨论】:

  • 我试过你的代码,它可以在我的设备上运行。

标签: android kotlin android-permissions


【解决方案1】:

这是我要求粗略和精细位置的解决方案,我希望这能完成这项工作

object Permission {
    private const val REQUEST_CODE_PERMISSION: Int = 1

    @SuppressLint("ObsoleteSdkInt")
    fun isGrantedLocationPermission(context: Context): Boolean {
        return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            true
        } else {
            context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
                    context.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
        }
    }

    fun grantLocationPermission(context: Context) {
        val permissions = arrayOf(
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION
        )
        (context as MainActivity).requestPermissions(permissions, REQUEST_CODE_PERMISSION)
    }
}

从 MainActivity 使用它:

override fun onCreate(savedInstanceState: Bundle?) {
        ...
        val button = findViewById<Button>(R.id.btnGetLocation)
        button.setOnClickListener {
            getLocation()
        }
    }

private fun getLocation() {
        //check if permission isnt granted:
        if (!Permission.isGrantedLocationPermission(this))
            Permission.grantLocationPermission(this)
        else {
            ...
        }
    }

//Check if user give permission or not:
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //permission granted
        } else {
            //permission denied
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }

【讨论】:

  • 这不是我要求的。我想创建一个具有自定义结果的自定义合同。尝试创建自定义合约时,永远不会调用 createIntent() 函数。
  • 如果您忘记了,请在清单中添加这两行 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Android 11 或更高版本--> <uses-permission android:name="android. permission.ACCESS_COARSE_LOCATION" /> 我尝试使用您的代码并且它有效,我更改了一些内容:class LocationPermission : ActivityResultContract<Unit, Any>(){ ... }
【解决方案2】:

您有问题的代码有编译错误,但是这种方法似乎有效。我真的不知道问题中的“自定义响应”应该是什么,所以我根据您的问题创建了一个名为 class LocationPermissionResult(val granted: Boolean) 的类。它主要是从 ActivityResultContracts 的RequestMultiplePermissions 编译而来的。

在 API 30 和 API 33 模拟器上测试,权限对话框打开并且返回的结果也是正确的。 (确保将权限添加到 AndroidManifest.xml)

这是源代码:

class LocationPermission : ActivityResultContract<Void?, LocationPermissionResult>() {

    private val permissions = arrayOf(
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.ACCESS_COARSE_LOCATION
    )

    override fun createIntent(context: Context, input: Void?): Intent {
        return Intent(ActivityResultContracts.RequestMultiplePermissions.ACTION_REQUEST_PERMISSIONS).putExtra(
            ActivityResultContracts.RequestMultiplePermissions.EXTRA_PERMISSIONS, permissions)
    }

    override fun getSynchronousResult(context: Context,
        input: Void?): SynchronousResult<LocationPermissionResult>? {
        val allGranted = permissions.all { permission ->
            ContextCompat.checkSelfPermission(
                context,
                permission
            ) == PackageManager.PERMISSION_GRANTED
        }
        return if (allGranted) {
            SynchronousResult(LocationPermissionResult(true))
        } else null
    }

    override fun parseResult(resultCode: Int, intent: Intent?): LocationPermissionResult {
        if (resultCode != Activity.RESULT_OK) return LocationPermissionResult(false)
        if (intent == null) return LocationPermissionResult(false)
        val grantResults = intent.getIntArrayExtra(
            ActivityResultContracts.RequestMultiplePermissions.EXTRA_PERMISSION_GRANT_RESULTS)
        return LocationPermissionResult(grantResults?.all { it == PackageManager.PERMISSION_GRANTED } == true)
    }
}

class LocationPermissionResult(val granted: Boolean)

【讨论】:

    【解决方案3】:

    您无需在此处创建自定义合同。您可以使用ActivityResultContracts.RequestMultiplePermissions 合约一次请求多个权限。

    private val requestMultiplePermissions =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
            permissions.forEach { (permission, granted) ->
                // Your logic
            }
        }
    
    
    requestMultiplePermissions.launch(
        arrayOf(
            android.Manifest.permission.ACCESS_FINE_LOCATION,
            android.Manifest.permission.ACCESS_COARSE_LOCATION
        )
    )
    

    【讨论】:

    • 我知道我不需要,但是我在多个地方都有相同的代码。我希望有一个自定义合同,既请求(因为现在需要)并返回自定义响应。您的解决方案涉及在我需要询问位置的任何地方复制相同的代码。自定义合同可以让我避免这种重复,问题是为什么不调用 createIntent() 函数。
    猜你喜欢
    • 1970-01-01
    • 2020-08-03
    • 2020-01-28
    • 2013-01-06
    • 2019-10-09
    • 1970-01-01
    • 2018-12-21
    • 2017-09-13
    相关资源
    最近更新 更多