Android BLE广播设备端蓝牙接收器无法接收GATT连接广播问题
Android BLE广播端无法接收连接状态广播问题
这是我开发的首个Android蓝牙相关应用,目前遇到了一个较为特殊的问题:对外广播BLE服务的设备上,蓝牙广播接收器无法正常工作。
我同时使用两台手机测试该应用,为便于说明分别命名为手机A和B。首先我在手机A上启动BLE广播,随后在手机B上启动设备扫描,最后点击手机B上的发送数据按钮。该按钮按下后会首先发起GATT连接,连接成功后应该发送一条广播确认连接状态。我在BroadcastReceiver中添加了Log来监听该广播,最终仅能在手机B的logcat中看到对应日志输出,手机A的logcat中无相关内容。
我查阅了大量示例代码和StackOverflow上的相关帖子,仍未找到该问题的解决方案。
我目前尚未定位到问题根因,可能是我对蓝牙相关类的使用存在错误,或是相关知识储备不足。下面附上该简易项目唯一的类MainActivity的完整代码。
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private TextView mText; private Button mAdvertiseButton; private Button mDiscoverButton; private Button mSendButton; private String TAG = "INFOBLERESULTS"; private BluetoothLeScanner mBluetoothLeScanner; private BluetoothDevice bluetoothDevice; private Handler mHandler = new Handler(); private ScanCallback mScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { Log.d(TAG, result.getDevice().getAddress()); super.onScanResult(callbackType, result); if( result == null || result.getDevice() == null || TextUtils.isEmpty(result.getDevice().getAddress()) ) return; StringBuilder builder = new StringBuilder( result.getDevice().getAddress() ); builder.append("\n").append(result.getDevice().getName()); //builder.append("\n").append(new String(result.getScanRecord().getServiceData(result.getScanRecord().getServiceUuids().get(0)), Charset.forName("UTF-8"))); mText.setText(builder.toString()); bluetoothDevice = result.getDevice(); bluetoothLeService = new BluetoothLeService(); bluetoothLeService.setAddress(result.getDevice().getAddress()); } @Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); } @Override public void onScanFailed(int errorCode) { Log.e( TAG, "Discovery onScanFailed: " + errorCode ); super.onScanFailed(errorCode); } }; private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); private boolean connected = false; //Inner classes class BluetoothLeService extends Service { public final static String ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED"; public final static String ACTION_GATT_DISCONNECTED = "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED"; public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED"; public final static String ACTION_DATA_AVAILABLE = "com.example.bluetooth.le.ACTION_DATA_AVAILABLE"; private static final int STATE_DISCONNECTED = 0; private static final int STATE_CONNECTED = 2; private int connectionState; public Context ctx; protected BluetoothGatt bluetoothGatt; protected final BluetoothGattCallback gattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { Log.i(TAG, "GATT status = "+ status + " newState = " + newState); if(status == BluetoothGatt.GATT_SUCCESS){ if (newState == BluetoothProfile.STATE_CONNECTED) { // successfully connected to the GATT Server connectionState = STATE_CONNECTED; broadcastUpdate(ACTION_GATT_CONNECTED); bluetoothGatt = gatt; } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { // disconnected from the GATT Server connectionState = STATE_DISCONNECTED; broadcastUpdate(ACTION_GATT_DISCONNECTED); gatt.close(); } }else{ gatt.close(); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); } else { Log.w(TAG, "onServicesDiscovered received: " + status); } } @Override public void onCharacteristicRead( BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status ) { if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); } } @Override public void onCharacteristicChanged( BluetoothGatt gatt, BluetoothGattCharacteristic characteristic ) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); } }; private Binder binder = new LocalBinder(); private String address = ""; public void setAddress(String address) { this.address = address; } @Nullable @Override public IBinder onBind(Intent intent) { return binder; } @Override public boolean onUnbind(Intent intent) { close(); return super.onUnbind(intent); } private void close() { if (bluetoothGatt == null) { return; } bluetoothGatt.close(); bluetoothGatt = null; } public boolean connect() { if (bluetoothAdapter == null || this.address == null || this.address.equals("")) { Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); return false; } try { final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address); bluetoothGatt = device.connectGatt(MainActivity.this.getApplicationContext(), false, gattCallback); Log.d(TAG,"GATT "+ bluetoothGatt); return true; } catch (IllegalArgumentException exception) { Log.w(TAG, "Device not found with provided address."); return false; } } private void broadcastUpdate(final String action) { final Intent intent = new Intent(action); Log.i(TAG, intent + ""); MainActivity.this.getApplicationContext().sendBroadcast(intent); } private void broadcastUpdate(final String action, BluetoothGattCharacteristic characteristic) { final Intent intent = new Intent(action); sendBroadcast(intent); } public List<BluetoothGattService> getSupportedGattServices() { if (bluetoothGatt == null) return null; return bluetoothGatt.getServices(); } public void readCharacteristic(BluetoothGattCharacteristic characteristic) { if (bluetoothGatt == null) { Log.w(TAG, "BluetoothGatt not initialized"); return; } bluetoothGatt.readCharacteristic(characteristic); } public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,boolean enabled) { if (bluetoothGatt == null) { Log.w(TAG, "BluetoothGatt not initialized"); return; } bluetoothGatt.setCharacteristicNotification(characteristic, enabled); } class LocalBinder extends Binder { public BluetoothLeService getService() { return BluetoothLeService.this; } } } private BluetoothLeService bluetoothLeService = new BluetoothLeService(); private final ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { bluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService(); if (bluetoothLeService != null) { if (!bluetoothAdapter.isEnabled()) { Log.e(TAG, "Unable to initialize Bluetooth"); } else{ bluetoothLeService.connect(); Log.i(TAG, "Service connected"); } } } @Override public void onServiceDisconnected(ComponentName name) { bluetoothLeService = null; } }; private final BroadcastReceiver gattUpdateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); Log.d(TAG, "RECEIVED " + action); if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { connected = true; //Log.d(TAG, "CONNECTED"); } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) { connected = false; //Log.d(TAG, "DISCONNECTED"); } } }; private final ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { Log.i("RESULT", result.getResultCode() + ""); setup(); } }); private void setup() { bluetoothLeService.ctx = this.getApplicationContext(); Log.d("APPLICATIONCONTEXT", bluetoothLeService.ctx + ""); mDiscoverButton.setOnClickListener(this); mAdvertiseButton.setOnClickListener(this); mSendButton.setOnClickListener(this); mBluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner(); if (!BluetoothAdapter.getDefaultAdapter().isMultipleAdvertisementSupported()) { Toast.makeText(this, "Multiple advertisement not supported", Toast.LENGTH_SHORT).show(); mAdvertiseButton.setEnabled(false); mDiscoverButton.setEnabled(false); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull @org.jetbrains.annotations.NotNull String[] permissions, @NonNull @org.jetbrains.annotations.NotNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 2) { final LocationManager manager = (LocationManager) getSystemService( Context.LOCATION_SERVICE ); if(!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)){ Intent enableLocationIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); someActivityResultLauncher.launch(enableLocationIntent); } else{ setup(); } } } @RequiresApi(api = Build.VERSION_CODES.M) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mText = (TextView) findViewById( R.id.text ); mDiscoverButton = (Button) findViewById( R.id.discover_btn ); mAdvertiseButton = (Button) findViewById( R.id.advertise_btn ); mSendButton = (Button) findViewById( R.id.send_btn ); this.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 2); } @Override protected void onResume() { super.onResume(); MainActivity.this.getApplicationContext().registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter()); } @Override protected void onPause() { super.onPause(); MainActivity.this.getApplicationContext().unregisterReceiver(gattUpdateReceiver); } @Override public void onClick(View v) { Log.d(TAG, getString( R.string.ble_uuid )); if( v.getId() == R.id.discover_btn ) { discover(); } else if( v.getId() == R.id.advertise_btn ) { advertise(); //MainActivity.this.getApplicationContext().registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter()); } else if (v.getId() == R.id.send_btn){ //MainActivity.this.getApplicationContext().unregisterReceiver(gattUpdateReceiver); send(); } } public void advertise(){ BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser(); AdvertiseSettings settings = new AdvertiseSettings.Builder().setTimeout(0) .setAdvertiseMode( AdvertiseSettings.ADVERTISE_MODE_BALANCED ) .setTxPowerLevel( AdvertiseSettings.ADVERTISE_TX_POWER_HIGH ) .setConnectable( true ) .build(); ParcelUuid pUuid = ParcelUuid.fromString( getString( R.string.ble_uuid ) ) ; AdvertiseData data = new AdvertiseData.Builder() .addServiceUuid( pUuid ).setIncludeDeviceName(false) .build(); AdvertiseCallback advertisingCallback = new AdvertiseCallback() { @Override public void onStartSuccess(AdvertiseSettings settingsInEffect) { Log.d(TAG, "START ADVERTISING"); super.onStartSuccess(settingsInEffect); } @Override public void onStartFailure(int errorCode) { Log.e( TAG, "Advertising onStartFailure: " + errorCode ); super.onStartFailure(errorCode); } }; advertiser.startAdvertising( settings, data, advertisingCallback ); } public void discover(){ ScanFilter filter = new ScanFilter.Builder() .setServiceUuid( ParcelUuid.fromString( getString(R.string.ble_uuid ) ) ) .build(); List<ScanFilter> filters = new ArrayList<>(); filters.add( filter ); ScanSettings settings = new ScanSettings.Builder() .setScanMode( ScanSettings.SCAN_MODE_BALANCED ) .build(); mBluetoothLeScanner.startScan(filters, settings, mScanCallback); Log.d(TAG, "Discovery started"); mHandler.postDelayed(new Runnable() { @Override public void run() { Log.d(TAG, "Discovery stopped"); mBluetoothLeScanner.stopScan(mScanCallback); } }, 10000); } public void send(){ Log.d(TAG, "START CONNECTIONG GATT"); mBluetoothLeScanner.stopScan(mScanCallback); //boundGatt(); connectGatt(); } public void boundGatt(){ Intent gattServiceIntent = new Intent(MainActivity.this.getApplicationContext(), BluetoothLeService.class); bindService(gattServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE); } public void connectGatt(){ bluetoothLeService.connect(); } private static IntentFilter makeGattUpdateIntentFilter() { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED); intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE); return intentFilter; } }
内容的提问来源于stack exchange,提问作者Andrea Pantieri
相关产品推荐
相关产品推荐

