赞
踩
因此,如果你的应用目标是API级别23或更高,并且需要进行蓝牙扫描,你还需要添加:
从Android 10(API级别29)开始,ACCESS_FINE_LOCATION权限被分为更细粒度的权限,如果你的应用需要在后台访问位置,还需要声明:
对于运行时权限(如位置权限),你需要在应用运行时请求用户授权。这通常在你的应用尝试进行蓝牙扫描之前完成。
这是请求权限的一个基本示例:
(1)安卓原生检查权限和申请权限
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
}
在这里,MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION是一个应用定义的整数常量。将在回调方法onRequestPermissionsResult中使用它来接收请求结果。
(2)第三方库xxPermissions
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
// 检查蓝牙连接权限,如果没有,则请求权限
getPermission(Manifest.permission.BLUETOOTH_CONNECT);
return;
}
// 获取权限的方法
private void getPermission(String permission) {
// 请求权限
XXPermissions.with(getContext())
.permission(permission) // 申请单个权限
.request(new OnPermissionCallback() {
@Override
public void onGranted(@NonNull List permissions, boolean allGranted) {
if (!allGranted) {
// 如果未全部授予权限,则显示提示信息
Toast.makeText(getContext(), “获取部分权限成功,但部分权限未正常授予”, Toast.LENGTH_SHORT).show();
Log.d(“TAG”, “获取部分权限成功”);
return;
}
// 权限全部成功授予后的操作
Log.d(“TAG”, “获取权限成功”);
}
@Override
public void onDenied(@NonNull List permissions, boolean doNotAskAgain) {
if (doNotAskAgain) {
// 如果用户选择不再询问,则提示用户手动开启权限,并跳转到应用设置页面
Toast.makeText(getContext(), “被永久拒绝授权,请手动授予权限”, Toast.LENGTH_SHORT).show();
Log.d(“TAG”, “被永久拒绝授权,请手动授予权限”);
XXPermissions.startPermissionActivity(getContext(), permissions);
} else {
// 如果权限被拒绝但没有选择不再询问,则显示失败提示
Toast.makeText(getContext(), “获取权限失败”, Toast.LENGTH_SHORT).show();
Log.d(“TAG”, “获取权限失败”);
}
}
});
}
经典蓝牙BT开发流程
备注:后面几节讲解的都是以BLE为例子
这就是开始使用蓝牙开发所需了解的基础知识。
我们继续下一节。
在这一节中,我们将学习如何在你的应用中启用蓝牙功能,并检查用户的设备是否支持蓝牙。
首先,你需要获取BluetoothAdapter的实例,它是所有蓝牙操作的入口点。
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
如果getDefaultAdapter()返回null,则表示设备不支持蓝牙。
接下来,检查蓝牙是否已经启用。使用BluetoothAdapter的isEnabled**()**方法可以检查蓝牙是否启用:
if (bluetoothAdapter != null && !bluetoothAdapter.isEnabled()) {
// 蓝牙未启用
}
bluetoothAdapter != null 说明设备支持蓝牙
!bluetoothAdapter.isEnabled() 说明蓝牙没启用
如果蓝牙未启用,你可以请求用户启用它。
这可以通过启动一个Intent来请求用户启用蓝牙,而不是直接调用enable()方法,因为**enable()**方法无需用户同意即可启用蓝牙,这可能不是最佳用户体验。
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
在这里,REQUEST_ENABLE_BT是应用定义的整数请求码,用于在你的Activity的onActivityResult回调中接收结果。
当用户响应启用蓝牙的请求时,系统会调用你的Activity的onActivityResult方法。
你可以在这里检查请求的结果:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK) {
// 用户启用了蓝牙
} else {
// 用户未启用蓝牙
}
}
}
这就是如何在你的应用中启用蓝牙并检查设备是否支持蓝牙的基本步骤,理解这些步骤是进行蓝牙开发的基础。
在这一节中,我们将学习如何发现附近的蓝牙设备以及如何获取已经与你的设备配对的蓝牙设备列表。
你的Android设备可能已经与一些蓝牙设备配对过了。
要获取这些已配对的设备列表,你可以使用BluetoothAdapter的**getBondedDevices()**方法:
Set pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
// 至少有一个已配对设备
for (BluetoothDevice device : pairedDevices) {
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC地址
Log.d(“TAG”, “蓝牙设备名称:”+deviceName);
Log.d(“TAG”, “蓝牙设备地址:”+deviceHardwareAddress);
}
}
要发现附近的蓝牙设备,你需要调用BluetoothAdapter的startDiscovery()方法。这个方法是异步的,发现过程通常会持续12秒。
你需要注册一个BroadcastReceiver来监听BluetoothDevice.ACTION_FOUND广播,这个广播会在发现新设备时发送。
// 注册广播接收器以监听发现的设备
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
// 发现设备
if (bluetoothAdapter.startDiscovery()) {
// 发现过程成功启动
}
疑问:
BluetoothDevice.ACTION_FOUND 是一个什么值?
解答:
在你的BroadcastReceiver中,你可以获取发现的设备信息:
private final BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// 从Intent中获取发现的BluetoothDevice
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC地址
}
}
};
疑问:
解答:
- BluetoothDevice.ACTION_ACL_CONNECTED:当与远程设备建立低级别(ACL)连接时发送的广播。
- BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED:当系统要断开与远程设备的低级别(ACL)连接时发送的广播。
- BluetoothDevice.ACTION_ACL_DISCONNECTED:当与远程设备的低级别(ACL)连接断开时发送的广播。
- BluetoothDevice.ACTION_BOND_STATE_CHANGED:当远程设备的配对状态发生变化时发送的广播。
- BluetoothDevice.ACTION_NAME_CHANGED:当远程设备的名称发生变化时发送的广播。
- BluetoothDevice.ACTION_PAIRING_REQUEST:在需要配对时发送的广播,通常是因为配对过程需要输入PIN码或确认配对。
- BluetoothAdapter.ACTION_DISCOVERY_STARTED:当设备发现开始时发送的广播。
- BluetoothAdapter.ACTION_DISCOVERY_FINISHED:当设备发现结束时发送的广播。
- BluetoothAdapter.ACTION_STATE_CHANGED:当蓝牙适配器的状态发生变化时发送的广播,例如蓝牙被开启或关闭。
监听这些action可以让你的应用更好地与蓝牙设备交互。
例如,
通过监听ACTION_BOND_STATE_CHANGED,你的应用可以知道何时一个设备已经成功配对,或者配对失败。
通过监听ACTION_ACL_CONNECTED和ACTION_ACL_DISCONNECTED,你的应用可以知道何时设备连接或断开连接。
可以在这些节点做一些处理。
由于发现过程会消耗大量资源,一旦你找到了你感兴趣的设备,或者你想停止扫描,你应该使用**cancelDiscovery()**方法来停止发现过程:
bluetoothAdapter.cancelDiscovery();
记得在不再需要时,**unregisterReceiver(receiver)**注销你的BroadcastReceiver,例如,在你的Activity或Fragment的onDestroy()方法中:
@Override
protected void onDestroy() {
super.onDestroy();
// 确保我们不再监听广播
unregisterReceiver(receiver);
}
这就是如何发现新设备以及获取已配对设备的基本步骤。
理解这些步骤对于开发能够与其他蓝牙设备交互的应用是非常重要的。
当你准备好了,请告诉我,以便我们继续下一节。
在这一节中,我们将学习如何使用BluetoothSocket来连接到一个蓝牙设备。连接到设备是进行数据交换的前提。
要与远程蓝牙设备建立连接,首先需要创建一个BluetoothSocket。
BluetoothSocket代表了蓝牙套接字的接口,它是两个设备之间通信的通道。
对于大多数用途,你将使用**createRfcommSocketToServiceRecord(UUID)**方法来创建BluetoothSocket。
这个方法需要一个UUID参数,这个UUID必须是你想要连接的远程设备上的蓝牙服务的UUID。UUID代表通用唯一标识符,用于唯一标识你的应用的蓝牙服务。
BluetoothDevice device = … // 获取一个BluetoothDevice对象
UUID MY_UUID = UUID.fromString(“00001101-0000-1000-8000-00805f9b34fb”); // 示例UUID
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(MY_UUID);
有几个概念:
创建BluetoothSocket后,你可以调用它的**connect()**方法来尝试与远程设备建立连接。
这个方法是**阻塞调用****(**直到连接成功或抛出异常)。
try {
socket.connect();
// 连接成功,可以开始进行数据交换
} catch (IOException e) {
// 连接失败
e.printStackTrace();
}
连接成功后,你可以通过BluetoothSocket的输入输出流来进行数据的读写。
try {
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
// 从InputStream读取数据
byte[] buffer = new byte[1024];
int bytes;
bytes = inputStream.read(buffer);
String receivedData = new String(buffer, 0, bytes);
// 向OutputStream写入数据
String dataToSend = “Hello, Bluetooth!”;
outputStream.write(dataToSend.getBytes());
} catch (IOException e) {
// 处理异常
}
完成数据交换后,应该关闭BluetoothSocket来释放资源。
try {
socket.close();
} catch (IOException e) {
// 处理异常
}
注意事项
- 连接过程可能会花费一些时间,建议在一个单独的线程中进行连接操作,以避免阻塞UI线程。
- 确保你的UUID与远程设备提供的服务UUID匹配。
- 在连接过程中和之后,要妥善处理异常。
疑问:
解答:
在蓝牙通信中,由于蓝牙协议本身的限制以及不同设备的性能差异,发送大量数据时直接发送整个数据包可能会导致数据传输失败或者效率低下。
因此,将大数据分割成小片段(fragments)进行发送是一种常见的做法,这就是所谓的“片段发送”或“数据分片”。
数据分片的基本思想,是将大的数据包分割成多个较小的数据片段,然后逐个片段地发送这些数据。接收方收到所有片段后,再将它们重新组合成原始的数据包。
实现数据分片的一个简单方法是:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注网络安全获取)
零基础入门
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
同时每个成长路线对应的板块都有配套的视频提供:
因篇幅有限,仅展示部分资料
网络安全面试题
绿盟护网行动
还有大家最喜欢的黑客技术
网络安全源码合集+工具包
所有资料共282G,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
mg.cn/img_convert/5912337446dee53639406fead3d3f03c.jpeg)
网络安全源码合集+工具包
所有资料共282G,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。