蓝牙开发 首先需要申请权限
<!--经典蓝牙一样,应用使用蓝牙,需要声明BLUETOOTH权限,如果需要扫描设备或者操作蓝牙设置,则还需要BLUETOOTH_ADMIN权限-->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
此外 AndroidM之后,如果需要搜索附近蓝牙设备 还需要添加两个动态权限(
需要在代码中动态申请)
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
接收 需要获取蓝牙系统管理
在使用蓝牙功能之前,我们需要判断设备是否支持蓝牙,如支持,则再判断 是否开启了蓝牙
bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
/**
* 判断是否支持蓝牙,并打开蓝牙
* 获取到BluetoothAdapter之后,还需要判断是否支持蓝牙,以及蓝牙是否打开。
* 如果没打开,需要让用户打开蓝牙:
*/
public void checkBleDevice(Context context) {
if (getmBluetoothAdapter() != null) {
if (!getmBluetoothAdapter().isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
enableBtIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(enableBtIntent);
}
} else {
Log.i("blueTooth", "该手机不支持蓝牙");
}
}
开启蓝牙后,需要扫描搜索附近蓝牙设备
//开始搜索
getmBluetoothAdapter().startDiscovery();
当搜索到设备,会接收到相应的广播,当然 我们需要注册该广播
/**
* 注册蓝牙回调广播
*/
private void blueToothRegister() {
BltManager.getInstance().registerBltReceiver(this, new BltManager.OnRegisterBltReceiver() {
/**搜索到新设备
* @param device
*/
@Override
public void onBluetoothDevice(BluetoothDevice device) {
if (bltList != null && !bltList.contains(device)) {
bltList.add(device);
}
if (myAdapter != null)
myAdapter.notifyDataSetChanged();
}
/**连接中
* @param device
*/
@Override
public void onBltIng(BluetoothDevice device) {
btl_bar.setVisibility(View.VISIBLE);
blt_status_text.setText("连接" + device.getName() + "中……");
}
/**连接完成
* @param device
*/
@Override
public void onBltEnd(BluetoothDevice device) {
btl_bar.setVisibility(View.GONE);
blt_status_text.setText("连接" + device.getName() + "完成");
}
/**取消链接
* @param device
*/
@Override
public void onBltNone(BluetoothDevice device) {
btl_bar.setVisibility(View.GONE);
blt_status_text.setText("取消了连接" + device.getName());
}
});
}
接下来就是建立蓝牙通信
这里需要用到 BluetoothServerSocket
/**
* 从蓝牙适配器中创建一个蓝牙服务作为服务端,在获得蓝牙适配器后创建服务器端
*/
private void createBltService() {
try {
if (BltManager.getInstance().getmBluetoothAdapter() != null && BltManager.getInstance().getmBluetoothAdapter().isEnabled()) {
bluetoothServerSocket = BltManager.getInstance().getmBluetoothAdapter().listenUsingRfcommWithServiceRecord("com.bluetooth.demo", BltContant.SPP_UUID);
}
} catch (IOException e) {
e.printStackTrace();
}
}
创建好Socket之后,我们需要在服务端等待链接
/**
* 这个操作应该放在子线程中,因为存在线程阻塞的问题
*/
public void run(Handler handler) {
//服务器端的bltsocket需要传入uuid和一个独立存在的字符串,以便验证,通常使用包名的形式
while (true) {
try {
//注意,当accept()返回BluetoothSocket时,socket已经连接了,因此不应该调用connect方法。
//这里会线程阻塞,直到有蓝牙设备链接进来才会往下走
socket = getBluetoothServerSocket().accept();
if (socket != null) {
BltAppliaction.bluetoothSocket = socket;
//回调结果通知
Message message = new Message();
message.what = 3;
message.obj = socket.getRemoteDevice();
handler.sendMessage(message);
//如果你的蓝牙设备只是一对一的连接,则执行以下代码
getBluetoothServerSocket().close();
//如果你的蓝牙设备是一对多的,则应该调用break;跳出循环
break;
}
} catch (IOException e) {
try {
getBluetoothServerSocket().close();
} catch (IOException e1) {
e1.printStackTrace();
}
// break;
}
}
}
客户端则需要申请链接
/**
* 尝试连接一个设备,子线程中完成,因为会线程阻塞
*
* @param btDev 蓝牙设备对象
* @param handler 结果回调事件
* @return
*/
private void connect(final BluetoothDevice btDev, final Handler handler) {
try {
//通过和服务器协商的uuid来进行连接
mBluetoothSocket = btDev.createRfcommSocketToServiceRecord(BltContant.SPP_UUID);
if (mBluetoothSocket != null)
//全局只有一个bluetooth,所以我们可以将这个socket对象保存在appliaction中
BltAppliaction.bluetoothSocket = mBluetoothSocket;
//通过反射得到bltSocket对象,与uuid进行连接得到的结果一样,但这里不提倡用反射的方法
//mBluetoothSocket = (BluetoothSocket) btDev.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(btDev, 1);
Log.d("blueTooth", "开始连接...");
//在建立之前调用
if (getmBluetoothAdapter().isDiscovering())
//停止搜索
getmBluetoothAdapter().cancelDiscovery();
//如果当前socket处于非连接状态则调用连接
if (!getmBluetoothSocket().isConnected()) {
//你应当确保在调用connect()时设备没有执行搜索设备的操作。
// 如果搜索设备也在同时进行,那么将会显著地降低连接速率,并很大程度上会连接失败。
new Thread(new Runnable() {
@Override
public void run() {
if (getmBluetoothSocket() != null)
try {
getmBluetoothSocket().connect();
if (handler == null) return;
//结果回调
Message message = new Message();
message.what = 4;
message.obj = btDev;
handler.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
Log.d("blueTooth", "已经链接");
} catch (Exception e) {
Log.e("blueTooth", "...链接失败");
try {
getmBluetoothSocket().close();
} catch (IOException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
当服务器链接成功 我们就可以基于Socket 进行数据相互传输了
传输文字:
/**
* 发送文本消息
*
* @param message
*/
public static void sendMessage(String message) {
if (BltAppliaction.bluetoothSocket == null || TextUtils.isEmpty(message)) return;
try {
message += "\n";
OutputStream outputStream = BltAppliaction.bluetoothSocket.getOutputStream();
outputStream.write(message.getBytes("utf-8"));
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
传输文件:
/**
* 发送文件
*/
public static void sendMessageByFile(String filePath) {
if (BltAppliaction.bluetoothSocket == null || TextUtils.isEmpty(filePath)) return;
try {
OutputStream outputStream = BltAppliaction.bluetoothSocket.getOutputStream();
//要传输的文件路径
File file = new File(filePath);
//说明不存在该文件
if (!file.exists()) return;
//说明该文件是一个文件夹
if (file.isDirectory()) return;
//1、发送文件信息实体类
outputStream.write("file".getBytes("utf-8"));
//将文件写入流
FileInputStream fis = new FileInputStream(file);
//每次上传1M的内容
byte[] b = new byte[1024];
int length;
int fileSize = 0;//实时监测上传进度
while ((length = fis.read(b)) != -1) {
fileSize += length;
Log.i("socketChat", "文件上传进度:" + (fileSize / file.length() * 100) + "%");
//2、把文件写入socket输出流
outputStream.write(b, 0, length);
}
//关闭文件流
fis.close();
//该方法无效
//outputStream.write("\n".getBytes());
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
接收消息
public static void receiveMessage(Handler handler) {
if (BltAppliaction.bluetoothSocket == null || handler == null) return;
try {
InputStream inputStream = BltAppliaction.bluetoothSocket.getInputStream();
// 从客户端获取信息
BufferedReader bff = new BufferedReader(new InputStreamReader(inputStream));
String json;
while (true) {
while ((json = bff.readLine()) != null) {
Message message = new Message();
message.obj = json;
message.what = 1;
handler.sendMessage(message);
//说明接下来会接收到一个文件流
if ("file".equals(json)) {
FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory() + "/test.gif");
int length;
int fileSzie = 0;
byte[] b = new byte[1024];
// 2、把socket输入流写到文件输出流中去
while ((length = inputStream.read(b)) != -1) {
fos.write(b, 0, length);
fileSzie += length;
System.out.println("当前大小:" + fileSzie);
//这里通过先前传递过来的文件大小作为参照,因为该文件流不能自主停止,所以通过判断文件大小来跳出循环
}
fos.close();
message.obj = "文件:保存成功";
message.what = 2;
handler.sendMessage(message);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}