我创建了包括客户端和服务器应用程序的BLE应用程序。该代码运行成功。现在,我想将服务器代码作为服务运行,以使蓝牙每次都打开,并且可以在需要时由客户端应用程序进行搜索。用于服务器的代码如下。请指导我将此代码用作服务。
public class ServerActivity extends AppCompatActivity {
private static final String TAG = "ServerActivity";
private ActivityServerBinding mBinding;
private Handler mHandler;
private Handler mLogHandler;
private List<BluetoothDevice> mDevices;
private Map<String, byte[]> mClientConfigurations;
private BluetoothGattServer mGattServer;
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
// Lifecycle
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler();
mLogHandler = new Handler(Looper.getMainLooper());
mDevices = new ArrayList<>();
mClientConfigurations = new HashMap<>();
mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_server);
mBinding.restartServerButton.setOnClickListener(v -> restartServer());
}
@Override
protected void onResume() {
super.onResume();
// Check if bluetooth is enabled
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
// Request user to enable it
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableBtIntent);
finish();
return;
}
// Check low energy support
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
// Get a newer device
log("No LE Support.");
finish();
return;
}
// Check advertising
if (!mBluetoothAdapter.isMultipleAdvertisementSupported()) {
// Unable to run the server on this device, get a better device
log("No Advertising Support.");
finish();
return;
}
mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
GattServerCallback gattServerCallback = new GattServerCallback();
mGattServer = mBluetoothManager.openGattServer(this, gattServerCallback);
Bundle bundle = getIntent().getExtras();
String plate_name = bundle.getString("PLATE_NAME");
mBluetoothAdapter.setName(plate_name);
Toast.makeText(getApplicationContext(),"PLATE NAME "+plate_name,Toast.LENGTH_LONG).show();
@SuppressLint("HardwareIds")
String deviceInfo = "Device Info"
+ "\nName: " + mBluetoothAdapter.getName()
+ "\nAddress: " + mBluetoothAdapter.getAddress();
mBinding.serverDeviceInfoTextView.setText(deviceInfo);
setupServer();
startAdvertising();
}
@Override
protected void onPause() {
super.onPause();
stopAdvertising();
stopServer();
}
// GattServer
private void setupServer() {
BluetoothGattService service = new BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
// Write characteristic
BluetoothGattCharacteristic writeCharacteristic = new BluetoothGattCharacteristic(CHARACTERISTIC_ECHO_UUID,
BluetoothGattCharacteristic.PROPERTY_WRITE,
// Somehow this is not necessary, the client can still enable notifications
// | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
BluetoothGattCharacteristic.PERMISSION_WRITE);
// Characteristic with Descriptor
BluetoothGattCharacteristic notifyCharacteristic = new BluetoothGattCharacteristic(CHARACTERISTIC_TIME_UUID,
// Somehow this is not necessary, the client can still enable notifications
// BluetoothGattCharacteristic.PROPERTY_NOTIFY,
0, 0);
BluetoothGattDescriptor clientConfigurationDescriptor = new BluetoothGattDescriptor(CLIENT_CONFIGURATION_DESCRIPTOR_UUID,
BluetoothGattDescriptor.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE);
clientConfigurationDescriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
notifyCharacteristic.addDescriptor(clientConfigurationDescriptor);
service.addCharacteristic(writeCharacteristic);
service.addCharacteristic(notifyCharacteristic);
mGattServer.addService(service);
}
private void stopServer() {
if (mGattServer != null) {
mGattServer.close();
}
}
private void restartServer() {
stopAdvertising();
stopServer();
setupServer();
startAdvertising();
}
// Advertising
private void startAdvertising() {
if (mBluetoothLeAdvertiser == null) {
return;
}
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setConnectable(true)
.setTimeout(0)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_LOW)
.build();
ParcelUuid parcelUuid = new ParcelUuid(SERVICE_UUID);
AdvertiseData data = new AdvertiseData.Builder()
.setIncludeDeviceName(true)
.addServiceUuid(parcelUuid)
.build();
mBluetoothLeAdvertiser.startAdvertising(settings, data, mAdvertiseCallback);
}
private void stopAdvertising() {
if (mBluetoothLeAdvertiser != null) {
mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
}
}
private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
log("Peripheral advertising started.");
}
@Override
public void onStartFailure(int errorCode) {
log("Peripheral advertising failed: " + errorCode);
}
};
// Notifications
private void notifyCharacteristicTime(byte[] value) {
notifyCharacteristic(value, CHARACTERISTIC_TIME_UUID);
}
private void notifyCharacteristic(byte[] value, UUID uuid) {
mHandler.post(() -> {
BluetoothGattService service = mGattServer.getService(SERVICE_UUID);
BluetoothGattCharacteristic characteristic = service.getCharacteristic(uuid);
log("Notifying characteristic " + characteristic.getUuid().toString()
+ ", new value: " + StringUtils.byteArrayInHexFormat(value));
characteristic.setValue(value);
// Indications require confirmation, notifications do not
boolean confirm = BluetoothUtils.requiresConfirmation(characteristic);
for (BluetoothDevice device : mDevices) {
if (clientEnabledNotifications(device, characteristic)) {
mGattServer.notifyCharacteristicChanged(device, characteristic, confirm);
}
}
});
}
private boolean clientEnabledNotifications(BluetoothDevice device, BluetoothGattCharacteristic characteristic) {
List<BluetoothGattDescriptor> descriptorList = characteristic.getDescriptors();
BluetoothGattDescriptor descriptor = BluetoothUtils.findClientConfigurationDescriptor(descriptorList);
if (descriptor == null) {
// There is no client configuration descriptor, treat as true
return true;
}
String deviceAddress = device.getAddress();
byte[] clientConfiguration = mClientConfigurations.get(deviceAddress);
if (clientConfiguration == null) {
// Descriptor has not been set
return false;
}
byte[] notificationEnabled = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
return clientConfiguration.length == notificationEnabled.length
&& (clientConfiguration[0] & notificationEnabled[0]) == notificationEnabled[0]
&& (clientConfiguration[1] & notificationEnabled[1]) == notificationEnabled[1];
}
// Gatt Server Actions
public void log(String msg) {
Log.d(TAG, msg);
mLogHandler.post(() -> {
mBinding.viewServerLog.logTextView.append(msg + "\n");
mBinding.viewServerLog.logScrollView.post(() -> mBinding.viewServerLog.logScrollView.fullScroll(View.FOCUS_DOWN));
if (msg.contains("Open")) {
ToneGenerator toneGen1 = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
toneGen1.startTone(ToneGenerator.TONE_CDMA_PIP, 150);
} else if (msg.contains("Close")) {
ToneGenerator toneGen1 = new ToneGenerator(AudioManager.STREAM_MUSIC, 100);
toneGen1.startTone(ToneGenerator.TONE_CDMA_PIP, 150);
toneGen1.startTone(ToneGenerator.TONE_CDMA_PIP, 300);
}
});
}
public void addDevice(BluetoothDevice device) {
log("Device added: " + device.getAddress());
mHandler.post(() -> mDevices.add(device));
}
public void removeDevice(BluetoothDevice device) {
log("Device removed: " + device.getAddress());
mHandler.post(() -> {
mDevices.remove(device);
String deviceAddress = device.getAddress();
mClientConfigurations.remove(deviceAddress);
});
}
public void addClientConfiguration(BluetoothDevice device, byte[] value) {
String deviceAddress = device.getAddress();
mClientConfigurations.put(deviceAddress, value);
}
public void sendResponse(BluetoothDevice device, int requestId, int status, int offset, byte[] value) {
mGattServer.sendResponse(device, requestId, status, 0, null);
}
public void notifyCharacteristicEcho(byte[] value) {
notifyCharacteristic(value, CHARACTERISTIC_ECHO_UUID);
}
// Gatt Callback
private class GattServerCallback extends BluetoothGattServerCallback {
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
super.onConnectionStateChange(device, status, newState);
log("onConnectionStateChange " + device.getAddress()
+ "\nstatus " + status
+ "\nnewState " + newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
addDevice(device);
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
removeDevice(device);
}
}
// The Gatt will reject Characteristic Read requests that do not have the permission set,
// so there is no need to check inside the callback
@Override
public void onCharacteristicReadRequest(BluetoothDevice device,
int requestId,
int offset,
BluetoothGattCharacteristic characteristic) {
super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
log("onCharacteristicReadRequest " + characteristic.getUuid().toString());
if (BluetoothUtils.requiresResponse(characteristic)) {
// Unknown read characteristic requiring response, send failure
sendResponse(device, requestId, BluetoothGatt.GATT_FAILURE, 0, null);
}
// Not one of our characteristics or has NO_RESPONSE property set
}
// The Gatt will reject Characteristic Write requests that do not have the permission set,
// so there is no need to check inside the callback
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device,
int requestId,
BluetoothGattCharacteristic characteristic,
boolean preparedWrite,
boolean responseNeeded,
int offset,
byte[] value) {
super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
log("onCharacteristicWriteRequest" + characteristic.getUuid().toString()
+ "\nReceived: " + StringUtils.stringFromBytes(value));
if (CHARACTERISTIC_ECHO_UUID.equals(characteristic.getUuid())) {
sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
// Reverse message to differentiate original message & response
byte[] response = ByteUtils.reverse(value);
characteristic.setValue(response);
log("Sending: " + StringUtils.byteArrayInHexFormat(response));
notifyCharacteristicEcho(response);
}
}
// The Gatt will reject Descriptor Read requests that do not have the permission set,
// so there is no need to check inside the callback
@Override
public void onDescriptorReadRequest(BluetoothDevice device,
int requestId,
int offset,
BluetoothGattDescriptor descriptor) {
super.onDescriptorReadRequest(device, requestId, offset, descriptor);
log("onDescriptorReadRequest" + descriptor.getUuid().toString());
}
// The Gatt will reject Descriptor Write requests that do not have the permission set,
// so there is no need to check inside the callback
@Override
public void onDescriptorWriteRequest(BluetoothDevice device,
int requestId,
BluetoothGattDescriptor descriptor,
boolean preparedWrite,
boolean responseNeeded,
int offset,
byte[] value) {
super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
log("onDescriptorWriteRequest: " + descriptor.getUuid().toString()
+ "\nvalue: " + StringUtils.stringFromBytes(value));
if (CLIENT_CONFIGURATION_DESCRIPTOR_UUID.equals(descriptor.getUuid())) {
addClientConfiguration(device, value);
sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, null);
}
}
@Override
public void onNotificationSent(BluetoothDevice device, int status) {
super.onNotificationSent(device, status);
log("onNotificationSent");
}
}
}
答案 0 :(得分:0)
将Foreground服务与持久性通知一起使用。您的服务将继续运行。