在获得许可并在 Kotlin 中打开蓝牙之前如何设置应用程序

How to set up the application until permission is granted and bluetooth is turned on in Kotlin

我正在尝试编写一个程序通过蓝牙与 ESP32 模块通信。要使程序运行,必须打开 Bt 并授予 FINE_LOCATION 权限。我正在使用 API 29.

下面的代码有效,但还可以做得更好。

我是初学者,只能这样了

我有几个问题:

我可以将 shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)ActivityResultContracts.RequestPermission() 一起使用吗?如果可以,如何使用?

如果用户第一次拒绝就达到我的目的 授予权限,我 运行 一个几乎相同的合同,但 dialog.How 可以减少此代码吗?

如何简化这个常量检查:

if (conditions.isReady()) {
    buildInterfaceOk()
} else buildInterfaceError()

我的一半代码似乎是多余的,我不知道如何摆脱它。

所有这些问题实际上都涉及第一个运行,然后一切都很好。

代码:

const val TAG = "DEBUG"

data class Conditions (var isBtEnabled : Boolean , var permissionsOk :Boolean){
fun isReady():Boolean{
    if (isBtEnabled && permissionsOk) return true
    else return false
}
fun log(){
    Log.d("DEBUG","Conditions-> $isBtEnabled , $permissionsOk")
}}

class MainActivity : AppCompatActivity() {

    private lateinit var bind: ActivityMainBinding
    private lateinit var broadcastReceiver: BroadcastReceiver
    private lateinit var bluetoothAdapter: BluetoothAdapter
    private var conditions = Conditions(false, false)
    private var requestBluetoothEnable =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            Log.d(TAG, "IT RESULT CODE: ${it.resultCode.toString()}")
            //kiedy bt jest wlaczone , result -1 , kiedy wylaczone i wlaczamy i akceptujemy tez -1
            //a jak odrzucamy to 0
            if (it.resultCode == -1) {
                conditions.log()
                conditions.isBtEnabled = true
            }
            if (conditions.isReady()) {
                buildInterfaceOk()
            } else buildInterfaceError()
        }

    //use it when user denied first time
    private val requestPermissionLocationSecond =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
            if (granted) {
                Log.d(TAG, "Permission granted by contract 2")
                conditions.permissionsOk = checkPermissions()
                if (conditions.isReady()) {
                    buildInterfaceOk()
                } else buildInterfaceError()
            } else {
                val builder = AlertDialog.Builder(this@MainActivity)
                builder.setTitle("V2 - Hi!")
                builder.setMessage(
                    " Please go to the app settings and manually turn on " +
                            "\"location permission\". Without this permission, I do not work. "
                )
                builder.setPositiveButton("Ok") { dialog, which -> }
                val dialog: AlertDialog = builder.create()
                dialog.show()
                Log.d(TAG, " V2-> Permission denied, - contract 2")
            }
        }

    // first try to get permission
    private var requestPermissionLocation =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
            if (granted) {
                Log.d(TAG, "Permission granted by contract 1")
                conditions.permissionsOk = checkPermissions()
                if (conditions.isReady()) {
                    buildInterfaceOk()
                } else buildInterfaceError()
                //shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
            } else {
                Log.d(TAG, "Permission denied by contract 1")
                val builder = AlertDialog.Builder(this@MainActivity)
                builder.setTitle("V2 - Uprawnienie do lokalizacji")
                builder.setMessage("I need these permissions to work with Bt devices ")
                builder.setPositiveButton("YES") { dialog, which ->
                    requestPermissionLocationSecond.launch(android.Manifest.permission.ACCESS_FINE_LOCATION)
                }
                builder.setNegativeButton("No") { dialog, which -> }
                val dialog: AlertDialog = builder.create()
                dialog.show()
                conditions.permissionsOk = checkPermissions()
                if (conditions.isReady()) {
                    buildInterfaceOk()
                } else buildInterfaceError()
            }
        }


    override fun onCreate(savedInstanceState: Bundle?) {
        bind = ActivityMainBinding.inflate(layoutInflater)

        super.onCreate(savedInstanceState)
        setContentView(bind.root)
        Log.d(TAG, "BUild version : ${Build.VERSION.SDK_INT} -> ${Build.VERSION.CODENAME}")
        val currentDebug = getString(R.string.app_name)
        Log.d(TAG, "CURRENT DEBUG : $currentDebug")
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()

        requestBluetoothEnable.launch(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE))
        requestPermissionLocation.launch(Manifest.permission.ACCESS_FINE_LOCATION)

        conditions.isBtEnabled = bluetoothAdapter.isEnabled
        conditions.permissionsOk = checkPermissions()

        Log.d(TAG, "FIRST conditions check :")
        if (conditions.isReady()) {
            conditions.log()
            buildInterfaceOk()
        }
    }

    private fun buildInterfaceOk() {
        Log.d(TAG, "BUILDING INTERFACE : all is fine")
        bind.tvInfo.text = "All is fine i can build interface"
    }

    private fun buildInterfaceError() {
        Log.d(TAG, "BUILDING INTERFACE : errors")
        bind.tvInfo.text = "Some errors..."
    }

    private fun checkPermissions(): Boolean {
        val permissionsRequired =
            arrayOf(
                Manifest.permission.BLUETOOTH,
                Manifest.permission.BLUETOOTH_ADMIN,
                //Manifest.permission.BLUETOOTH_CONNECT, //to znow wymagane od S(API 31) ??
                //Manifest.permission.BLUETOOTH_SCAN, //to znow wymagane od  S(API 31) ??
                Manifest.permission.ACCESS_FINE_LOCATION
                //Manifest.permission.ACCESS_BACKGROUND_LOCATION
            )
        var permissionsOk = true

        permissionsRequired.forEach { requiredPermission ->
            if (ContextCompat.checkSelfPermission(
                    this.applicationContext,
                    requiredPermission
                ) == PackageManager.PERMISSION_GRANTED
            ) {
                Log.d(TAG, "PERMISSION : $requiredPermission -> GRANTED")
            } else {
                Log.d(TAG, "PERMISSION : $requiredPermission -> NOT GRANTED")
                permissionsOk = false

            }
        }
        return permissionsOk
    }
}

我会做的是显示 AlertDialog 首先说,你必须接受所有权限,然后 Request Permissions 直到用户同意所有权限。

Check Permission -> Pass -> Start App

Check Permission -> Fail -> Alert Dialog "You must accept all permissions for the app to start."

Request Permission -> Check Permission -> Pass -> Start App

Request Permission -> Check Permission -> Fail -> Request Permission

Request Permission -> Check Permission -> Fail & Never ask again -> 
Alert Dialog "Go to setting to turn on permissions" -> onPositive "OK" -> Request Permission

唯一的问题是用户可以选择“不再询问”,这意味着您不能再请求权限。

幸运的是,您可以判断用户是否选择了“不再询问”,这应该可以帮助您入门

这种方式将鼓励代码重用,因为在用户接受权限之前,您实际上是在循环执行相同的操作。跳出循环的唯一方法是全面授予权限。