android如何在应用中实现对小米蓝牙音频接收器的连接

具体实现:
private static final String TAG = "BluetoothA2DPTest";
private BroadcastReceiver mBroadcastR
private BluetoothA2dp mBluetoothA2
private BluetoothAdapter mBluetoothA
private String DEVICE_NAME = "KUWO_K1";
private BluetoothDevice mBluetoothD
private MediaPlayer mMediaP
private void initParameters(){
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter == null){
Log.e(TAG,"have no bluetooth adapter.");
if(!mBluetoothAdapter.isEnabled()){
mBluetoothAdapter.enable();
//开始搜索附近蓝牙
startDiscovery();
//绑定BluetoothA2DP,获得service
getBluetoothA2DP();
//监听广播
mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
BluetoothD
switch (intent.getAction()) {
case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
//&editor-fold&
switch (intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, -1)) {
case BluetoothA2dp.STATE_CONNECTING:
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.i(TAG, "device: " + device.getName() +" connecting");
case BluetoothA2dp.STATE_CONNECTED:
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.i(TAG, "device: " + device.getName() +" connected");
//连接成功,开始播放
startPlay();
case BluetoothA2dp.STATE_DISCONNECTING:
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.i(TAG, "device: " + device.getName() +" disconnecting");
case BluetoothA2dp.STATE_DISCONNECTED:
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.i(TAG, "device: " + device.getName() +" disconnected");
setResultPASS();
//&/editor-fold&
case BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED:
//&editor-fold&
int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, -1);
switch (state) {
case BluetoothA2dp.STATE_PLAYING:
Log.i(TAG, "state: playing.");
case BluetoothA2dp.STATE_NOT_PLAYING:
Log.i(TAG, "state: not playing");
Log.i(TAG, "state: unkown");
//&/editor-fold&
case BluetoothDevice.ACTION_FOUND:
//&editor-fold&
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int deviceClassType = device.getBluetoothClass().getDeviceClass();
//找到指定的蓝牙设备
if ((deviceClassType == BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET
|| deviceClassType == BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES)
&& device.getName().equals(DEVICE_NAME)) {
Log.i(TAG, "Found device:" + device.getName());
mBluetoothDevice =
//start bond,开始配对
createBond();
//&/editor-fold&
case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
//&editor-fold&
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,BluetoothDevice.BOND_NONE);
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
switch (bondState){
case BluetoothDevice.BOND_BONDED:
//配对成功
Log.i(TAG,"Device:"+device.getName()+" bonded.");
mBluetoothAdapter.cancelDiscovery();
//取消搜索
connect();
//连接蓝牙设备
case BluetoothDevice.BOND_BONDING:
Log.i(TAG,"Device:"+device.getName()+" bonding.");
case BluetoothDevice.BOND_NONE:
Log.i(TAG,"Device:"+device.getName()+" not bonded.");
//不知道是蓝牙耳机的关系还是什么原因,经常配对不成功
//配对不成功的话,重新尝试配对
createBond();
//&/editor-fold&
case BluetoothAdapter.ACTION_STATE_CHANGED:
//&editor-fold&
state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
switch (state) {
case BluetoothAdapter.STATE_TURNING_ON:
Log.i(TAG, "BluetoothAdapter is turning on.");
case BluetoothAdapter.STATE_ON:
Log.i(TAG, "BluetoothAdapter is on.");
//蓝牙已打开,开始搜索并连接service
startDiscovery();
getBluetoothA2DP();
case BluetoothAdapter.STATE_TURNING_OFF:
Log.i(TAG, "BluetoothAdapter is turning off.");
case BluetoothAdapter.STATE_OFF:
Log.i(TAG, "BluetoothAdapter is off.");
//&/editor-fold&
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mBroadcastReceiver, filter);
private void startDiscovery(){
Log.i(TAG,"mBluetoothAdapter startDiscovery.");
if(mBluetoothAdapter!=null && mBluetoothAdapter.isEnabled() && !mBluetoothAdapter.isDiscovering()){
mBluetoothAdapter.startDiscovery();
private void getBluetoothA2DP(){
Log.i(TAG,"getBluetoothA2DP");
if(mBluetoothAdapter == null){
if(mBluetoothA2dp != null){
mBluetoothAdapter.getProfileProxy(this, new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if(profile == BluetoothProfile.A2DP){
//Service连接成功,获得BluetoothA2DP
mBluetoothA2dp = (BluetoothA2dp)
public void onServiceDisconnected(int profile) {
},BluetoothProfile.A2DP);
private void createBond() {
Log.i(TAG, "createBond");
mBluetoothDevice.createBond();
//connect和disconnect都是hide方法,普通应用只能通过反射机制来调用该方法
private void connect(){
Log.i(TAG,"connect");
if(mBluetoothA2dp == null){
if(mBluetoothDevice == null){
Method connect = mBluetoothA2dp.getClass().getDeclaredMethod("connect", BluetoothDevice.class);
connect.setAccessible(true);
connect.invoke(mBluetoothA2dp,mBluetoothDevice);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
Log.e(TAG,"connect exception:"+e);
e.printStackTrace();
private void startPlay(){
Log.i(TAG, "startPlay");
AudioManager mAudioManager= (AudioManager)getSystemService(AUDIO_SERVICE);
if(mAudioManager!=null){
int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,maxVolume,0);
Uri uri = Uri.parse("android.resource://"+getPackageName()+"/"+ R.raw.speaker_test);
mMediaPlayer = new MediaPlayer();
mMediaPlayer.reset();
mMediaPlayer.setDataSource(this,uri);
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
//播放完成,可以考虑断开连接
disconnect();
mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e(TAG, "Playback error.");
return false;
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch(IllegalStateException|IOException e) {
Log.e(TAG, "Exception: prepare or start mediaplayer");
setResultFAIL();
//程序退出前,要release播放器
private void stopPlay(){
Log.i(TAG,"stopPlay");
if(mMediaPlayer!=null){
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
private void disconnect(){
Log.i(TAG,"disconnect");
if(mBluetoothA2dp == null){
if(mBluetoothDevice == null){
Method disconnect = mBluetoothA2dp.getClass().getDeclaredMethod("disconnect", BluetoothDevice.class);
disconnect.setAccessible(true);
disconnect.invoke(mBluetoothA2dp,mBluetoothDevice);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
Log.e(TAG,"connect exception:"+e);
e.printStackTrace();
//取消配对
private void unPairAllDevices(){
Log.i(TAG,"unPairAllDevices");
for(BluetoothDevice device:mBluetoothAdapter.getBondedDevices()){
Method removeBond = device.getClass().getDeclaredMethod("removeBond");
removeBond.invoke(device);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
//注意,在程序退出之前(OnDestroy),需要断开蓝牙相关的Service
//否则,程序会报异常:service leaks
private void disableAdapter(){
Log.i(TAG,"disableAdapter");
if(mBluetoothAdapter == null){
if(mBluetoothAdapter.isDiscovering()){
mBluetoothAdapter.cancelDiscovery();
//关闭ProfileProxy,也就是断开service连接
mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP,mBluetoothA2dp);
if(mBluetoothAdapter.isEnabled()){
boolean ret = mBluetoothAdapter.disable();
Log.i(TAG,"disable adapter:"+ret);
阅读(...) 评论()Android系统中的蓝牙连接程序编写实例教程
转载 &更新时间:日 15:43:27 & 作者:zhoulc
这篇文章主要介绍了Android系统中的蓝牙连接程序编写实例教程,包括蓝牙的设备查找及自动配对等各种基础功能的实现,十分给力,需要的朋友可以参考下
Bluetooth结构
frameworks/base/core/java/android/bluetooth/
包含了bluetooth的JAVA类。
frameworks/base/core/jni/android_bluetooth_开头的文件
定义了bluez通过JNI到上层的接口。
frameworks/base/core/jni/android_server_bluetoothservice.cpp
调用硬件适配层的接口system/bluetooth/bluedroid/bluetooth.c
3、bluez库
external/bluez/
这是bluez用户空间的库,开源的bluetooth代码,包括很多协议,生成libbluetooth.so。
4、硬件适配层
system/bluetooth/bluedroid/bluetooth.c
包含了对硬件操作的接口
system/bluetooth/data/*
一些配置文件,复制到/etc/bluetooth/。
还有其他一些测试代码和工具。
简略介绍Bluetooth开发使用到的类
1、BluetoothAdapter,蓝牙适配器,可判断蓝牙设备是否可用等功能。
常用方法列举如下:
&&& cancelDiscovery() ,取消搜索过程,在进行蓝牙设备搜索时,如果调用该方法会停止搜索。(搜索过程会持续12秒)
&&& disable()关闭蓝牙,也就是我们常说的禁用蓝牙。
&&& enable()打开蓝牙,这个方法打开蓝牙但不会弹出提示,正常流程操作下,我们会让系统提示用户是否打开蓝牙设备。如下两行代码可轻松搞定。
&&& Intent enabler=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
&&& startActivityForResult(enabler,reCode);//同startActivity(enabler);(在主Activity启动一个二级Activity,reCode一般等于3,一定记得要在AndroidManifest.xml里面添加蓝牙权限)
&&& getAddress()获取本地蓝牙地址
&&& getDefaultAdapter()获取默认BluetoothAdapter,实际上,也只有这一种方法获取BluetoothAdapter
&&& getName()获取本地蓝牙名称
&&& getRemoteDevice(String address)根据蓝牙地址获取远程蓝牙设备
&&& getState()获取本地蓝牙适配器当前状态(感觉可能调试的时候更需要)
&&& isDiscovering()判断当前是否正在查找设备,是返回true
&&& isEnabled()判断蓝牙是否打开,已打开返回true,否则,返回false
&&& listenUsingRfcommWithServiceRecord(String name,UUID uuid)根据名称,UUID创建并返回&&&
&&& BluetoothServerSocket,这是创建BluetoothSocket服务器端的第一步
&&& startDiscovery()开始搜索,这是搜索的第一步
&2.BluetoothDevice看名字就知道,这个类描述了一个蓝牙设备
&&& createRfcommSocketToServiceRecord(UUIDuuid)根据UUID创建并返回一个BluetoothSocket
&&& 这个方法也是我们获取BluetoothDevice的目的——创建BluetoothSocket
&&& 这个类其他的方法,如getAddress(),getName(),同BluetoothAdapter
&&& 这个类有几个隐藏方法,涉及到蓝牙的自动配对,setPin,createBond,cancelPairingUserInput,等方法(需要通过java的反射,调用这几个隐藏方法)
3.BluetoothServerSocket如果去除了Bluetooth相信大家一定再熟悉不过了,既然是Socket,方法就应该都差不多,
&&& 这个类一种只有三个方法
&&& 两个重载的accept(),accept(inttimeout)两者的区别在于后面的方法指定了过时时间,需要注意的是,执行这两个方法的时候,直到接收到了客户端的请求(或是过期之后),都会阻塞线程,应该放在新线程里运行!
&&& 还有一点需要注意的是,这两个方法都返回一个BluetoothSocket,最后的连接也是服务器端与客户端的两个BluetoothSocket的连接
&&& close()关闭!
4.BluetoothSocket,跟BluetoothServerSocket相对,是客户端
&&& 一共5个方法,不出意外,都会用到
&&& close(),关闭
&&& connect()连接
&&& getInptuStream()获取输入流
&&& getOutputStream()获取输出流
&&& getRemoteDevice()获取远程设备,这里指的是获取bluetoothSocket指定连接的那个远程蓝牙设备
二、蓝牙设备的发现、查找。
1.基于安全性考虑,设置开启可被搜索后,Android系统会默认给出120秒的时间,其他设备能在这120秒内搜索到它。
&&& Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
&&& startActivityForResult(enalbe,REQUEST_DISCOVERABLE);
2.搜索蓝牙设备
&&& BluetoothAdapter _bluetooth = BluetoothAdapter.getDefaultAdapter();
&&& _bluetooth.startDiscovery();
3.关闭蓝牙设备
&&& BluetoothAdapter _bluetooth = BluetoothAdapter.getDefaultAdapter();
&&& _bluetooth.disable();
4.创建蓝牙客户端
&&& BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString(UUID号));
&&& socket.connect();
4.创建蓝牙服务端
&&& BluetoothServerSocket _serverSocket = _bluetooth.listenUsingRfcommWithServiceRecord(服务端名称,UUID.fromeString(UUID号));
&&& BluetoothSocket socket = _serverSocket.accept();
&&& InputStream inputStream = socket.getInputStream();
TCP/IP通信相关代码实现
注:tcp_ip模块需要在系统setting模块中,完成蓝牙的配对,只有配对成功的,才能进行socket通信(具体如何配对和如何自动配对,将在bluetoot3或者4中进行讲解)
AndridManifest.xml
&manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.thecaseforbluetooth"
android:versionCode="1"
android:versionName="1.0" &
android:minSdkVersion="8"
android:targetSdkVersion="15" /&
&uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /&
&uses-permission android:name="android.permission.BLUETOOTH" /&
&application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" &
android:name=".BluetoothActivity"
android:label="@string/title_activity_bluetooth" &
&intent-filter&
&action android:name="android.intent.action.MAIN" /&
&category android:name="android.intent.category.LAUNCHER" /&
&/intent-filter&
&/activity&
&/application&
&/manifest&
&LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" &
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnSearch"
android:text="查找设备"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnExit"
android:text="退出应用"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnDis"
android:text="设置可被发现"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnserver"
android:text="启动服务端"
&ToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbtnSwitch"
android:text="开/关 蓝牙设备"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/lvDevices"
&/LinearLayout&
BluetoothActivity.java
package com.example.
import java.util.ArrayL
import java.util.S
import android.app.A
import android.bluetooth.BluetoothA
import android.bluetooth.BluetoothD
import android.content.BroadcastR
import android.content.C
import android.content.I
import android.content.IntentF
import android.os.B
import android.view.M
import android.view.V
import android.view.View.OnClickL
import android.widget.AdapterV
import android.widget.AdapterView.OnItemClickL
import android.widget.ArrayA
import android.widget.B
import android.widget.ListV
import android.widget.T
import android.widget.ToggleB
public class BluetoothActivity extends Activity {
public Button searchB//搜索蓝牙设备
public Button exitB//退出应用
public Button discoverB//设置可被发现
public ToggleButton openB//开关蓝牙设备
public ListView listV//蓝牙设备清单
public ArrayAdapter&String&
public ArrayList&String& list =new ArrayList&String&();
private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set&BluetoothDevice& bondD
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
searchBtn = (Button)findViewById(R.id.btnSearch);
exitBtn = (Button)findViewById(R.id.btnExit);
discoverBtn = (Button)findViewById(R.id.btnDis);
openBtn = (ToggleButton)findViewById(R.id.tbtnSwitch);
serverbtn = (Button)findViewById(R.id.btnserver);
listView = (ListView)findViewById(R.id.lvDevices);
context = getApplicationContext();
adapter = new ArrayAdapter&String&(this, android.R.layout.simple_list_item_1,list);
listView.setAdapter(adapter);
openBtn.setChecked(false);
//注册广播接收信号
IntentFilter intent = new IntentFilter();
intent.addAction(BluetoothDevice.ACTION_FOUND);// 用BroadcastReceiver来取得搜索结果
intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); //每当扫描模式变化的时候,应用程序可以为通过ACTION_SCAN_MODE_CHANGED值来监听全局的消息通知。比如,当设备停止被搜寻以后,该消息可以被系统通知給应用程序。
intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); //每当蓝牙模块被打开或者关闭,应用程序可以为通过ACTION_STATE_CHANGED值来监听全局的消息通知。
registerReceiver(searchReceiver, intent);
//显示已配对设备以及搜索未配对设备
searchBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
if(bluetoothAdapter.isDiscovering()){
bluetoothAdapter.cancelDiscovery();
list.clear();
bondDevices = bluetoothAdapter.getBondedDevices();
for(BluetoothDevice device : bondDevices) {
String str = " 已配对完成 " + device.getName() +" "
+ device.getAddress();
list.add(str);
adapter.notifyDataSetChanged();
bluetoothAdapter.startDiscovery();
//退出应用
exitBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
BluetoothActivity.this.finish();
//设置蓝牙设备可发现
discoverBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Intent discoverIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverIntent);
//开关蓝牙设备
openBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
if(openBtn.isChecked() == true){
bluetoothAdapter.disable();
else if(openBtn.isChecked() == false){
bluetoothAdapter.enable();
//作为服务端开启
serverbtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
ServerThread serverThread = new ServerThread(bluetoothAdapter, context);
Toast.makeText(context, "server 端启动", 5000).show();
serverThread.start();
listView.setOnItemClickListener(new ItemClickListener());
public void onStart() {
super.onStart();
// If BT is not on, request that it be enabled.
if(bluetoothAdapter == null){
Toast.makeText(context, "蓝牙设备不可用", 5000).show();
if (!bluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, 3);
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
private final BroadcastReceiver searchReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
BluetoothDevice device =
if(BluetoothDevice.ACTION_FOUND.equals(action)){
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() == BluetoothDevice.BOND_NONE) {
Toast.makeText(context, device.getName()+"", 5000).show();
String str = " 未配对完成 " + device.getName() +" "
+ device.getAddress();
if (list.indexOf(str) == -1)// 防止重复添加
list.add(str);
adapter.notifyDataSetChanged();
public class ItemClickListener implements OnItemClickListener {
public void onItemClick(AdapterView&?& arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
if(bluetoothAdapter.isDiscovering())
bluetoothAdapter.cancelDiscovery();
String str = list.get(arg2);
String address = str.substring(str.length() - 17);
BluetoothDevice btDev = bluetoothAdapter.getRemoteDevice(address);
ClientThread clientThread = new ClientThread(btDev, context);
clientThread.start();
Bluetoothprotocol.java
package com.example.
public interface Bluetoothprotocol {
public static final String PROTOCOL_SCHEME_L2CAP = "btl2cap";
public static final String PROTOCOL_SCHEME_RFCOMM = "btspp";
public static final String PROTOCOL_SCHEME_BT_OBEX = "btgoep";
public static final String PROTOCOL_SCHEME_TCP_OBEX = "tcpobex";
ServerThread.java
package com.example.
import java.io.IOE
import java.io.InputS
import java.io.OutputS
import java.util.UUID;
import android.bluetooth.BluetoothA
import android.bluetooth.BluetoothServerS
import android.bluetooth.BluetoothS
import android.content.C
import android.os.M
import android.util.L
import android.widget.T
public class ServerThread extends Thread {
public BluetoothServerSocket mserverS
public BluetoothAdapter bluetoothA
public BluetoothS
public ServerThread(BluetoothAdapter bluetoothAdapter,Context context) {
this.bluetoothAdapter = bluetoothA
this.context =
public void run() {
/* 创建一个蓝牙服务器
* 参数分别:服务器名称、UUID */
mserverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(Bluetoothprotocol.PROTOCOL_SCHEME_RFCOMM,
UUID.fromString("0-805F9B34FB"));
/* 接受客户端的连接请求 */
socket = mserverSocket.accept();
//下面代码作者偷懒,读写另外起一个线程最好
//接收数据
byte[] buffer = new byte[1024];
InputStream mmInStream =
mmInStream = socket.getInputStream();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
System.out.println("zhoulc server");
while(true){
if( (bytes = mmInStream.read(buffer)) & 0 )
byte[] buf_data = new byte[bytes];
for(int i=0; i& i++)
buf_data[i] = buffer[i];
String s = new String(buf_data);
System.out.println(s+"zhoulc server is in");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
ClientThread.java
package com.example.
import java.io.IOE
import java.io.OutputS
import java.util.UUID;
import android.bluetooth.BluetoothD
import android.bluetooth.BluetoothS
import android.content.C
import android.widget.T
public class ClientThread extends Thread {
public BluetoothS
public BluetoothD
public ClientThread(BluetoothDevice device,Context context){
this.device =
this.context =
public void run() {
//创建一个Socket连接:只需要服务器在注册时的UUID号
socket = device.createRfcommSocketToServiceRecord(UUID.fromString("0-805F9B34FB"));
socket.connect();
//下面代码作者偷懒,读写另外起一个线程最好
//发送数据
if (socket == null)
Toast.makeText(context, "链接失败", 5000).show();
System.out.println("zhoulc client");
while(true){
System.out.println("zhoulc client is in");
String msg = "hello everybody I am client";
OutputStream os = socket.getOutputStream();
os.write(msg.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
蓝牙设备之间自动配对
&&& 1、蓝牙设备之间自动配对,需要两个设备都安装进行配对的apk(网上好多自动配对的帖子都没有说明情况)
&&& 2、在自动匹配的时候想通过反射调用BluetoothDevice的setPin、createBond、cancelPairingUserInput实现设置密钥、配对请求创建、取消密钥信息输入等。
&&&&&&& 1)createBond()创建,最终会调到源码的BluetoothService的createBond(String address)方法,通过对源码浅显的了解,createBond主要是写入匹配密钥(BluetoothService的writeDockPin())以及进入jni注册回调函数onCreatePairedDeviceResult观察匹配结果
比如:&&& // Pins did not match, or remote device did not respond to pin
&&&&&&&&&&& // request in time
&&&&&&&&&&& // We rejected pairing, or the remote side rejected pairing. This
&&&&&&&&&&& // happens if either side presses 'cancel' at the pairing dialog.
&&&&&&&&&&& // Not sure if this happens
&&&&&&&&&&& // Other device is not responding at all
&&&&&&&&&&& // already bonded
等,在jni中创建了进行匹配的device("CreatePairedDevice"),这时bluetooth会发送一个ACTION_PAIRING_REQUEST的广播,只有当前会出现密钥框的蓝牙设备收到。写完密钥之后,发送广播给另外一个蓝牙设备接收,然后打开密钥输入框进行匹配。
&&&&&&& 2)setPin()设置密钥,通过查看setting源码,发现在确认输入密钥之后会调用setPin()(如果点取消,就会调用cancelPairingUserInput,取消密钥框),setPin具体通过D-BUS做了什么没有去深究,但是在调用setPin的时候会remove掉一个map里面的键值对(address:int),也就是我们在调用setPin之后如果再去调用onCreatePairedDeviceResult,则该方法一定返回false,并且出现下面的打印提示:cancelUserInputNative(B8:FF:FE:55:EF:D6) called but no native data available, ignoring. Maybe the PasskeyAgent Request was already cancelled by the remote or by bluez.(因为该方法也会remove掉一个键值对)
&&&&&&& 3)cancelPairingUserInput()取消用户输入密钥框,个人觉得一般情况下不要和setPin(setPasskey、setPairingConfirmation、setRemoteOutOfBandData)一起用,这几个方法都会remove掉map里面的key:value(也就是互斥的)。
&&& 3、蓝牙耳机、手柄等一些无法手动配置的设备是如何完成自动配对的。
&&& 在源码里面有一个自动配对的方法,也就是把pin值自动设为“0000”
/*package*/ synchronized boolean attemptAutoPair(String address) {
&&&&&&& if (!mBondState.hasAutoPairingFailed(address) &&
&&&&&&&&&&&&&&& !mBondState.isAutoPairingBlacklisted(address)) {
&&&&&&&&&&& mBondState.attempt(address);
&&&&&&&&&&& setPin(address, BluetoothDevice.convertPinToBytes("0000"));
&&&&&&&&&&&
该方法是在底层回调到java层的onRequestPinCode方法时被调用,首先 Check if its a dock(正常输入的密钥,走正常配对方式,双方输入匹配值),然后再 try 0000 once if the device looks dumb(涉及到Device.AUDIO_VIDEO相关部分如:耳机,免提等进入自动匹配模式)进行自动配对。
言归正传,虽然个人觉得自动配对需要双方乃至多方蓝牙设备都需要装上实现自动配对的apk,已经失去了自动配对的意义,但有可能还是会派上用场。下面我们看看现实情况的自动配对是什么样的吧。
由于BluetoothDevice配对的方法都是hide的,所以我们需要通过反射调用被隐藏的方法,现在基本都是通用的工具类型了,网上模式基本一样。
ClsUtils.java
package cn.
import java.lang.reflect.F
import java.lang.reflect.M
import android.bluetooth.BluetoothA
import android.bluetooth.BluetoothD
import android.util.L
public class ClsUtils
public static BluetoothDevice remoteDevice=
* 与设备配对 参考源码:platform/packages/apps/Settings.git
* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
@SuppressWarnings("unchecked")
static public boolean createBond(@SuppressWarnings("rawtypes") Class btClass, BluetoothDevice btDevice)
throws Exception
Method createBondMethod = btClass.getMethod("createBond");
Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);
return returnValue.booleanValue();
* 与设备解除配对 参考源码:platform/packages/apps/Settings.git
* /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
@SuppressWarnings("unchecked")
static public boolean removeBond(Class btClass, BluetoothDevice btDevice)
throws Exception
Method removeBondMethod = btClass.getMethod("removeBond");
Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);
return returnValue.booleanValue();
@SuppressWarnings("unchecked")
static public boolean setPin(Class btClass, BluetoothDevice btDevice,
String str) throws Exception
Method removeBondMethod = btClass.getDeclaredMethod("setPin",
new Class[]
{byte[].class});
Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice,
new Object[]
{str.getBytes()});
Log.d("returnValue", "setPin is success " +btDevice.getAddress()+ returnValue.booleanValue());
catch (SecurityException e)
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
catch (IllegalArgumentException e)
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
// 取消用户输入
@SuppressWarnings("unchecked")
static public boolean cancelPairingUserInput(Class btClass,
BluetoothDevice device)
throws Exception
Method createBondMethod = btClass.getMethod("cancelPairingUserInput");
// cancelBondProcess()
Boolean returnValue = (Boolean) createBondMethod.invoke(device);
Log.d("returnValue", "cancelPairingUserInput is success " + returnValue.booleanValue());
return returnValue.booleanValue();
// 取消配对
@SuppressWarnings("unchecked")
static public boolean cancelBondProcess(Class btClass,
BluetoothDevice device)
throws Exception
Method createBondMethod = btClass.getMethod("cancelBondProcess");
Boolean returnValue = (Boolean) createBondMethod.invoke(device);
return returnValue.booleanValue();
* @param clsShow
@SuppressWarnings("unchecked")
static public void printAllInform(Class clsShow)
// 取得所有方法
Method[] hideMethod = clsShow.getMethods();
int i = 0;
for (; i & hideMethod. i++)
//Log.e("method name", hideMethod.getName() + ";and the i is:"
// 取得所有常量
Field[] allFields = clsShow.getFields();
for (i = 0; i & allFields. i++)
//Log.e("Field name", allFields.getName());
catch (SecurityException e)
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
catch (IllegalArgumentException e)
// throw new RuntimeException(e.getMessage());
e.printStackTrace();
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
Bluetooth1.java 主activity,所有界面操作实现地方
package cn.
import java.io.IOE
import java.util.ArrayL
import java.util.L
import android.app.A
import android.bluetooth.BluetoothA
import android.bluetooth.BluetoothD
import android.bluetooth.BluetoothS
import android.content.BroadcastR
import android.content.C
import android.content.I
import android.content.IntentF
import android.os.B
import android.util.L
import android.view.M
import android.view.V
import android.widget.AdapterV
import android.widget.ArrayA
import android.widget.B
import android.widget.ListV
import android.widget.T
import android.widget.ToggleB
public class Bluetooth1 extends Activity {
/** Called when the activity is first created. */
Button btnSearch, btnDis, btnE
ToggleButton tbtnS
ListView lvBTD
ArrayAdapter&String& adtD
List&String& lstDevices = new ArrayList&String&();
BluetoothAdapter btA
public static BluetoothSocket btS
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Button 设置
btnSearch = (Button) this.findViewById(R.id.btnSearch);
btnSearch.setOnClickListener(new ClickEvent());
btnExit = (Button) this.findViewById(R.id.btnExit);
btnExit.setOnClickListener(new ClickEvent());
btnDis = (Button) this.findViewById(R.id.btnDis);
btnDis.setOnClickListener(new ClickEvent());
// ToogleButton设置
tbtnSwitch = (ToggleButton) this.findViewById(R.id.tbtnSwitch);
tbtnSwitch.setOnClickListener(new ClickEvent());
// ListView及其数据源 适配器
lvBTDevices = (ListView) this.findViewById(R.id.lvDevices);
adtDevices = new ArrayAdapter&String&(this,
android.R.layout.simple_list_item_1, lstDevices);
lvBTDevices.setAdapter(adtDevices);
lvBTDevices.setOnItemClickListener(new ItemClickEvent());
btAdapt = BluetoothAdapter.getDefaultAdapter();// 初始化本机蓝牙功能
// ========================================================
// modified by wiley
* if (btAdapt.getState() == BluetoothAdapter.STATE_OFF)// 读取蓝牙状态并显示
* tbtnSwitch.setChecked(false); else if (btAdapt.getState() ==
* BluetoothAdapter.STATE_ON) tbtnSwitch.setChecked(true);
if (btAdapt.isEnabled()) {
tbtnSwitch.setChecked(false);
tbtnSwitch.setChecked(true);
// ============================================================
// 注册Receiver来获取蓝牙设备相关的结果
IntentFilter intent = new IntentFilter();
intent.addAction(BluetoothDevice.ACTION_FOUND);// 用BroadcastReceiver来取得搜索结果
intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(searchDevices, intent);
private final BroadcastReceiver searchDevices = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Bundle b = intent.getExtras();
Object[] lstName = b.keySet().toArray();
// 显示所有收到的消息及其细节
for (int i = 0; i & lstName. i++) {
String keyName = lstName.toString();
Log.e(keyName, String.valueOf(b.get(keyName)));
BluetoothDevice device =
// 搜索设备时,取得设备的MAC地址
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() == BluetoothDevice.BOND_NONE) {
String str = "
未配对|" + device.getName() + "|"
+ device.getAddress();
if (lstDevices.indexOf(str) == -1)// 防止重复添加
lstDevices.add(str); // 获取设备名称和mac地址
adtDevices.notifyDataSetChanged();
}else if(BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)){
device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
switch (device.getBondState()) {
case BluetoothDevice.BOND_BONDING:
Log.d("BlueToothTestActivity", "正在配对......");
case BluetoothDevice.BOND_BONDED:
Log.d("BlueToothTestActivity", "完成配对");
//connect(device);//连接设备
case BluetoothDevice.BOND_NONE:
Log.d("BlueToothTestActivity", "取消配对");
protected void onDestroy() {
this.unregisterReceiver(searchDevices);
super.onDestroy();
android.os.Process.killProcess(android.os.Process.myPid());
class ItemClickEvent implements AdapterView.OnItemClickListener {
public void onItemClick(AdapterView&?& arg0, View arg1, int arg2,
long arg3) {
if(btAdapt.isDiscovering())btAdapt.cancelDiscovery();
String str = lstDevices.get(arg2);
String[] values = str.split("\\|");
String address = values[2];
Log.e("address", values[2]);
BluetoothDevice btDev = btAdapt.getRemoteDevice(address);
Boolean returnValue =
if (btDev.getBondState() == BluetoothDevice.BOND_NONE) {
Toast.makeText(Bluetooth1.this, "远程设备发送蓝牙配对请求", 5000).show();
//这里只需要createBond就行了
ClsUtils.createBond(btDev.getClass(), btDev);
}else if(btDev.getBondState() == BluetoothDevice.BOND_BONDED){
Toast.makeText(Bluetooth1.this, btDev.getBondState()+" ....正在连接..", 1000).show();
} catch (Exception e) {
e.printStackTrace();
class ClickEvent implements View.OnClickListener {
public void onClick(View v) {
if (v == btnSearch)// 搜索蓝牙设备,在BroadcastReceiver显示结果
if (btAdapt.getState() == BluetoothAdapter.STATE_OFF) {// 如果蓝牙还没开启
Toast.makeText(Bluetooth1.this, "请先打开蓝牙", 1000)
if (btAdapt.isDiscovering())
btAdapt.cancelDiscovery();
lstDevices.clear();
Object[] lstDevice = btAdapt.getBondedDevices().toArray();
for (int i = 0; i & lstDevice. i++) {
BluetoothDevice device = (BluetoothDevice) lstDevice[i];
String str = " 已配对|" + device.getName() + "|"
+ device.getAddress();
lstDevices.add(str); // 获取设备名称和mac地址
adtDevices.notifyDataSetChanged();
setTitle("本机:" + btAdapt.getAddress());
btAdapt.startDiscovery();
} else if (v == tbtnSwitch) {// 本机蓝牙启动/关闭
if (tbtnSwitch.isChecked() == false)
btAdapt.enable();
else if (tbtnSwitch.isChecked() == true)
btAdapt.disable();
} else if (v == btnDis)// 本机可以被搜索
Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
} else if (v == btnExit) {
if (btSocket != null)
btSocket.close();
} catch (IOException e) {
e.printStackTrace();
Bluetooth1.this.finish();
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
PairingRequest.java (重要部分,自动配对主要是这个部分完成,activity只是创建了一个配对请求)
package cn.
import android.bluetooth.BluetoothD
import android.content.BroadcastR
import android.content.C
import android.content.I
import android.widget.T
public class PairingRequest extends BroadcastReceiver {
String strPsw = "0000";
final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST";
static BluetoothDevice remoteDevice =
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_PAIRING_REQUEST)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
ClsUtils.setPin(device.getClass(), device, strPsw); // 手机和蓝牙采集器配对
// ClsUtils.cancelPairingUserInput(device.getClass(),
// device); //一般调用不成功,前言里面讲解过了
Toast.makeText(context, "配对信息" + device.getName(), 5000)
} catch (Exception e) {
// TODO Auto-generated catch block
Toast.makeText(context, "请求连接错误...", 1000).show();
// pair(device.getAddress(),strPsw);
AndroidManifest.xml 启动activity,接收广播
&manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.bluetooth"
android:versionCode="1"
android:versionName="1.0" &
android:minSdkVersion="8"
android:targetSdkVersion="15" /&
&uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /&
&uses-permission android:name="android.permission.BLUETOOTH" /&
&application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" &
android:name=".Bluetooth1"
android:label="@string/title_activity_bluetooth1" &
&intent-filter&
&action android:name="android.intent.action.MAIN" /&
&category android:name="android.intent.category.LAUNCHER" /&
&/intent-filter&
&/activity&
&receiver android:name=".PairingRequest"&
&intent-filter&
&action android:name="android.bluetooth.device.action.PAIRING_REQUEST" /&
&/intent-filter&
&/receiver&
&/application&
&/manifest&
main.xml 布局
&LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" &
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnSearch"
android:text="btnSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnExit"
android:text="btnExit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnDis"
android:text="btnDis"
&ToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tbtnSwitch"
android:text="tbtnSwitch"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/lvDevices"
&/LinearLayout&
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具}

我要回帖

更多关于 android 蓝牙音频 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信