Android - 蓝牙接收器无法在广告设备上工作
Android - Bluetooth receiver not working on advertising device
这是我在 Androind 中使用蓝牙的第一个应用程序,我遇到了一个独特的问题:蓝牙接收器无法在宣传蓝牙服务的设备上工作。
我在 2 phone 秒内同时测试了该应用程序(我将它们称为 phone A 和 B 以便更好地解释)。首先我用 phone A 开始广告,然后我用 phone B 开始发现,最后我按下 phone B 中的按钮发送数据。这个按钮应该首先启动 Gatt 连接,如果它正在工作,它应该广播一条确认连接的消息。为了看到它,我在广播接收器中使用了一个日志,但我得到的结果是这个 messsagge 只出现在 phone B 的 logcat 中,而不是 phone A 中的一个。
我在 Whosebug 上查看了很多示例和 post,但我似乎无法找到解决此问题的方法。
所以我真的找不到这里真正的问题是什么。也许我只是使用不好蓝牙 classes 或者我只是缺乏知识。无论如何,这里有 MainActivity 的所有代码,因为它是这个简单项目的唯一 class。
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;
}
}
你的外设(phoneA)只做广告,但是BluetoothGattServer
没有设置。这可能是所描述行为的原因 - 广告和扫描有效,但连接无效。
BluetoothGatt
+ BluetoothGattCallback
用于 Central 角色(你称之为 phone B)。
BluetoothGattServer
+ BluetoothGattServerCallback
用于外围设备 (phone A)。
备注:
- 来自中央端的连接(phone B)看起来不错,因为当找到广告设备时,您使用
bluetoothAdapter.getRemoteDevice(address)
获取它,然后调用 device.connectGatt
- 要传输一些数据,您需要将带有 BluetoothGattCharacteristic 的 BluetoothGattService 添加到您的 BluetoothGattServer - example of setup in Kotlin
- github 上的示例 项目:BLEProof - 它在 Kotlin 中,2 个应用程序相互通信:Central 和 Peripheral,所有代码都在 MainActivity.kt
这是我在 Androind 中使用蓝牙的第一个应用程序,我遇到了一个独特的问题:蓝牙接收器无法在宣传蓝牙服务的设备上工作。
我在 2 phone 秒内同时测试了该应用程序(我将它们称为 phone A 和 B 以便更好地解释)。首先我用 phone A 开始广告,然后我用 phone B 开始发现,最后我按下 phone B 中的按钮发送数据。这个按钮应该首先启动 Gatt 连接,如果它正在工作,它应该广播一条确认连接的消息。为了看到它,我在广播接收器中使用了一个日志,但我得到的结果是这个 messsagge 只出现在 phone B 的 logcat 中,而不是 phone A 中的一个。
我在 Whosebug 上查看了很多示例和 post,但我似乎无法找到解决此问题的方法。
所以我真的找不到这里真正的问题是什么。也许我只是使用不好蓝牙 classes 或者我只是缺乏知识。无论如何,这里有 MainActivity 的所有代码,因为它是这个简单项目的唯一 class。
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;
}
}
你的外设(phoneA)只做广告,但是BluetoothGattServer
没有设置。这可能是所描述行为的原因 - 广告和扫描有效,但连接无效。
BluetoothGatt
+ BluetoothGattCallback
用于 Central 角色(你称之为 phone B)。
BluetoothGattServer
+ BluetoothGattServerCallback
用于外围设备 (phone A)。
备注:
- 来自中央端的连接(phone B)看起来不错,因为当找到广告设备时,您使用
bluetoothAdapter.getRemoteDevice(address)
获取它,然后调用device.connectGatt
- 要传输一些数据,您需要将带有 BluetoothGattCharacteristic 的 BluetoothGattService 添加到您的 BluetoothGattServer - example of setup in Kotlin
- github 上的示例 项目:BLEProof - 它在 Kotlin 中,2 个应用程序相互通信:Central 和 Peripheral,所有代码都在 MainActivity.kt