做网站时怎样申请域名,白云高端网站建设案例,网站每个月8g流量,网站首页的文字下拉怎么做一、新建项目
在Android Studio中新建一个项目#xff0c;如下图所示#xff1a;
选择No Activity#xff0c;然后点击Next 点击Finish#xff0c;完成项目创建。
1、配置build.gradle
在android{}闭包中添加viewBinding#xff0c;用于获取控件 buildFeatures {viewB…
一、新建项目
在Android Studio中新建一个项目如下图所示
选择No Activity然后点击Next 点击Finish完成项目创建。
1、配置build.gradle
在android{}闭包中添加viewBinding用于获取控件 buildFeatures {viewBinding true}添加完成后点击同步Sync
2、配置清单文件AndroidManifest.xml
在清单文件中添加蓝牙相关权限如下 !--蓝牙连接权限--uses-permission android:nameandroid.permission.BLUETOOTH /!--发现和配对蓝牙设备权限--uses-permission android:nameandroid.permission.BLUETOOTH_ADMIN /!--Android 6~11 定位权限--uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION /uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION /!--以下三个是Android12中新增作用与Android12及以上--!--Android12 的蓝牙权限 如果您的应用与已配对的蓝牙设备通信或者获取当前手机蓝牙是否打开--uses-permission android:nameandroid.permission.BLUETOOTH_CONNECT /!--Android12 的蓝牙权限 如果您的应用使当前设备可被其他蓝牙设备检测到--uses-permission android:nameandroid.permission.BLUETOOTH_ADVERTISE /!--Android12 的蓝牙权限 如果您的应用查找蓝牙设备如蓝牙低功耗 (BLE) 外围设备Android12在不申请定位权限时必须加上android:usesPermissionFlagsneverForLocation否则搜不到设备--uses-permissionandroid:nameandroid.permission.BLUETOOTH_SCANandroid:usesPermissionFlagsneverForLocationtools:targetApis /二、搜索蓝牙设备
搜索蓝牙设备之前需要检测手机蓝牙是否已经打开如果未开启蓝牙需要先开启蓝牙才能搜索蓝牙设备。
1、创建MainActivity
在项目包名的位置右键选择创建Empty Views Activity
勾选Launcher Activity然后点击Finish 构建activity_main.xml布局
?xml version1.0 encodingutf-8?
androidx.constraintlayout.widget.ConstraintLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:idid/mainandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:paddingHorizontal15dpandroid:paddingVertical20dptools:context.MainActivityButtonandroid:idid/btnStartScanandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text搜索蓝牙设备app:layout_constraintStart_toStartOfparentapp:layout_constraintTop_toTopOfparent //androidx.constraintlayout.widget.ConstraintLayoutMainActivity中通过ViewBinding绑定布局代码如下
public class MainActivity extends AppCompatActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding mBinding ActivityMainBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());}
}2、开启蓝牙
MainActivity中添加点击事件
public class MainActivity extends AppCompatActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding mBinding ActivityMainBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());mBinding.btnStartScan.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {}});}
}新建个BleUtils工具类并添加检测蓝牙是否开启、检测是否有权限的方法
public class BleUtils {/*** 检测是否已经开启蓝牙*/public static boolean isOpenBle(Context context) {BluetoothManager manager (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);if (manager ! null) {BluetoothAdapter adapter manager.getAdapter();if (adapter ! null) {return adapter.isEnabled();}}return false;}/*** 检测是否有权限*/public static boolean hasPermission(Context context, String permission) {return context.checkSelfPermission(permission) PackageManager.PERMISSION_GRANTED;}}然后在搜索蓝牙设备的点击事件中检测手机是否已开启蓝牙已开启蓝牙可以搜索蓝牙设备未开启蓝牙需要先开启蓝牙 mBinding.btnStartScan.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {//判断是否开启蓝牙if (!BleUtils.isOpenBle(mContext)) {openBle();} else {//已开启蓝牙//搜索蓝牙设备searchBle();}}});开启蓝牙需要打开蓝牙相关的权限
在build.gradle中引入三方库’com.blankj:utilcodex:1.31.1’用于权限管理和获取各种工具类 //https://github.com/Blankj/AndroidUtilCode 工具类implementation com.blankj:utilcodex:1.31.1在MainActivity中添加开启蓝牙方法 /*** 开启蓝牙*/SuppressLint(MissingPermission)public void openBle() {if (Build.VERSION.SDK_INT Build.VERSION_CODES.S) {//Android12以上添加权限if (BleUtils.hasPermission(mContext, android.Manifest.permission.BLUETOOTH_CONNECT)) {//开启蓝牙Intent intent new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);} else {PermissionUtils.permission(Manifest.permission.BLUETOOTH_CONNECT).callback(new PermissionUtils.SimpleCallback() {Overridepublic void onGranted() {Intent intent new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);mContext.startActivity(intent);}Overridepublic void onDenied() {ToastUtils.showShort(Android12无此权限无法打开蓝牙);}}).request();}} else {Intent intent new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);mContext.startActivity(intent);}}扫描蓝牙设备前需要检测扫描蓝牙权限是否开启 /*** 搜索蓝牙设备,检测搜索权限*/private void searchBle() {if (Build.VERSION.SDK_INT Build.VERSION_CODES.S) {//Android12以上需要BLUETOOTH_SCAN权限if (!BleUtils.hasPermission(mContext, Manifest.permission.BLUETOOTH_CONNECT)) {PermissionUtils.permission(Manifest.permission.BLUETOOTH_CONNECT).callback(new PermissionUtils.SimpleCallback() {Overridepublic void onGranted() {//开启蓝牙Intent intent new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);}Overridepublic void onDenied() {ToastUtils.showShort(Android12无此权限无法打开蓝牙);}}).request();return;}if (BleUtils.hasPermission(mContext, Manifest.permission.BLUETOOTH_SCAN)) {ToastUtils.showShort(扫描蓝牙);startScan();} else {PermissionUtils.permission(Manifest.permission.BLUETOOTH_SCAN).callback(new PermissionUtils.SimpleCallback() {Overridepublic void onGranted() {//扫描蓝牙ToastUtils.showShort(扫描蓝牙);}Overridepublic void onDenied() {ToastUtils.showShort(Android12无此权限无法扫描蓝牙);}}).request();}} else {if (BleUtils.hasPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION)) {ToastUtils.showShort(扫描蓝牙);startScan();} else {PermissionUtils.permission(Manifest.permission.ACCESS_FINE_LOCATION).callback(new PermissionUtils.SimpleCallback() {Overridepublic void onGranted() {//扫描蓝牙ToastUtils.showShort(扫描蓝牙);}Overridepublic void onDenied() {ToastUtils.showShort(Android12无此权限无法扫描蓝牙);}}).request();}}}3、扫描搜索蓝牙设备 /*** 开始扫描蓝牙设备*/SuppressLint(MissingPermission)private void startScan() {BluetoothManager manager (BluetoothManager) mContext.getSystemService(BLUETOOTH_SERVICE);mBluetoothAdapter manager.getAdapter();if (mBluetoothAdapter ! null) {mScanner mBluetoothAdapter.getBluetoothLeScanner();LogUtils.i(startScan);if (mScanner ! null) {mHandler.removeCallbacks(scanRunnable);mScanner.startScan(scanCallback);mHandler.postDelayed(scanRunnable, 10 * 1000L);}}}/*** 扫描结果*/SuppressLint(MissingPermission)private final ScanCallback scanCallback new ScanCallback() {Overridepublic void onScanResult(int callbackType, ScanResult result) {super.onScanResult(callbackType, result);if (result ! null) {BluetoothDevice device result.getDevice();int rssi result.getRssi();String address device.getAddress();ScanDeviceBean scanDeviceBean new ScanDeviceBean();scanDeviceBean.setDeviceMac(device.getAddress());String deviceName device.getName();scanDeviceBean.setDeviceName(!TextUtils.isEmpty(deviceName) ? deviceName : Unknow);scanDeviceBean.setDeviceRssi(rssi);}}Overridepublic void onScanFailed(int errorCode) {super.onScanFailed(errorCode);}};class StopScanRunnable implements Runnable {StopScanRunnable() {}Overridepublic void run() {stopScan();}}/*** 停止扫描*/SuppressLint(MissingPermission)public void stopScan() {LogUtils.i(stopScan);try {if (mScanner ! null) {mHandler.removeCallbacks(scanRunnable);mScanner.stopScan(scanCallback);}} catch (Exception e) {throw new RuntimeException(e);}}其中ScanDeviceBean为扫描结果实体类
public class ScanDeviceBean {private String deviceMac;private String deviceName;private int deviceRssi;public String getDeviceMac() {return deviceMac;}public void setDeviceMac(String deviceMac) {this.deviceMac deviceMac;}public String getDeviceName() {return deviceName;}public void setDeviceName(String deviceName) {this.deviceName deviceName;}public int getDeviceRssi() {return deviceRssi;}public void setDeviceRssi(int deviceRssi) {this.deviceRssi deviceRssi;}
}activity_main.xml中添加RecyclerView用于展示搜素到的蓝牙设备
?xml version1.0 encodingutf-8?
androidx.constraintlayout.widget.ConstraintLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:idid/mainandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:paddingHorizontal15dpandroid:paddingVertical20dptools:context.MainActivityButtonandroid:idid/btnStartScanandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text搜索蓝牙设备app:layout_constraintStart_toStartOfparentapp:layout_constraintTop_toTopOfparent /androidx.recyclerview.widget.RecyclerViewandroid:idid/recyclerViewandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentapp:layoutManagerandroidx.recyclerview.widget.LinearLayoutManagerapp:layout_constraintTop_toBottomOfid/btnStartScan //androidx.constraintlayout.widget.ConstraintLayout将搜索到的蓝牙设备显示到列表中 //https://github.com/CymChad/BaseRecyclerViewAdapterHelperimplementation com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4DeviceAdapter
public class DeviceAdapter extends BaseQuickAdapterScanDeviceBean, BaseViewHolder {public DeviceAdapter() {super(R.layout.item_device);}Overrideprotected void convert(NonNull BaseViewHolder baseViewHolder, ScanDeviceBean deviceEntity) {baseViewHolder.setText(R.id.tv_name, deviceEntity.getDeviceName());baseViewHolder.setText(R.id.tv_address, deviceEntity.getDeviceMac());baseViewHolder.setText(R.id.tv_rssi, deviceEntity.getDeviceRssi()dBm);}
}
item_device布局
?xml version1.0 encodingutf-8?
androidx.constraintlayout.widget.ConstraintLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:paddingVertical8dpImageViewandroid:idid/imageViewandroid:layout_width50dpandroid:layout_height50dpandroid:padding8dpapp:layout_constraintStart_toStartOfparentapp:layout_constraintTop_toTopOfparentapp:srcCompatdrawable/icon_bluetooth /TextViewandroid:idid/tv_nameandroid:layout_width0dpandroid:layout_heightwrap_contentandroid:layout_marginStart10dpandroid:layout_marginTop4dpandroid:layout_marginEnd10dpandroid:textColorcolor/blackandroid:textSize14spandroid:textStyleboldapp:layout_constraintEnd_toStartOfid/tv_rssiapp:layout_constraintStart_toEndOfid/imageViewapp:layout_constraintTop_toTopOfid/imageViewtools:textBLE Name /TextViewandroid:idid/tv_addressandroid:layout_width0dpandroid:layout_heightwrap_contentandroid:layout_marginStart10dpandroid:layout_marginEnd10dpandroid:layout_marginBottom4dpandroid:textSize12spapp:layout_constraintBottom_toBottomOfid/imageViewapp:layout_constraintEnd_toStartOfid/tv_rssiapp:layout_constraintStart_toEndOfid/imageViewtools:text32:65:CF:0A:DA:87 /TextViewandroid:idid/tv_rssiandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentapp:layout_constraintBottom_toBottomOfparentapp:layout_constraintEnd_toEndOfparentapp:layout_constraintTop_toTopOfparenttools:text-62dBm //androidx.constraintlayout.widget.ConstraintLayout蓝牙图标icon_bluetooth.xml
?xml version1.0 encodingUTF-8 standaloneno?
vector xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:width48dpandroid:height48dpandroid:autoMirroredtrueandroid:tint#000000android:viewportWidth24.0android:viewportHeight24.0pathandroid:fillColorandroid:color/whiteandroid:pathDataM14.24,12.01l2.32,2.32c0.28,-0.72 0.44,-1.51 0.44,-2.33 0,-0.82 -0.16,-1.59 -0.43,-2.31l-2.33,2.32zM19.53,6.71l-1.26,1.26c0.63,1.21 0.98,2.57 0.98,4.02s-0.36,2.82 -0.98,4.02l1.2,1.2c0.97,-1.54 1.54,-3.36 1.54,-5.31 -0.01,-1.89 -0.55,-3.67 -1.48,-5.19zM15.71,7.71L10,2L9,2v7.59L4.41,5 3,6.41 8.59,12 3,17.59 4.41,19 9,14.41L9,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM11,5.83l1.88,1.88L11,9.59L11,5.83zM12.88,16.29L11,18.17v-3.76l1.88,1.88z //vector在MainActivity中展示蓝牙设备列表
public class MainActivity extends AppCompatActivity {private Context mContext;private BluetoothAdapter mBluetoothAdapter;private BluetoothLeScanner mScanner;private static final Handler mHandler new Handler();private final Runnable scanRunnable new StopScanRunnable();private final ArrayListScanDeviceBean mDeviceList new ArrayList();private DeviceAdapter mDeviceAdapter;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ActivityMainBinding mBinding ActivityMainBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());mContext getApplicationContext();mDeviceAdapter new DeviceAdapter();mBinding.recyclerView.setAdapter(mDeviceAdapter);mBinding.btnStartScan.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {//判断是否开启蓝牙if (!BleUtils.isOpenBle(mContext)) {openBle();} else {//已开启蓝牙//搜索蓝牙设备searchBle();}}});}/*** 开启蓝牙*/SuppressLint(MissingPermission)public void openBle() {if (Build.VERSION.SDK_INT Build.VERSION_CODES.S) {//Android12以上添加权限if (BleUtils.hasPermission(mContext, android.Manifest.permission.BLUETOOTH_CONNECT)) {//开启蓝牙Intent intent new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);} else {PermissionUtils.permission(Manifest.permission.BLUETOOTH_CONNECT).callback(new PermissionUtils.SimpleCallback() {Overridepublic void onGranted() {Intent intent new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);mContext.startActivity(intent);}Overridepublic void onDenied() {ToastUtils.showShort(Android12无此权限无法打开蓝牙);}}).request();}} else {Intent intent new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);mContext.startActivity(intent);}}/*** 搜索蓝牙设备,检测搜索权限*/SuppressLint(MissingPermission)private void searchBle() {if (Build.VERSION.SDK_INT Build.VERSION_CODES.S) {//Android12以上需要BLUETOOTH_SCAN权限if (!BleUtils.hasPermission(mContext, Manifest.permission.BLUETOOTH_CONNECT)) {PermissionUtils.permission(Manifest.permission.BLUETOOTH_CONNECT).callback(new PermissionUtils.SimpleCallback() {Overridepublic void onGranted() {//开启蓝牙Intent intent new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);}Overridepublic void onDenied() {ToastUtils.showShort(Android12无此权限无法打开蓝牙);}}).request();return;}if (BleUtils.hasPermission(mContext, Manifest.permission.BLUETOOTH_SCAN)) {ToastUtils.showShort(扫描蓝牙);startScan();} else {PermissionUtils.permission(Manifest.permission.BLUETOOTH_SCAN).callback(new PermissionUtils.SimpleCallback() {Overridepublic void onGranted() {//扫描蓝牙ToastUtils.showShort(扫描蓝牙);}Overridepublic void onDenied() {ToastUtils.showShort(Android12无此权限无法扫描蓝牙);}}).request();}} else {if (BleUtils.hasPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION)) {ToastUtils.showShort(扫描蓝牙);startScan();} else {PermissionUtils.permission(Manifest.permission.ACCESS_FINE_LOCATION).callback(new PermissionUtils.SimpleCallback() {Overridepublic void onGranted() {//扫描蓝牙ToastUtils.showShort(扫描蓝牙);}Overridepublic void onDenied() {ToastUtils.showShort(Android12无此权限无法扫描蓝牙);}}).request();}}}/*** 开始扫描蓝牙设备*/SuppressLint(MissingPermission)private void startScan() {BluetoothManager manager (BluetoothManager) mContext.getSystemService(BLUETOOTH_SERVICE);mBluetoothAdapter manager.getAdapter();if (mBluetoothAdapter ! null) {mScanner mBluetoothAdapter.getBluetoothLeScanner();LogUtils.i(startScan);if (mScanner ! null) {mHandler.removeCallbacks(scanRunnable);mScanner.startScan(scanCallback);mHandler.postDelayed(scanRunnable, 10 * 1000L);}}}/*** 扫描结果*/SuppressLint(MissingPermission)private final ScanCallback scanCallback new ScanCallback() {Overridepublic void onScanResult(int callbackType, ScanResult result) {super.onScanResult(callbackType, result);if (result ! null) {BluetoothDevice device result.getDevice();int rssi result.getRssi();String address device.getAddress();ScanDeviceBean scanDeviceBean new ScanDeviceBean();scanDeviceBean.setDeviceMac(device.getAddress());String deviceName device.getName();scanDeviceBean.setDeviceName(!TextUtils.isEmpty(deviceName) ? deviceName : Unknow);scanDeviceBean.setDeviceRssi(rssi);boolean isContain false;for (ScanDeviceBean bean : mDeviceList) {if (bean.getDeviceMac().equals(scanDeviceBean.getDeviceMac())) {isContain true;break;}}if (!isContain) {mDeviceList.add(scanDeviceBean);mDeviceAdapter.setList(mDeviceList);}}}Overridepublic void onScanFailed(int errorCode) {super.onScanFailed(errorCode);}};class StopScanRunnable implements Runnable {StopScanRunnable() {}Overridepublic void run() {stopScan();}}/*** 停止扫描*/SuppressLint(MissingPermission)public void stopScan() {LogUtils.i(stopScan);try {if (mScanner ! null) {mHandler.removeCallbacks(scanRunnable);mScanner.stopScan(scanCallback);}} catch (Exception e) {throw new RuntimeException(e);}}}搜索到的蓝牙设备列表如下
三、连接蓝牙设备
蓝牙设备列表添加点击事件点击连接蓝牙设备 mDeviceAdapter.setOnItemClickListener(new OnItemClickListener() {Overridepublic void onItemClick(NonNull BaseQuickAdapter?, ? adapter, NonNull View view, int position) {String deviceMac mDeviceList.get(position).getDeviceMac();connectBle(deviceMac);}});/*** 连接蓝牙设备** param macAddress 蓝牙设备地址*/SuppressLint(MissingPermission)public void connectBle(String macAddress) {if (mBluetoothAdapter ! null !TextUtils.isEmpty(macAddress)) {BluetoothDevice remoteDevice mBluetoothAdapter.getRemoteDevice(macAddress);if (remoteDevice ! null) {if (Build.VERSION.SDK_INT Build.VERSION_CODES.M) {//BluetoothDevice.TRANSPORT_AUTO:对于GATT连接到远程双模设备无物理传输优先。//BluetoothDevice.TRANSPORT_BREDR:GATT连接到远程双模设备优先BR/EDR。//BluetoothDevice.TRANSPORT_LE:GATT连接到远程双模设备优先BLE。mBluetoothGatt remoteDevice.connectGatt(mContext, false, mBleGattCallBack, BluetoothDevice.TRANSPORT_LE);} else {mBluetoothGatt remoteDevice.connectGatt(mContext, false, mBleGattCallBack);}}}}连接状态回调
/*** 连接状态回调*/SuppressLint(MissingPermission)class BleGattCallBack extends BluetoothGattCallback {// Override
// public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
// super.onMtuChanged(gatt, mtu, status);
// if (status BluetoothGatt.GATT_SUCCESS) {
// LogUtils.e( request mtu success.约定后的MTU值为 mtu);
// } else {
// LogUtils.e( request mtu failed.);
// }
//
// if (mBluetoothGatt ! null) {
// mBluetoothGatt.discoverServices();
// }
// }Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {super.onConnectionStateChange(gatt, status, newState);LogUtils.i(onConnectionStateChange status status newState newState);if (newState BluetoothProfile.STATE_CONNECTED) {LogUtils.i(蓝牙连接成功开始发现服务);// boolean mut gatt.requestMtu(500);//如有需要可以申请扩容
// LogUtils.i(申请MTU扩容 mut);if (mBluetoothGatt ! null) {mBluetoothGatt.discoverServices();}} else if (newState BluetoothProfile.STATE_DISCONNECTED) {LogUtils.e(蓝牙连接已断开);}}Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {super.onServicesDiscovered(gatt, status);LogUtils.i(onServicesDiscovered status status);if (status BluetoothGatt.GATT_SUCCESS) {LogUtils.i(成功获取服务开始获取服务里的特性);if (mBluetoothGatt ! null) {ListBluetoothGattService services mBluetoothGatt.getServices();for (BluetoothGattService gattService : services) {LogUtils.d(服务uuid gattService.getUuid());ListBluetoothGattCharacteristic characteristics gattService.getCharacteristics();for (BluetoothGattCharacteristic gattCharacteristic : characteristics) {int charaProp gattCharacteristic.getProperties();StringBuilder stringBuilder new StringBuilder();if ((charaProp BluetoothGattCharacteristic.PROPERTY_READ) 0) {stringBuilder.append( 可读 );}if ((charaProp BluetoothGattCharacteristic.PROPERTY_WRITE) 0) {stringBuilder.append( 可写 );}if ((charaProp BluetoothGattCharacteristic.PROPERTY_NOTIFY) 0) {stringBuilder.append( 通知 );}LogUtils.d(特性uuid gattCharacteristic.getUuid() stringBuilder);}}}} else {LogUtils.e(服务获取失败);}}Overridepublic void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicRead(gatt, characteristic, status);//Android12及以下适用此方法if (Build.VERSION.SDK_INT Build.VERSION_CODES.TIRAMISU) {//适用于Android12及以下LogUtils.i(onCharacteristicRead(Android12及以下)读取特性 characteristic.getUuid() status status);}}Overridepublic void onCharacteristicRead(NonNull BluetoothGatt gatt, NonNull BluetoothGattCharacteristic characteristic, NonNull byte[] value, int status) {super.onCharacteristicRead(gatt, characteristic, value, status);//Android13及以上适用此方法LogUtils.i(onCharacteristicRead(Android13及以上)读取特性 characteristic.getUuid() status status);}Overridepublic void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {super.onCharacteristicWrite(gatt, characteristic, status);LogUtils.i(onCharacteristicWrite写入特性 characteristic.getUuid() status status);if (status BluetoothGatt.GATT_SUCCESS) {//Android 13及以上版本characteristic.getValue()方法已过时可能存在获取不到value的可能如需要可以通过gatt.readCharacteristic(characteristic)前提是这个特性可读String value Arrays.toString(characteristic.getValue());LogUtils.i(onCharacteristicWrite写入特性 characteristic.getUuid() 值 value 十六进制值 BleUtils.bytesToHex(characteristic.getValue()));} else {}}//Descriptor描述符中定义的属性用于描述一个characteristic值Overridepublic void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {super.onDescriptorWrite(gatt, descriptor, status);if (Build.VERSION.SDK_INT Build.VERSION_CODES.TIRAMISU) {LogUtils.i(onDescriptorWrite(Android13及以上)写描述符 descriptor.getUuid().toString() status: status);} else {LogUtils.i(onDescriptorWrite(Android12及以下)写描述符 descriptor.getUuid().toString() value: Arrays.equals(descriptor.getValue(), BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) status: status);}//Android 13及以上版本descriptor.getValue()方法已过时获取的value为null需要可以通过gatt.readDescriptor(descriptor)获取value前提是这个特性可读if (status BluetoothGatt.GATT_SUCCESS) {} else {}}Overridepublic void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {super.onDescriptorRead(gatt, descriptor, status);//Android12及以下适用此方法if (Build.VERSION.SDK_INT Build.VERSION_CODES.TIRAMISU) {//适用于Android12及以下LogUtils.i(onDescriptorRead(Android12及以下)读描述符 descriptor.getUuid().toString());if (status BluetoothGatt.GATT_SUCCESS) {} else {}}}Overridepublic void onDescriptorRead(NonNull BluetoothGatt gatt, NonNull BluetoothGattDescriptor descriptor, int status, NonNull byte[] value) {super.onDescriptorRead(gatt, descriptor, status, value);//Android13及以上适用此方法LogUtils.i(onDescriptorRead(Android13及以上)读描述符 descriptor.getUuid().toString());if (status BluetoothGatt.GATT_SUCCESS) {} else {}}Overridepublic void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {//通知特性发生改变super.onCharacteristicChanged(gatt, characteristic);if (Build.VERSION.SDK_INT Build.VERSION_CODES.TIRAMISU) {//适用于Android12及Android12以下final byte[] value characteristic.getValue();if (value ! null value.length 0) {String hexValue BleUtils.bytesToHex(characteristic.getValue());LogUtils.i(onCharacteristicChanged(Android12及以下)特性发生改变 characteristic.getUuid() 值 hexValue);}}}Overridepublic void onCharacteristicChanged(NonNull BluetoothGatt gatt, NonNull BluetoothGattCharacteristic characteristic, NonNull byte[] value) {super.onCharacteristicChanged(gatt, characteristic, value);//Android13及以上适用此方法if (value.length 0) {String hexValue BleUtils.bytesToHex(value);LogUtils.i(onCharacteristicChanged(Android13及以上)特性发生改变 characteristic.getUuid() 值 hexValue);}}}四、读、写、通知
根据uuid获取相应的特性就可以进行读、写、通知操作 /*** 读取特性值** param gattCharacteristic 要读取的特性*/private boolean readCharacteristic(BluetoothGattCharacteristic gattCharacteristic) {if (mBluetoothGatt ! null) {boolean readState mBluetoothGatt.readCharacteristic(gattCharacteristic);LogUtils.i(readCharacteristic readState);return readState;}return false;}/*** 写入特性值** param gattCharacteristic 要写入的特性*/private boolean writeCharacteristic(BluetoothGattCharacteristic gattCharacteristic, byte[] data) {if (mBluetoothGatt ! null) {boolean writeState;if (Build.VERSION.SDK_INT Build.VERSION_CODES.TIRAMISU) {//Android13及以上适用此方法writeState mBluetoothGatt.writeCharacteristic(gattCharacteristic,data, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT) BluetoothStatusCodes.SUCCESS;} else {//Android12及以下适用此方法writeState mBluetoothGatt.writeCharacteristic(gattCharacteristic);}LogUtils.i(writeCharacteristic writeState);return writeState;}return false;}/*** 设置特性通知** param gattCharacteristic 需要获取通知的特性* param descriptorUuid 描述UUID* param enable true 获取特性变化通知 false 关闭通知*/private boolean setCharacteristicNotification(BluetoothGattCharacteristic gattCharacteristic, String descriptorUuid, boolean enable) {if (mBluetoothGatt ! null) {boolean notifyCharacter mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, enable);if (notifyCharacter) {BluetoothGattDescriptor descriptor gattCharacteristic.getDescriptor(UUID.fromString(descriptorUuid));if (descriptor ! null) {boolean notifyState;if (Build.VERSION.SDK_INT Build.VERSION_CODES.TIRAMISU) {//Android13及以上适用此方法notifyState mBluetoothGatt.writeDescriptor(descriptor,enable ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE) BluetoothStatusCodes.SUCCESS;} else {//Android12及以下适用此方法if (enable) {descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);} else {descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);}notifyState mBluetoothGatt.writeDescriptor(descriptor);}LogUtils.i(setCharacteristicNotification notifyState notifyState);return notifyState;}}}return false;}
五、判断手机已连接的蓝牙设备
判断是否有已经连接的蓝牙设备通过此方法可以看到手机连接了几个蓝牙设备获取已连接蓝牙设备的信息 /*** 判断是否有已经连接的蓝牙设备*/public void isConnectedBleDevice() {BluetoothManager manager (BluetoothManager) mContext.getSystemService(BLUETOOTH_SERVICE);if (manager ! null) {ListBluetoothDevice connectedDevices manager.getConnectedDevices(BluetoothProfile.GATT);LogUtils.d(connectedDevices.size() connectedDevices.size());for (BluetoothDevice bluetoothDevice : connectedDevices) {LogUtils.d(bluetoothDevice.getAddress() bluetoothDevice.getName());}}}六、刷新缓存
蓝牙断开连接后通过反射的方式刷新缓存 /*** 刷新缓存*/public void refreshDeviceCache() {if (mBluetoothGatt ! null) {try {Method localMethod mBluetoothGatt.getClass().getMethod(refresh);Boolean success (Boolean) localMethod.invoke(mBluetoothGatt);LogUtils.i(refreshDeviceCache, is success: success);} catch (Exception e) {LogUtils.e(exception occur while refreshing device: e.getMessage());e.printStackTrace();}}}