android 蓝牙通讯测试工具,Android Bluetooth 学习(2)应用层实现蓝牙设备查找、tcp_ip通信...

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秒内搜索到它。

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模块需要在系统setting模块中,完成蓝牙的配对,只有配对成功的,才能进行socket通信(具体如何配对和如何自动配对,将在bluetoot3或者4中进行讲解)

AndridManifest.xml

package="com.example.thecaseforbluetooth"

android:versionCode="1"

android:versionName="1.0" >

android:minSdkVersion="8"

android:targetSdkVersion="15" />

android:icon="@drawable/ic_launcher"

android:label="@string/app_name"

android:theme="@style/AppTheme" >

android:name=".BluetoothActivity"

android:label="@string/title_activity_bluetooth" >

main.xml

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="启动服务端"

/>

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"

/>

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 adapter;

public ArrayList list =new ArrayList();

private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

Set 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(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

{

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();

}

}

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值