写博客,整理下本身学的零散的知识。说得好不如作得好,开始!html
android使用蓝牙4.0的条件:Android API Level 要在18及以上,即android 4.3以上。java
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
android
其中,若是android.hardware.bluetooth_le设置为false,能够安装在不支持的设备上使用。
服务器
方法1:app
<span style="font-family:SimSun;font-size:12px;">if (!mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(mContext, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); return; }</span>
<span style="font-family:SimSun;">BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); BluetoothManager BmBluetoothAdapter = bluetoothManager.getAdapter(); if (mBluetoothAdapter == null) { Toast.makeText(mContext, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); }</span>
<span style="font-family:SimSun;">//true为强制打开成功,false为失败 public static boolean turnOnBluetooth() { BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter != null){ return bluetoothAdapter.enable(); } return false; }</span>
<span style="font-family:SimSun;"><pre name="code" class="java">public class MainActivity extends Activity{ //自定义的打开 Bluetooth 的请求码,与 onActivityResult 中返回的 requestCode 匹配。 private static final int REQUEST_CODE_BLUETOOTH_ON = 999; //Bluetooth 设备可见时间,单位:秒。 private static final int BLUETOOTH_DISCOVERABLE_DURATION = 300; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(R.layout.activity_main); if ((BluetoothManager.isBluetoothSupported()) && (!BluetoothManager.isBluetoothEnabled())){ this.turnOnBluetooth(); } } //弹出系统弹框提示用户打开 Bluetooth private void turnOnBluetooth() { // 请求打开 Bluetooth Intent requestBluetoothOn = new Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE); // 设置 Bluetooth 设备能够被其它 Bluetooth 设备扫描到 requestBluetoothOn.setAction(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); // 设置 Bluetooth 设备可见时间 requestBluetoothOn.putExtra( BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, BLUETOOTH_DISCOVERABLE_DURATION); // 请求开启 Bluetooth this.startActivityForResult(requestBluetoothOn, REQUEST_CODE_BLUETOOTH_ON); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data){ // requestCode 与请求开启 Bluetooth 传入的 requestCode 相对应 if (requestCode == REQUEST_CODE_BLUETOOTH_ON){ switch (resultCode){ // 点击确认按钮 case Activity.RESULT_OK: // 用户选择开启 Bluetooth,Bluetooth 会被开启 break; // 点击取消按钮或点击返回键 case Activity.RESULT_CANCELED: // TODO 用户拒绝打开 Bluetooth, Bluetooth 不会被开启 break; default: break; } } } }</span>
<span style="font-family:SimSun;">this.startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS)); </span>
<span style="font-family:SimSun;"> //强制关闭 Bluetooth 成功 false:强制关闭 Bluetooth 失败 public static boolean turnOffBluetooth(){ BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter != null){ return bluetoothAdapter.disable(); } return false; }</span>
<span style="font-family:SimSun;">this.startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS)); </span>
<span style="font-family:SimSun;"> private static final long SCAN_PERIOD = 10000; private void scanLeDevice(final boolean enable) { if (enable) { // Stops scanning after a pre-defined scan period. mHandler.postDelayed(new Runnable() { @Override public void run() { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); invalidateOptionsMenu(); } }, SCAN_PERIOD); mScanning = true; mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } }</span>
<span style="font-family:SimSun;">private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { runOnUiThread(new Runnable() { @Override public void run() { //经过这个device获取设备的name、address、uuid等信息 mLeDeviceListAdapter.addDevice(device); mLeDeviceListAdapter.notifyDataSetChanged(); } }); } };</span>
<span style="font-family:SimSun;">import java.util.List; import java.util.UUID; import android.app.Service; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; /** * 用来管理链接服务和数据托管在一个给定的蓝牙LE设备GATT服务器通讯 */ public class BluetoothLeService extends Service { private final boolean D = false; private final static String TAG = BluetoothLeService.class.getSimpleName(); private BluetoothManager mBluetoothManager; private BluetoothAdapter mBluetoothAdapter; private BluetoothGatt mBluetoothGatt; private String mBluetoothDeviceAddress; private int mConnectionState = STATE_DISCONNECTED; public int m_rssi; private static final int STATE_DISCONNECTED = 0; private static final int STATE_CONNECTING = 1; private static final int STATE_CONNECTED = 2; 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"; public final static String EXTRA_DATA = "com.example.bluetooth.le.EXTRA_DATA"; public final static UUID UUID_HEART_RATE_MEASUREMENT = UUID .fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT); public final static UUID UUID_ISSC_RX = UUID .fromString(SampleGattAttributes.ISSC_CHAR_RX_UUID); // 实现GATT的事件回调接口,例如:链接更改和服务发现 private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { String intentAction; if (newState == BluetoothProfile.STATE_CONNECTED) { intentAction = ACTION_GATT_CONNECTED; mConnectionState = STATE_CONNECTED; broadcastUpdate(intentAction); if (D) Log.i(TAG, "Connected to GATT server."); // Attempts to discover services after successful connection. boolean result = mBluetoothGatt.discoverServices(); if (D) Log.i(TAG, "Attempting to start service discovery:" + result); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { intentAction = ACTION_GATT_DISCONNECTED; mConnectionState = STATE_DISCONNECTED; if (D) Log.i(TAG, "Disconnected from GATT server."); broadcastUpdate(intentAction); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); } else { if (D) Log.e(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); } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); } @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { super.onReliableWriteCompleted(gatt, status); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { m_rssi = rssi; // Log.e("RSSI", "rssi: " + m_rssi); // super.onReadRemoteRssi(gatt, rssi, status); } }; private void broadcastUpdate(final String action) { final Intent intent = new Intent(action); sendBroadcast(intent); } private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) { final Intent intent = new Intent(action); // This is special handling for the Heart Rate Measurement profile. Data // parsing is // carried out as per profile specifications: // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { int flag = characteristic.getProperties(); int format = -1; if ((flag & 0x01) != 0) { format = BluetoothGattCharacteristic.FORMAT_UINT16; if (D) Log.d(TAG, "Heart rate format UINT16."); } else { format = BluetoothGattCharacteristic.FORMAT_UINT8; if (D) Log.d(TAG, "Heart rate format UINT8."); } final int heartRate = characteristic.getIntValue(format, 1); if (D) Log.d(TAG, String.format("Received heart rate: %d", heartRate)); // intent.putExtra(EXTRA_DATA, String.valueOf(heartRate)); intent.putExtra(EXTRA_DATA, String.valueOf(heartRate)); } else { // For all other profiles, writes the data formatted in HEX. final byte[] data = characteristic.getValue(); if (data != null && data.length > 0) { if (Public.b_ascii_mode) { intent.putExtra(EXTRA_DATA, new String(data) + "\n"); } else { final StringBuilder stringBuilder = new StringBuilder( data.length); for (byte byteChar : data) { stringBuilder.append(String.format("%02X ", byteChar)); } intent.putExtra(EXTRA_DATA, stringBuilder.toString() + "\n"); } } } sendBroadcast(intent); } public class LocalBinder extends Binder { BluetoothLeService getService() { return BluetoothLeService.this; } } @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public boolean onUnbind(Intent intent) { // 使用一个给定的设备以后,你应该确保 BluetoothGatt.close()在资源被彻底清理后执行的,在这个特定的示例中, // close() 应该是UI和服务已经断开的时候被调用 close(); return super.onUnbind(intent); } private final IBinder mBinder = new LocalBinder(); // 初始化蓝牙适配器 public boolean initialize() { // API 18及以上,就能够经过bluetoothmanager管理蓝牙适配器. if (mBluetoothManager == null) { mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (mBluetoothManager == null) { if (D) Log.e(TAG, "Unable to initialize BluetoothManager."); return false; } } mBluetoothAdapter = mBluetoothManager.getAdapter(); if (mBluetoothAdapter == null) { if (D) Log.e(TAG, "Unable to obtain a BluetoothAdapter."); return false; } return true; } /** * 链接到托管在BLE设备的GATT服务器。 * * @param adress * * @return 若是链接成功启动,则返回true。经过回调异步报告链接结果。 */ public boolean connect(final String address) { if (mBluetoothAdapter == null || address == null) { if (D) Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); return false; } if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) { if (D) Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection."); if (mBluetoothGatt.connect()) { mConnectionState = STATE_CONNECTING; return true; } else { return false; } } final BluetoothDevice device = mBluetoothAdapter .getRemoteDevice(address); if (device == null) { if (D) Log.w(TAG, "Device not found. Unable to connect."); return false; } // 直接链接到设备,因此咱们设置自动链接参数为false。 mBluetoothGatt = device.connectGatt(this, false, mGattCallback); if (D) Log.d(TAG, "Trying to create a new connection."); mBluetoothDeviceAddress = address; mConnectionState = STATE_CONNECTING; return true; } public void update_rssi() { if (mBluetoothGatt != null) { mBluetoothGatt.readRemoteRssi(); } } public int get_rssi() { return m_rssi; } /** * Disconnects an existing connection or cancel a pending connection. The * disconnection result is reported asynchronously through the callback. * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * */ public void disconnect() { if (mBluetoothAdapter == null || mBluetoothGatt == null) { if (D) Log.w(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.disconnect(); } /** * After using a given BLE device, the app must call this method to ensure * resources are released properly. */ public void close() { if (mBluetoothGatt == null) { return; } mBluetoothGatt.close(); mBluetoothGatt = null; } /** * Request a read on a given {@code BluetoothGattCharacteristic}. The read * result is reported asynchronously through the * {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)} * callback. * * @param characteristic * The characteristic to read from. */ public void readCharacteristic(BluetoothGattCharacteristic characteristic) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { if (D) Log.w(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.readCharacteristic(characteristic); } public void writeCharacteristic(BluetoothGattCharacteristic characteristic, byte[] value) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); } final int charaProp = characteristic.getProperties(); if ((charaProp | BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0) { characteristic .setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); } else { characteristic .setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); } characteristic.setValue(value); mBluetoothGatt.writeCharacteristic(characteristic); // mBluetoothGatt.beginReliableWrite(); // mBluetoothGatt.executeReliableWrite(); } /** * Enables or disables notification on a give characteristic. * * @param characteristic * Characteristic to act on. * @param enabled * If true, enable notification. False otherwise. */ public void setCharacteristicNotification( BluetoothGattCharacteristic characteristic, boolean enabled) { if (mBluetoothAdapter == null || mBluetoothGatt == null) { if (D) Log.w(TAG, "BluetoothAdapter not initialized"); return; } mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); // This is specific to Heart Rate Measurement. if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) { BluetoothGattDescriptor descriptor = characteristic .getDescriptor(UUID .fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); descriptor .setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor); } if (UUID_ISSC_RX.equals(characteristic.getUuid())) { BluetoothGattDescriptor descriptor = characteristic .getDescriptor(UUID .fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); if (descriptor != null) { descriptor .setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor); } } } /** * Retrieves a list of supported GATT services on the connected device. This * should be invoked only after {@code BluetoothGatt#discoverServices()} * completes successfully. * * @return A {@code List} of supported services. */ public List<BluetoothGattService> getSupportedGattServices() { if (mBluetoothGatt == null) return null; return mBluetoothGatt.getServices(); } } </span>
<span style="font-family:SimSun;"> Intent gattServiceIntent = new Intent(this,BicycleBluetoothService.class); bindService(gattServiceIntent, mBicycleServiceConnection,BIND_AUTO_CREATE); Public.bicycle_ascii_mode = false; mHandler = new Handler(); registerReceiver(mBicycleGattUpdateReceiverBicycle,makeBicycleGattUpdateIntentFilter());</span>