引入蓝牙依赖
This commit is contained in:
@@ -226,6 +226,7 @@ dependencies {
|
|||||||
implementation "androidx.camera:camera-camera2:1.0.2"
|
implementation "androidx.camera:camera-camera2:1.0.2"
|
||||||
implementation "androidx.camera:camera-lifecycle:1.0.2"
|
implementation "androidx.camera:camera-lifecycle:1.0.2"
|
||||||
implementation "androidx.camera:camera-view:1.0.0-alpha25"
|
implementation "androidx.camera:camera-view:1.0.0-alpha25"
|
||||||
|
//蓝牙扫描
|
||||||
implementation 'no.nordicsemi.android.support.v18:scanner:1.6.0'
|
implementation 'no.nordicsemi.android.support.v18:scanner:1.6.0'
|
||||||
//蓝牙通讯
|
//蓝牙通讯
|
||||||
implementation 'no.nordicsemi.android:ble:2.11.0'
|
implementation 'no.nordicsemi.android:ble:2.11.0'
|
||||||
|
|||||||
@@ -35,6 +35,14 @@
|
|||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||||
|
<!-- 蓝牙权限 -->
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||||
|
<!-- 支持ble的设备 -->
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.bluetooth_le"
|
||||||
|
android:required="true" />
|
||||||
|
|
||||||
<!--后台获取位置信息,若需后台定位则必选-->
|
<!--后台获取位置信息,若需后台定位则必选-->
|
||||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||||
<!--用于申请调用A-GPS模块,卫星定位加速-->
|
<!--用于申请调用A-GPS模块,卫星定位加速-->
|
||||||
|
|||||||
@@ -120,4 +120,7 @@ public class AppConfig {
|
|||||||
public static String APP_CLIENT_ID = "428a8310cd442757ae699df5d894f051";
|
public static String APP_CLIENT_ID = "428a8310cd442757ae699df5d894f051";
|
||||||
public static String APP_USER_TYPE = "app_user";
|
public static String APP_USER_TYPE = "app_user";
|
||||||
|
|
||||||
|
//蓝牙设备的uuid
|
||||||
|
public static String BLUETOOTH_DEVICE_UUID = "1775244d-6b43-439b-877c-060f2d9bed07";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ import com.ckkj.water.BuildConfig;
|
|||||||
import com.ckkj.water.ConstantUtil;
|
import com.ckkj.water.ConstantUtil;
|
||||||
import com.ckkj.water.R;
|
import com.ckkj.water.R;
|
||||||
import com.ckkj.water.base.BaseActivity;
|
import com.ckkj.water.base.BaseActivity;
|
||||||
|
import com.ckkj.water.custom.GridSpacingItemDecoration;
|
||||||
import com.ckkj.water.databinding.AddDeviceLayoutBinding;
|
import com.ckkj.water.databinding.AddDeviceLayoutBinding;
|
||||||
|
import com.ckkj.water.device.adapter.BleScanDeviceAdapter;
|
||||||
import com.ckkj.water.device.mvp.DeviceContract;
|
import com.ckkj.water.device.mvp.DeviceContract;
|
||||||
import com.ckkj.water.device.mvp.DeviceImpl;
|
import com.ckkj.water.device.mvp.DeviceImpl;
|
||||||
import com.ckkj.water.device.mvp.DevicePresenter;
|
import com.ckkj.water.device.mvp.DevicePresenter;
|
||||||
@@ -72,6 +74,8 @@ public class AddDeviceActivity_copy extends BaseActivity<AddDeviceLayoutBinding,
|
|||||||
private String mUuid = "1775244d-6b43-439b-877c-060f2d9bed07";
|
private String mUuid = "1775244d-6b43-439b-877c-060f2d9bed07";
|
||||||
private ScanCallback mScanCallback;
|
private ScanCallback mScanCallback;
|
||||||
private boolean bluetoothReady = false;
|
private boolean bluetoothReady = false;
|
||||||
|
private BleScanDeviceAdapter bleAdapter;
|
||||||
|
private List<WaterDeviceEntity> mDeviceList = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DevicePresenter createPresenter() {
|
public DevicePresenter createPresenter() {
|
||||||
@@ -90,6 +94,10 @@ public class AddDeviceActivity_copy extends BaseActivity<AddDeviceLayoutBinding,
|
|||||||
.titleBar(viewBinding.rlTitle)
|
.titleBar(viewBinding.rlTitle)
|
||||||
.init();
|
.init();
|
||||||
viewBinding.includedTitle.tvTitle.setText(R.string.add_device_title);
|
viewBinding.includedTitle.tvTitle.setText(R.string.add_device_title);
|
||||||
|
viewBinding.rvDevices.addItemDecoration(new GridSpacingItemDecoration(4, 10, true));
|
||||||
|
bleAdapter = new BleScanDeviceAdapter(mContext,R.layout.scan_ble_device_item,mDeviceList);
|
||||||
|
viewBinding.rvDevices.setAdapter(bleAdapter);
|
||||||
|
|
||||||
if(checkBluetoothPermissions()){
|
if(checkBluetoothPermissions()){
|
||||||
// 初始化蓝牙适配器
|
// 初始化蓝牙适配器
|
||||||
initBluetooth();
|
initBluetooth();
|
||||||
@@ -115,7 +123,6 @@ public class AddDeviceActivity_copy extends BaseActivity<AddDeviceLayoutBinding,
|
|||||||
if (animationDrawable.isRunning()) {
|
if (animationDrawable.isRunning()) {
|
||||||
animationDrawable.stop();
|
animationDrawable.stop();
|
||||||
viewBinding.ivScanAnimation.setVisibility(GONE);
|
viewBinding.ivScanAnimation.setVisibility(GONE);
|
||||||
viewBinding.imgDeviceItem.setVisibility(VISIBLE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,21 +148,18 @@ public class AddDeviceActivity_copy extends BaseActivity<AddDeviceLayoutBinding,
|
|||||||
@Override
|
@Override
|
||||||
public void onScanResult(int callbackType, @NonNull ScanResult result) {
|
public void onScanResult(int callbackType, @NonNull ScanResult result) {
|
||||||
super.onScanResult(callbackType, result);
|
super.onScanResult(callbackType, result);
|
||||||
|
WaterDeviceEntity bean = new WaterDeviceEntity();
|
||||||
|
//设备名字
|
||||||
String deviceName = result.getScanRecord() != null ?
|
String deviceName = result.getScanRecord() != null ?
|
||||||
result.getScanRecord().getDeviceName() : "无名称";
|
result.getScanRecord().getDeviceName() : "无名称";
|
||||||
|
//Mac地址
|
||||||
String deviceAddress = result.getDevice().getAddress();
|
String deviceAddress = result.getDevice().getAddress();
|
||||||
Log.e("TEST", "扫描到: " + deviceName + " (" + deviceAddress + ")");
|
|
||||||
|
|
||||||
ScanRecord record = result.getScanRecord();
|
bean.setDeviceName(deviceName);
|
||||||
|
bean.setMacAddress(deviceAddress);
|
||||||
|
mDeviceList.add(bean);
|
||||||
|
bleAdapter.notifyItemInserted(mDeviceList.size() - 1);
|
||||||
|
|
||||||
if (record != null) {
|
|
||||||
|
|
||||||
List<ParcelUuid> uuids =
|
|
||||||
record.getServiceUuids();
|
|
||||||
Log.e("TEST", "uuids=" + uuids);
|
|
||||||
}
|
|
||||||
|
|
||||||
ToastUtil.showShort(mContext, "扫描到: " + deviceName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -238,7 +242,6 @@ public class AddDeviceActivity_copy extends BaseActivity<AddDeviceLayoutBinding,
|
|||||||
setClick(viewBinding.includedTitle.imgBack);
|
setClick(viewBinding.includedTitle.imgBack);
|
||||||
setClick(viewBinding.tvScanAdd);
|
setClick(viewBinding.tvScanAdd);
|
||||||
setClick(viewBinding.btnBleScan);
|
setClick(viewBinding.btnBleScan);
|
||||||
setClick(viewBinding.imgDeviceItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setClick(View view) {
|
private void setClick(View view) {
|
||||||
@@ -251,11 +254,11 @@ public class AddDeviceActivity_copy extends BaseActivity<AddDeviceLayoutBinding,
|
|||||||
finish();
|
finish();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R.id.img_device_item:
|
// case R.id.img_device_item:
|
||||||
Bundle bundle = new Bundle();
|
// Bundle bundle = new Bundle();
|
||||||
bundle.putInt(ConstantUtil.ACTIVITY_NAVIGATE_FLAG,100);
|
// bundle.putInt(ConstantUtil.ACTIVITY_NAVIGATE_FLAG,100);
|
||||||
goTo(mContext, SelectWifiActivity.class,bundle);
|
// goTo(mContext, SelectWifiActivity.class,bundle);
|
||||||
break;
|
// break;
|
||||||
|
|
||||||
case R.id.tv_scan_add:
|
case R.id.tv_scan_add:
|
||||||
//检测有无相机权限
|
//检测有无相机权限
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.ckkj.water.device.adapter;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.chad.library.adapter.base.BaseQuickAdapter;
|
||||||
|
import com.chad.library.adapter.base.BaseViewHolder;
|
||||||
|
import com.ckkj.water.R;
|
||||||
|
import com.ckkj.water.index.entity.WaterDeviceEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fengxiaoyang
|
||||||
|
* @date 2026/6/3
|
||||||
|
* @description 扫描到的设备适配器
|
||||||
|
*/
|
||||||
|
public class BleScanDeviceAdapter extends BaseQuickAdapter<WaterDeviceEntity, BaseViewHolder> {
|
||||||
|
private Context mContext;
|
||||||
|
public BleScanDeviceAdapter(Context context,int layoutResId, @Nullable List<WaterDeviceEntity> data) {
|
||||||
|
super(layoutResId, data);
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void convert(BaseViewHolder helper, WaterDeviceEntity item) {
|
||||||
|
helper.setText(R.id.tv_device_name,item.getDeviceName());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package com.ckkj.water.utils.manager;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothGatt;
|
||||||
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
import android.bluetooth.BluetoothGattService;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import no.nordicsemi.android.ble.BleManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fengxiaoyang
|
||||||
|
* @date 2026/6/3
|
||||||
|
* @description 蓝牙设备管理
|
||||||
|
*/
|
||||||
|
public class WaterDeviceManager extends BleManager {
|
||||||
|
private BluetoothGattCharacteristic writeCharacteristic;
|
||||||
|
private BluetoothGattCharacteristic notifyCharacteristic;
|
||||||
|
|
||||||
|
public WaterDeviceManager(@NonNull Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected BleManagerGattCallback getGattCallback() {
|
||||||
|
return new DeviceGattCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DeviceGattCallback extends BleManagerGattCallback {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initialize() {
|
||||||
|
|
||||||
|
setNotificationCallback(notifyCharacteristic)
|
||||||
|
.with((device, data) -> {
|
||||||
|
|
||||||
|
byte[] bytes = data.getValue();
|
||||||
|
|
||||||
|
Log.e("TEST", "收到数据: "
|
||||||
|
+ Arrays.toString(bytes));
|
||||||
|
});
|
||||||
|
|
||||||
|
enableNotifications(notifyCharacteristic)
|
||||||
|
.enqueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRequiredServiceSupported(@NonNull BluetoothGatt gatt) {
|
||||||
|
|
||||||
|
BluetoothGattService service =
|
||||||
|
gatt.getService(UUID.fromString(
|
||||||
|
"0000ffff-0000-1000-8000-00805f9b34fb"));
|
||||||
|
|
||||||
|
if (service == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeCharacteristic =
|
||||||
|
service.getCharacteristic(UUID.fromString(
|
||||||
|
"0000ff01-0000-1000-8000-00805f9b34fb"));
|
||||||
|
|
||||||
|
notifyCharacteristic =
|
||||||
|
service.getCharacteristic(UUID.fromString(
|
||||||
|
"0000ff02-0000-1000-8000-00805f9b34fb"));
|
||||||
|
|
||||||
|
return writeCharacteristic != null
|
||||||
|
&& notifyCharacteristic != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onServicesInvalidated() {
|
||||||
|
writeCharacteristic = null;
|
||||||
|
notifyCharacteristic = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(byte[] data) {
|
||||||
|
|
||||||
|
if (writeCharacteristic == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeCharacteristic(writeCharacteristic, data)
|
||||||
|
.enqueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@@ -43,14 +45,19 @@
|
|||||||
android:layout_width="@dimen/dp_200"
|
android:layout_width="@dimen/dp_200"
|
||||||
android:layout_height="@dimen/dp_200"
|
android:layout_height="@dimen/dp_200"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:src="@drawable/anim_add_device_scan"/>
|
android:src="@drawable/anim_add_device_scan"
|
||||||
|
android:visibility="visible"/>
|
||||||
|
|
||||||
<ImageView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/img_device_item"
|
android:id="@+id/rv_devices"
|
||||||
android:layout_width="@dimen/dp_150"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/dp_150"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:src="@mipmap/ic_launcher"
|
android:paddingHorizontal="@dimen/dp_5"
|
||||||
|
android:layout_marginTop="@dimen/dp_5"
|
||||||
|
tools:listitem="@layout/scan_ble_device_item"
|
||||||
|
app:spanCount="4"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||||
android:visibility="gone"/>
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|||||||
23
app/src/main/res/layout/scan_ble_device_item.xml
Normal file
23
app/src/main/res/layout/scan_ble_device_item.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/dp_5"
|
||||||
|
android:gravity="center_horizontal">
|
||||||
|
<com.makeramen.roundedimageview.RoundedImageView
|
||||||
|
android:id="@+id/img_device"
|
||||||
|
android:layout_width="@dimen/dp_60"
|
||||||
|
android:layout_height="@dimen/dp_60"
|
||||||
|
android:src="@mipmap/app_logo"
|
||||||
|
app:riv_corner_radius="@dimen/dp_10"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_device_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/dp_5"
|
||||||
|
android:text="设备名称"
|
||||||
|
android:textColor="@color/textPrimaryColor"
|
||||||
|
android:textSize="13sp"/>
|
||||||
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user