Bluetooth结构
1、JAVA层
frameworks/base/core/java/android/bluetooth/
包含了bluetooth的JAVA类。
2、JNI层
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秒内搜索到它。 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模块需要在系统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" > <uses-sdk 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" > <activity 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>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" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnSearch" android:text="查找设备" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnExit" android:text="退出应用" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnDis" android:text="设置可被发现" /> <Button 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="开/关 蓝牙设备" /> <ListView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/lvDevices" /> </LinearLayout>BluetoothActivity.java
package com.example.thecaseforbluetooth; import java.util.ArrayList; import java.util.Set; import android.app.Activity; 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.os.Bundle; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.Toast; import android.widget.ToggleButton; public class BluetoothActivity extends Activity { public Button searchBtn;//搜索蓝牙设备 public Button exitBtn;//退出应用 public Button discoverBtn;//设置可被发现 public ToggleButton openBtn;//开关蓝牙设备 public Button serverbtn; public ListView listView;//蓝牙设备清单 public ArrayAdapter<String> adapter; public ArrayList<String> list =new ArrayList<String>(); private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); Set<BluetoothDevice> bondDevices ; public Context context ; @Override 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() { @Override 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() { @Override public void onClick(View v) { // TODO Auto-generated method stub BluetoothActivity.this.finish(); } }); //设置蓝牙设备可发现 discoverBtn.setOnClickListener(new OnClickListener() { @Override 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() { @Override 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() { @Override 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()); } @Override 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); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } private final BroadcastReceiver searchReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String action = intent.getAction(); BluetoothDevice device = null; 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 { @Override 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.thecaseforbluetooth; 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.thecaseforbluetooth; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.os.Message; import android.util.Log; import android.widget.Toast; public class ServerThread extends Thread { public BluetoothServerSocket mserverSocket; public BluetoothAdapter bluetoothAdapter; public BluetoothSocket socket; public Context context; public ServerThread(BluetoothAdapter bluetoothAdapter,Context context) { this.bluetoothAdapter = bluetoothAdapter; this.context = context; } public void run() { try { /* 创建一个蓝牙服务器 * 参数分别:服务器名称、UUID */ mserverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(Bluetoothprotocol.PROTOCOL_SCHEME_RFCOMM, UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); // /* 接受客户端的连接请求 */ socket = mserverSocket.accept(); //下面代码作者偷懒,读写另外起一个线程最好 //接收数据 byte[] buffer = new byte[1024]; int bytes; InputStream mmInStream = null; try { 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<bytes; 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.thecaseforbluetooth; import java.io.IOException; import java.io.OutputStream; import java.util.UUID; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.widget.Toast; public class ClientThread extends Thread { public BluetoothSocket socket; public BluetoothDevice device; public Context context; public ClientThread(BluetoothDevice device,Context context){ this.device = device; this.context = context; } public void run() { try { //创建一个Socket连接:只需要服务器在注册时的UUID号 socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); //连接 socket.connect(); //下面代码作者偷懒,读写另外起一个线程最好 //发送数据 if (socket == null) { Toast.makeText(context, "链接失败", 5000).show(); return; } System.out.println("zhoulc client"); while(true){ try { 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(); } } }