本文主要展示一个Android蓝牙4.0的开发示例。
一.蓝牙4.0
蓝牙4.0应用的设备一般是比较特殊的设备,比如低耗能蓝牙灯泡。并且使用的类的方法也是有点不同的。
BlueToothAdapter这个类是蓝牙设备的管理类。
BlueToothDevice蓝牙设备对象,里面包含蓝牙的数据。
上面两个类蓝牙设备都会有用到,下面这两个类只有蓝牙4.0才能用到。
BlueToothGatt低耗能蓝牙设备的控制对象
BlueToothGattCharateristic低耗能蓝牙设备的特征值对象
二.下面展示一个蓝牙灯泡的程序设计示例
这个蓝牙灯泡是低耗能蓝牙设备,需要支持蓝牙4.0的手机,Android版本需要以上4.3就可以了。
开发蓝牙设备时,蓝牙的传输协议也是要理解的,这个简单说一下,比如这个蓝牙灯泡,它的协议字段是一个十七位的byte数组,其中数组的第二三四六个数组的值,分别是控制RGB和光亮度,所以控制上面数组的四个值,就可以改变蓝牙灯泡的颜色的改变。
下面的代码:
(一)权限
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<!--6.0以上才要加的额外权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
(二)设备选择的页面
package fuxi.bluetooth40;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
/**
* 设备选择页面
*/
public class DevicesActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
private static final int REQUEST_ENABLE = 1001;//请求打开蓝牙的请求码
private static final int REQUEST_LOCATION = 1002;//请求扫描显示设备的请求码
BluetoothAdapter bluetoothAdapter;//蓝牙管理器
ArrayAdapter<String> adapter;//列表的适配器
List<BluetoothDevice> devices = new ArrayList();//列表的对象
List<String> deviceNames = new ArrayList<>();//列表对象的数据
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ListView lv = new ListView(this);
setContentView(lv);//显示列表视图
//实例化适配器
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, deviceNames);
//给列表设置适配器
lv.setAdapter(adapter);
requestPer();//权限的请求
lv.setOnItemClickListener(this);//给List列表设置点击事件
}
/**
* 权限的请求方法
*/
private void requestPer() {
if (Build.VERSION.SDK_INT >= 23) {
int check = checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION);
if (check != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_LOCATION);
} else {
//有了权限,就扫描蓝牙设备
checkBlue();
}
} else {
//版本低于6。0
checkBlue();
}
}
/**
* 请求权限后的回调方法
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//成功了,扫描蓝牙
checkBlue();
} else {
setResult(RESULT_CANCELED);
finish();
}
}
/**
* 重写onResume方法,进行广播接收者的注册
*/
@Override
protected void onResume() {
super.onResume();
registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
}
/**
* 重写生命周期的onPause方法,进行广播接收者的注销
*/
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
/**
* 创建广播接收者
* //获取设备广播
*/
private BroadcastReceiver receiver = new BroadcastReceiver() {
//收到广播后的回调方法
@Override
public void onReceive(Context context, Intent intent) {
//获取设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
devices.add(device);//添加蓝牙设备对象
//添加蓝牙设备名称
deviceNames.add(TextUtils.isEmpty(device.getName()) ? "未命名" : device.getName());
Toast.makeText(DevicesActivity.this,"",Toast.LENGTH_SHORT).show();
adapter.notifyDataSetChanged();//刷新适配器
}
};
/**
* 蓝牙设备的扫描操作,并显示在视图列表中
*/
public void checkBlue() {
//是否打开了蓝牙
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter.isEnabled()) {//蓝牙已经就绪,可以进行扫描
deviceNames.clear();
devices.clear();
adapter.notifyDataSetChanged();
//开始扫描设置,扫描完成后会系统自动发送广播
bluetoothAdapter.startDiscovery();
} else {//蓝牙还没有就绪,要先打开蓝牙
openBlue();
}
}
/**
* 打开蓝牙设备
*/
private void openBlue() {
//打开蓝牙
startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), REQUEST_ENABLE);
}
/**
* 请求打开蓝牙后返回的回调方法方法
* 进行扫描蓝牙设备操作
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
checkBlue();
}
/**
* 点击列表视图的回调方法
* 这里只能选择固定产品的设备,选择其他的就提示重选
*/
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
BluetoothDevice device = devices.get(position);
//KQX
if (device.getName().startsWith("KQX")) {
setResult(RESULT_OK, getIntent().putExtra("device", device));//传递数据,这个对象已经序列化过了
finish();
} else {
Toast.makeText(this, "请选择卡丘熊蓝牙灯", Toast.LENGTH_SHORT).show();
}
}
}
(三)主页面显示的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="test"
android:text="校验" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="rgb"
android:text="测试颜色" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="loop"
android:text="循环显示" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="stopLoop"
android:text="取消循环显示" />
</LinearLayout>
(四)设备控制的页面
package fuxi.bluetooth40;
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.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import java.util.List;
/**
* Android蓝牙4.0演示使用
*/
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_DEVICE = 1000;//设备选择页面的请求码
BluetoothDevice device;//蓝牙设备对象
BluetoothGatt gatt;//低耗能蓝牙设备对象
BluetoothGattCharacteristic writer;//耗能设备的输入的特征值
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startActivityForResult(new Intent(this, DevicesActivity.class), REQUEST_DEVICE);
}
/**
* 测试
*/
public void test(View v) {
//发送数据
// byte[] buf = getBuf((byte) 0x30);
// byte[] buf = {0x55, (byte) 0xaa, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
byte[] buf = new byte[17];
buf[0] = 0x55;
buf[1] = (byte) 0xaa;
buf[2] = 0x30;
writer.setValue(buf);
gatt.writeCharacteristic(writer);
}
/**
* 改变颜色
*/
public void rgb(View v) {
int r = (int) (Math.random() * 255);
int g = (int) (Math.random() * 255);
int b = (int) (Math.random() * 255);
byte[] buf = getBuf(new byte[]{0x07, (byte) r, (byte) g, (byte) b, 0x00, (byte) 0x80});
writer.setValue(buf);
gatt.writeCharacteristic(writer);
}
/**
* 循环改变颜色
*/
public void loop(View v) {
handler.sendEmptyMessageDelayed(1,1000);
}
/**
* 取消循环改变颜色
*/
public void stopLoop(View v) {
handler.removeMessages(1);
}
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
changeLoop();
handler.sendEmptyMessageDelayed(1,1000);
}
};
private void changeLoop(){
int r = (int) (Math.random() * 255);
int g = (int) (Math.random() * 255);
int b = (int) (Math.random() * 255);
byte[] buf = getBuf(new byte[]{0x07, (byte) r, (byte) g, (byte) b, 0x00, (byte) 0x80});
writer.setValue(buf);
gatt.writeCharacteristic(writer);
}
/**
* 蓝牙设备连接后的回调方法
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_DEVICE && resultCode == RESULT_OK) {
device = data.getParcelableExtra("device");
if (device != null)
conn();//连接这个低耗能蓝牙设备
} else {
finish();
}
}
/**
* 连接低耗能蓝牙设备的方法
*/
private void conn() {
//BLE连接过程,这里需要最低版本是API是18,也就是android4.3以后的手机
//第一个参数上下文
//第二个参数是否自动连接
//第三个参数连接后的回调方法
gatt = device.connectGatt(this, false, mGattCallback);
//连接
gatt.connect();
}
/**
* 连接蓝牙时,连接的回调接口
*/
BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
//选择部分需要的回调方法
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
Log.e("TAG", "-------------------->>第一步");
Log.e("TAG", "----------->onConnectionStateChange");
//获取服务 获取设备电量 获取设备名称
gatt.discoverServices();
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
//获取低耗能蓝牙设备对象
List<BluetoothGattService> services = gatt.getServices();
for (BluetoothGattService service : services) {
Log.e("TAG", "---------------" + service.getUuid());
for (BluetoothGattCharacteristic bluetoothGattCharacteristic : service.getCharacteristics()) {
Log.e("TAG", "------------->>>" + bluetoothGattCharacteristic.getUuid());
}
}
Log.e("TAG", "----------->>onServicesDiscovered");
//获得需要的数据
//这里是设备对象的第三个服务的第一个特征值,用来数据的设置
writer = services.get(2).getCharacteristics().get(0);
//这里是设备对象的第三个服务的第二个特征值,用来数据的读取
BluetoothGattCharacteristic reader = gatt.getServices().get(2).getCharacteristics().get(1);
//打开读取开关
Log.e("TAG", "----------->>获取到特征值");
for (BluetoothGattDescriptor descriptor : reader.getDescriptors()) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
}
gatt.setCharacteristicNotification(reader, true);
}
};
/**
* 设置,获取协议数据
*/
public byte[] getBuf(byte... buf) {
byte[] bufs = new byte[17];
//两位协议头
bufs[0] = 0x55;
bufs[1] = (byte) 0xaa;
//协议命令共14个,不足补0
if (buf != null && buf.length > 0) {
for (int i = 0; i < buf.length; i++) {
bufs[2 + i] = buf[i];//从第三个开始设置
}
}
return bufs;
}
}
程序运行后先显示的是选择蓝牙设备的ListView页面,选择对的蓝牙设备,然后进入蓝牙设备控制页面,点击按钮就可以对蓝牙设备进行控制。但是首先你得有一个低耗能的蓝牙设备!
说一下蓝牙的其他知识:蓝牙2.0和蓝牙3.0其实功能是差不多的,都是可以使用手机连接,并且可以进行手机无线无网通信,蓝牙4.0就和前面的版本有很多的区别,它的发展主要是用来适应其他的蓝牙设备,并且一般是单向连接,比如上面的蓝牙灯泡,只需要手机给蓝牙设备传入指令让它执行就可以了。
蓝牙2.0开发,之前有个开发示例(实现两个手机无网无线的通信):
http://blog.csdn.net/wenzhi20102321/article/details/53870789