现在大部分手机都有蓝牙功用,能够与其他有蓝牙功用的设备衔接、传输数据等。本文介绍怎么运用蓝牙框架API扫描和配对邻近的设备。
官方文档
恳求权限
假如要在App中运用蓝牙功用,需求恳求多个权限,详细如下:
targetSdk 31(Android 12)及以上
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!--答应App衔接到配对的蓝牙设备(兼容低版别)-->
<uses-permission
android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<!--答应App发现和配对蓝牙设备(兼容低版别)-->
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<!--若App需求扫描蓝牙设备,恳求此权限-->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!--若App使当时设备可供其他蓝牙设备发现,恳求此权限-->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<!--若App与蓝牙设备配对、通讯,恳求此权限-->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!--若App经过蓝牙扫描成果获取物理方位,恳求此权限-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
承认不会运用蓝牙扫描成果获取物理方位时,设置BLUETOOTH_SCAN
权限的usesPermissionFlags
,就无需再恳求ACCESS_FINE_LOCATION
权限。
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!--若App需求扫描蓝牙设备,恳求此权限-->
<!--当usesPermissionFlags设置为neverForLocation时,无需再恳求ACCESS_FINE_LOCATION权限-->
<uses-permission
android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />
</manifest>
需求注意的是,BLUETOOTH_SCAN
、BLUETOOTH_ADVERTISE
、BLUETOOTH_CONNECT
均为运行时权限,需求恳求并取得用户赞同后,才能扫描邻近蓝牙设备、被其他蓝牙设备发现或与其他蓝牙设备配对和通信,代码如下:
class BluetoothExampleActivity : AppCompatActivity() {
private val requestMultiplePermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions: Map<String, Boolean> ->
val noGrantedPermissions = ArrayList<String>()
permissions.entries.forEach {
if (!it.value) {
noGrantedPermissions.add(it.key)
}
}
if (noGrantedPermissions.isEmpty()) {
// 一切恳求权限经过,能够履行后续操作
} else {
//未赞同授权
noGrantedPermissions.forEach {
if (!shouldShowRequestPermissionRationale(it)) {
//用户回绝权限而且体系不再弹出恳求权限的弹窗
//这时需求咱们自己处理,比方自定义弹窗告知用户为何必须要恳求这个权限
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val requestPermissionNames = arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_ADVERTISE, Manifest.permission.BLUETOOTH_CONNECT)
if (requestPermissionNames.find { ActivityCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED } != null) {
requestMultiplePermissionLauncher.launch(requestPermissionNames)
} else {
// 一切恳求权限经过,能够履行后续操作
}
}
}
targetSdk 30(Android 11)及以下
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!--答应App恳求衔接、接受衔接或传输数据-->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!--答应App发现和配对蓝牙设备-->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!--在Android 11(30)及以下版别中,方位权限是必须的-->
<!--在Android 9(28)及以下版别中,能够运用ACCESS_COARSE_LOCATION权限代替ACCESS_FINE_LOCATION权限-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
需求注意的是,方位权限为运行时权限,需求恳求并取得用户赞同后,才能扫描邻近蓝牙设备,代码如下:
class BluetoothExampleActivity : AppCompatActivity() {
private val requestPermissionName = Manifest.permission.ACCESS_FINE_LOCATION
private val requestSinglePermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted: Boolean ->
if (granted) {
// 恳求权限经过,能够履行后续操作
} else {
if (!shouldShowRequestPermissionRationale(requestPermissionName)) {
//用户回绝权限而且体系不再弹出恳求权限的弹窗
//这时需求咱们自己处理,比方自定义弹窗告知用户为何必须要恳求这个权限
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (ActivityCompat.checkSelfPermission(this, requestPermissionName) == PackageManager.PERMISSION_GRANTED) {
// 恳求权限经过,能够履行后续操作
} else {
requestSinglePermissionLauncher.launch(requestPermissionName)
}
}
}
检查与敞开蓝牙
检查是否支撑蓝牙功用
要运用蓝牙功用,首要需求承认当时设备是否支撑蓝牙功用,代码如下:
class BluetoothExampleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val bluetoothAdapter = (getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
if (bluetoothAdapter != null) {
// 当时设备支撑蓝牙功用
}
}
}
敞开蓝牙
承认当时设备支撑蓝牙功用后,检测蓝牙是否敞开,未敞开的话能够调用体系办法敞开蓝牙,代码如下:
class BluetoothExampleActivity : AppCompatActivity() {
private val intentLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
// 成功敞开蓝牙
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val bluetoothAdapter = (getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
if (bluetoothAdapter != null) {
if (bluetoothAdapter.isEnabled != true) {
// 蓝牙未敞开,经过体系启用蓝牙
intentLauncher.launch(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE))
}
}
}
}
扫描和配对邻近的设备
权限已恳求结束、蓝牙功用敞开后,能够扫描邻近的设备,进行配对。
获取已配对过的设备
当时设备可能现已与某些蓝牙设备配对过,获取已配对过的设备的代码如下:
class BluetoothExampleActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val bluetoothAdapter = (getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
// 已绑定的设备
val bondedDevices: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
}
}
扫描邻近设备并进行配对
注册广播接收者,监听扫描成果,运用startDiscovery
扫描邻近其他蓝牙设备。能够运用BluetoothDevice
的createBond
办法进行配对,代码如下:
class BluetoothExampleActivity : AppCompatActivity() {
private val scanResultReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
BluetoothDevice.ACTION_FOUND -> {
// 发现的蓝牙设备
val device: BluetoothDevice? = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
// 假如现已找到想要的设备,能够停止扫描
bluetoothAdapter?.cancelDiscovery()
// 与发现的蓝牙设备配对
device?.createBond()
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 注册蓝牙设备扫描成果监听
registerReceiver(scanResultReceiver, IntentFilter().apply {
addAction(BluetoothDevice.ACTION_FOUND)
})
val bluetoothAdapter = (getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
bluetoothAdapter?.startDiscovery()
}
override fun onDestroy() {
super.onDestroy()
// 撤销扫描成果监听
unregisterReceiver(scanResultReceiver)
}
}
示例
效果如图:
完好演示代码已在示例Demo中增加。
ExampleDemo github
ExampleDemo gitee