Android的蓝牙开发,包括蓝牙的广播事件和扫描,蓝牙配对连接、数据传输等问题,本文着重讲BLE低功耗蓝牙4.0开发
AndroidMainifest权限:
<uses-sdk
android:minSdkVersion="18"
android:targetSdkVersion="19" />
<!--蓝牙权限-->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!--Android 5.0以上蓝牙好需要位置权限-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="andriod.permission.ACCESS_FINE_LOCATION"/>
<!--设备支持BLE低功耗蓝牙 true -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"></uses-feature>
△低功耗蓝牙4.0开发:源码
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import android.app.Activity;
import android.app.AlertDialog;
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.BluetoothProfile;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.pm.PackageManager;
public class MainActivity extends Activity {
private BluetoothAdapter mBluetoothAdapter;
private Handler mHandler=new Handler();
private boolean mScanning;
private BluetoothGatt mGatt;
private BluetoothGattCharacteristic mGattCharacteristic;
private ListView mlv;//自定义列表listview
private BleAdapter mBleAdapter;//自定义适配器adapter
private ArrayList<BluetoothDevice> mArray=new ArrayList<BluetoothDevice>();//自定义容器
private EditText mEdit;//自定义edittext
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initUI();
initBLE();
}
@Override
protected void onDestroy() {
if(mGatt!=null){
mGatt.close();
mGatt=null;
}
super.onDestroy();
}
//初始化自定义控件
private void initUI(){
findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mGatt!=null){
mGatt.close();
mGatt=null;
}
scanLe(true);
}
});
mlv = (ListView) findViewById(R.id.listView1);
mBleAdapter = new BleAdapter(MainActivity.this,mArray);
mlv.setAdapter(mBleAdapter);
mlv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
if(mGatt==null){
mGatt = mArray.get(position).connectGatt(MainActivity.this, false, mGattCallback);
}else{
mGatt.connect();
}
new AlertDialog.Builder(MainActivity.this)
.setTitle("请输入内容")
.setView(mEdit=new EditText(MainActivity.this))
.setPositiveButton("确定", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mGattCharacteristic.setValue(mEdit.getText().toString().trim());
mGatt.writeCharacteristic(mGattCharacteristic);
}
})
.show();
}
});
}
//初始化蓝牙4.0
private void initBLE() {
//如果不支持BLE则退出程序
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this,"不支持低功耗蓝牙", Toast.LENGTH_SHORT).show();
finish();
}
//获取蓝牙适配器打开蓝牙
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter!=null&&!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();//自动打开蓝牙
}
}
//开始扫描BLE
private void scanLe(boolean enable) {
if (enable) {
if (mBluetoothAdapter.isEnabled()) {
if (mScanning){
return;
}
mArray.clear();
mScanning = true;
mHandler.postDelayed(mScanRunnable, 5000);//5秒后关闭扫描
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
Toast.makeText(this,"蓝牙检测中", Toast.LENGTH_SHORT).show();
}
} else {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mHandler.removeCallbacks(mScanRunnable);
mScanning = false;
}
}
//停止扫描BLE
private final Runnable mScanRunnable = new Runnable() {
@Override
public void run() {
scanLe(false);
}
};
//扫描结果
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
/**@param device:识别的远程设备
* @param rssi: 信号值为远程蓝牙设备的报告,0代表没有蓝牙设备
* @param scanRecord:远程设备提供的配对号
*/
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
//保存到本地:用来展示扫描得到的内容
if(!mArray.contains(device)){
Log.e("onLeScan","===设备"+device.getName()+"="+device.getAddress()+"="+rssi);
mArray.add(device);
mBleAdapter.notifyDataSetChanged();
}
}
});
}
};
//通知
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled){
mGatt.setCharacteristicNotification(characteristic, enabled);
BluetoothGattDescriptor clientConfig = characteristic.getDescriptor
(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if (enabled){
clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
}else{
clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
}
mGatt.writeDescriptor(clientConfig);
}
//数据通讯监听
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {//启动服务状态
Log.e("======", "===开始启动服务:" + gatt.discoverServices());
}
};
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS){//发现服务状态
Log.e("======", "===发现服务");
List<BluetoothGattService> services = mGatt.getServices();
for(final BluetoothGattService gattService:services) {
List<BluetoothGattCharacteristic> characteristics = gattService.getCharacteristics();
for (final BluetoothGattCharacteristic gattCharacteristic : characteristics) {
if (gattCharacteristic.getUuid().toString().equals
("0000ffe1-0000-1000-8000-00805f9b34fb")){
mGattCharacteristic=gattCharacteristic;
mHandler.postDelayed(new Runnable(){
@Override
public void run()
{
gatt.readCharacteristic(gattCharacteristic);
}
}, 200);
setCharacteristicNotification(gattCharacteristic,true);
List<BluetoothGattDescriptor> descriptors = gattCharacteristic.getDescriptors();
for (BluetoothGattDescriptor descriptor : descriptors)
{
gatt.readDescriptor(descriptor);
}
}
}
}
}
};
public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {//写入状态
Log.e("======", "===写入" +new String(characteristic.getValue()));
}
};
public void onCharacteristicRead(BluetoothGatt gatt,final BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {//读取状态
Log.e("======","===读取" +new String(characteristic.getValue()));
}
}
public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {
Log.e("======", "===获取数据" +new String(characteristic.getValue()));//获取数据
};
};
}
/**
* 蓝牙限制20字节需将数据分包
* **/
public int[] dataSeparate(int len)
{
int[] lens = new int[2];
lens[0]=len/20;
lens[1]=len-20*lens[0];
return lens;
}
/*
* 发送按键的响应事件,主要发送文本框的数据
*/
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
byte[] buff = send_et.getText().toString().getBytes();
int len = buff.length;
int[] lens = dataSeparate(len);
for(int i =0;i<lens[0];i++)
{
String str = new String(buff, 20*i, 20);
mGattCharacteristic.setValue(str);//只能一次发送20字节,所以这里要分包发送
//调用蓝牙服务的写特征值方法实现发送数据
mBluetoothLeService.writeCharacteristic(mGattCharacteristic);
}
if(lens[1]!=0)
{
String str = new String(buff, 20*lens[0], lens[1]);
mGattCharacteristic.setValue(str);
//调用蓝牙服务的写特征值方法实现发送数据
mBluetoothLeService.writeCharacteristic(mGattCharacteristic);
}
}
传统蓝牙:
1.打开蓝牙设备BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.cancelDiscovery();
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(mReceiver, filter);
mBluetoothAdapter.startDiscovery();//搜索附近蓝牙
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)){
//找到设备时 通过EXTRA_DEVICE附加域来得到一个BluetoothDevice设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//信号强度
int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI,Short.MIN_VALUE);
}else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){
//蓝牙配对或取消配对时的状态
}
}
};
device.connectGatt(act, false, new BluetoothGattCallback() {
public void onConnectionStateChange(android.bluetooth.BluetoothGatt gatt, int status, int newState) {
if(status == 0&&newState == 2) {
gatt.discoverServices();//搜索蓝牙周围服务
}else{
//"搜索失败"
}
};
public void onServicesDiscovered(android.bluetooth.BluetoothGatt gatt, int status) {
if(status == BluetoothGatt.GATT_SUCCESS){
Iterator var4 = gatt.getServices().iterator();
while(var4.hasNext()) {
BluetoothGattService var3;
BluetoothGattCharacteristic var5;
BluetoothGattService next = (BluetoothGattService)var4.next();
if((var3 = next).getUuid().equals(UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb"))
&& (var5 = var3.getCharacteristic(UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb"))) != null) {
gatt.readCharacteristic(var5);
//"获取电量中…"
}
}
}
};
public void onCharacteristicRead(final android.bluetooth.BluetoothGatt gatt, final android.bluetooth.BluetoothGattCharacteristic characteristic, final in t status) {
act.runOnUiThread(new Runnable() {
@Override
public void run() {
if(characteristic!=null&&status == BluetoothGatt.GATT_SUCCESS){
//characteristic.getIntValue(17, 0)+"%电量"
gatt.close();
}
}
});
};
} );
/**
* 根据Rssi获得返回的距离,返回数据单位为m
* @param rssi
* @return
*/
public static double getDistance(int rssi){
int iRssi = Math.abs(rssi);
double power = (iRssi-A_Value)/(10*n_Value); //A_Value=59发射端和接收端相隔1米时的信号强度,n_Value=2.0环境衰减因子
return Math.pow(10,power);
}
2.蓝牙连接有两种方式,可直接配对
String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
UUID uuid = UUID.fromString(SPP_UUID);
mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(macAddress);
BluetoothSocket socket= mBluetoothDevice.createRfcommSocketToServiceRecord(uuid);//UUID连接!服务端为listenUsingRfcommWithServiceRecord("name",uuid)
mBluetoothAdapter.cancelDiscovery();
socket.connect();
mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(macAddress);
Method m = mBluetoothDevice.getClass().getMethod(
"createRfcommSocket", new Class[] { int.class });
BluetoothSocket socket = (BluetoothSocket) m.invoke(mBluetoothDevice, 1);//1-30端口连接!
mBluetoothAdapter.cancelDiscovery();
socket.connect();
Method method = mBluetoothDevice.getClass().getMethod("createBond");//配对createBond/取消配对removeBond
Boolean returnValue = (Boolean) method.invoke(mBluetoothDevice);
3.蓝牙数据传输getInputStream getOutputStream
os = accept.getOutputStream();//输出流
os.write("连接成功success".getBytes());
is = socket.getInputStream();//输入流
byte[] buffer=new byte[512];
int len=0;
ByteArrayBuffer bab = new ByteArrayBuffer(len);
while(-1!=(len=is.read(buffer))){
bab.append(buffer, 0, len);
}
String string = new String(bab.toByteArray(),"utf-8");
注意:BluetoothSocket的等耗时操作需要另外开启线程再进行!!!