蓝牙设备开发:检索匹配指定名称的联系人姓名与号码
嘿,针对你要开发的这款蓝牙联系人检索设备,我整理了一套落地性很强的实现方案,直接照着来就能搞定!
核心需求梳理
先明确下核心逻辑:蓝牙设备发起带指定前缀的检索请求,手机端匹配姓名开头符合前缀的联系人,返回包含「索引+姓名+号码」的结构化数组字符串。比如搜索"A - "时,只返回姓名以"A - "开头的联系人,排除像"FriendA"这种前缀不匹配的。
分步实现方案
1. 蓝牙配对与通信链路搭建
首先得让蓝牙设备和手机建立稳定的通信连接,推荐用RFCOMM协议(蓝牙串口规范),这是设备间传输文本数据最常用的方式:
- 手机端作为蓝牙服务端,创建
BluetoothServerSocket监听设备连接请求; - 蓝牙设备作为客户端,扫描并配对手机后发起连接;
- 连接建立后,通过
InputStream接收设备发来的检索前缀,用OutputStream返回处理后的联系人结果。
2. 手机端联系人权限获取
要读取手机联系人,必须申请权限:
- 在
AndroidManifest.xml中声明静态权限:<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- Android 12+ 还需要以下权限 --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> - Android 6.0及以上版本,要在代码中动态申请
READ_CONTACTS权限,用户授权后才能访问联系人数据。
3. 联系人前缀匹配与数据提取
通过系统ContentResolver查询联系人,精准筛选开头匹配的条目:
- 筛选条件:只查询有电话号码的联系人,且姓名以指定前缀开头;
- 提取字段:联系人姓名(
DISPLAY_NAME_PRIMARY)和对应号码(NUMBER); - 号码格式化:去除号码中的空格、括号等冗余字符,保证输出格式统一。
4. 结果格式化与蓝牙传输
把匹配到的联系人按照你要求的格式打包成字符串,再通过蓝牙发送给设备:
- 格式示例:
[ [0] [0] A - Dad [1] +33600000000 [1] [0] A - Mom [1] +33611111111 ] - 注意用统一的字符编码(比如UTF-8)传输,避免乱码问题。
关键代码示例
联系人检索核心代码(Android端)
// 联系人实体类,存储姓名和号码 static class Contact { String name; String number; Contact(String name, String number) { this.name = name; this.number = number; } } // 根据前缀搜索匹配的联系人 private List<Contact> searchMatchedContacts(String prefix) { List<Contact> matchedList = new ArrayList<>(); ContentResolver resolver = getContentResolver(); // 查询所需字段:联系人ID、姓名、号码 String[] projection = { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY, ContactsContract.CommonDataKinds.Phone.NUMBER }; // 筛选条件:有电话号码 + 姓名以指定前缀开头 String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = 1 AND " + ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?"; String[] selectionArgs = {prefix + "%"}; Cursor cursor = resolver.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, selection, selectionArgs, ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC" ); if (cursor != null) { while (cursor.moveToNext()) { String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY)); String rawNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); // 格式化号码,去除冗余字符 String formattedNumber = PhoneNumberUtils.formatNumber(rawNumber, Locale.getDefault().getCountry()); matchedList.add(new Contact(name, formattedNumber)); } cursor.close(); } return matchedList; }
结果格式化代码
// 将联系人列表格式化为指定字符串 private String formatContactResponse(List<Contact> contacts) { StringBuilder sb = new StringBuilder("["); for (int i = 0; i < contacts.size(); i++) { Contact contact = contacts.get(i); sb.append("[").append(i).append("] [0] ").append(contact.name).append(" [1] ").append(contact.number); if (i != contacts.size() - 1) { sb.append(" "); } } sb.append("]"); return sb.toString(); }
蓝牙数据发送示例
// 假设已建立蓝牙连接,outputStream为蓝牙输出流 List<Contact> matchedContacts = searchMatchedContacts("A - "); String response = formatContactResponse(matchedContacts); try { outputStream.write(response.getBytes(StandardCharsets.UTF_8)); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); // 处理蓝牙传输异常,比如重连 }
注意事项
- 蓝牙稳定性:要处理连接断开、超时等异常情况,实现自动重连逻辑;
- 大小写匹配:如果需要不区分大小写的匹配,可以把查询条件改成
LOWER(DISPLAY_NAME_PRIMARY) LIKE LOWER(?),或者在代码中把前缀和姓名都转成小写后比较; - 多号码处理:部分联系人可能有多个号码,如果你需要返回所有号码,可以修改查询逻辑,把同一个联系人的多个号码都加入结果;
- 权限兼容:Android 13+对蓝牙权限的要求更严格,要确保权限申请流程符合系统规范。
内容的提问来源于stack exchange,提问作者TurtleForGaming Apps
相关产品推荐
相关产品推荐

