Android蓝牙开发——经典蓝牙的连接

1.蓝牙的基本操作
蓝牙权限

android.permission.BLUETOOTH
//允许程序连接到已配对的蓝牙设备,请求连接/接收连接/传输数据需要改权限, 主要用于对配对后进行操作.
android.permission.BLUETOOTH_ADMIN
//允许程序发现和配对蓝牙设备, 该权限用来管理蓝牙设备, 有了这个权限, 应用才能使用本机的蓝牙设备.
BluetoothAdapter

BluetoothAdapter代表了移动设备的本地的蓝牙适配器, 通过该蓝牙适配器可以对蓝牙进行基本操作

//获取蓝牙适配器对象.
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
开关蓝牙(推荐请求用户打开)

//直接打开
mBluetoothAdapter.enable();
//请求用户打开蓝牙
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(intent);
//关闭蓝牙
mBluetoothAdapter.disable();
蓝牙是否可用

//蓝牙是否可用,返回boolean值 true可用 false不可用
mBluetoothAdapter.isEnabled();
蓝牙可被发现及时间设置


//可被发现
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 600);
//默认120秒
startActivity(intent);
搜索蓝牙

蓝牙搜索在android6.0以后需要加上一个模糊定位的权限,并动态申请,虽然有些手机不加权限也能搜索到蓝牙设备,

但是大多会出现蓝牙一直等待搜索,蓝牙列表无法弹出。

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
//扫描蓝牙的方法,返回boolean值
//开始扫描
mBluetoothAdapter.startDiscovery();
//是否正在扫描
mBluetoothAdapter.isDiscovering();
//停止扫描
mBluetoothAdapter.cancelDiscovery();
startDiscovery()是一个异步方法,在搜索蓝牙设备的过程中,系统可能会发送以下三个广播:

ACTION_DISCOVERY_START(开始搜索)

ACTION_DISCOVERY_FINISHED(搜索结束)

ACTION_FOUND(找到设备)。

蓝牙地址

//获取本地蓝牙地址 返回String
mBluetoothAdapter.getAddress();
//检查蓝牙地址 蓝牙地址字母必须大写, 例如 : "00:43:A8:23:10:F0";
mBluetoothAdapter.checkBluetoothAddress(String address);
获取远程蓝牙设备

BluetoothDevice 代表了一个远程的蓝牙设备, 通过这个类可以查询远程设备的物理地址, 名称, 连接状态等信息;

//作用 : 根据蓝牙的物理地址获取远程的蓝牙设备, 如果地址不合法, 就会产生异常;
//返回值 : 获取到的BluetoothDevice对象;
public BluetoothDevice getRemoteDevice(String address);
蓝牙名字


//设置名字
mBluetoothAdapter.setName();
//得到名字
mBluetoothAdapter.getName();
创建监听


//创建一个监听Rfcommon端口的蓝牙监听, 使用accept()方法监听, 并获取BluetoothSocket对象; 
// 该系统会根据一个服务名称(name)和唯一的识别码(uuid)来创建一个SDP服务, 
// 远程蓝牙设备可以根据唯一的UUID来连接这个SDP服务器;
public BluetoothServerSocket listenUsingRfcommonWithServiceRecord(String name, UUID uuid);
// 参数 : name : SDP服务器名称, UUID, SDP记录下的UUID;
// 返回值 : 正在监听蓝牙端口;
UUID

在蓝牙中,每个服务和服务属性都唯一地由全局唯一标识符,Universally Unique Identifier(UUID)来校验。UUID相当于Socket的端口,

而蓝牙地址相当于Socket的IP。两个蓝牙设备进行连接时需要使用同一个UUID, 这是一个服务的唯一标识。

于普通蓝牙适配器和android手机蓝牙模块连接的UUID

//手机连接的UUID
//设备连接的UUID由厂商决定。
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
其他UUID可看http://blog.csdn.net/spmno/article/details/6931941
蓝牙连接
蓝牙客户端 BluetoothSocket,蓝牙服务端 BluetoothServerSocket 匹配成功然后使用connect()方法连接
2.具体代码(扫描蓝牙)没有其他蓝牙设备,使用两部手机替代。

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:onClick="startBluetooth"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="开启蓝牙"/>
    <Button
        android:onClick="searchBluetooth"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="搜索蓝牙"/>
    <ListView
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>
两个按钮,一个ListView显示蓝牙设备名字

初始画数据,设置适配器

ListView mListView;
BluetoothAdapter mBluetoothAdapter;
ArrayAdapter<String> mAdapter;
//存储蓝牙设备名字
List<String> deviceNames = new ArrayList<>();
//存储蓝牙设备
List<BluetoothDevice> devices = new ArrayList<>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    mListView = (ListView) findViewById(R.id.listview);
    mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, deviceNames);
    mListView.setAdapter(mAdapter);
}
开启蓝牙


//按钮点击事件 开启蓝牙
public void startBluetooth(View view) {
    //设置蓝牙可被发现
    Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
    //设置可被发现的时间 1200秒
    intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,1200);
    startActivity(intent);
}
搜索蓝牙 需要动态权限

//搜索蓝牙
public void searchBluetooth(View view) {
    //蓝牙开启状态
    if (mBluetoothAdapter.isEnabled()) {
        //动态权限
        if (Build.VERSION.SDK_INT > 23) {
            int check = checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION);
            if (check == PackageManager.PERMISSION_GRANTED) {
                //开始扫描
                startSearch();
            } else {
                requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},1);
            }
        } else {
            startSearch();
        }
        startSearch();
    } else {
        //如果蓝牙没开启
        startBluetooth(view);
    }
}
//开始搜索蓝牙
private void startSearch() {
    //如果没在搜索
    if (!mBluetoothAdapter.isDiscovering()) {
        //搜索蓝牙设备
        mBluetoothAdapter.startDiscovery();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode ==1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        startSearch();
    } else {
        Toast.makeText(this, "必须获取地理位置才能扫描蓝牙设备", Toast.LENGTH_SHORT).show();
    }
}
记得在AndroidManifest文件中在加上模糊地理位置权限

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
扫描蓝牙时,系统会发送广播,通过广播接收者获得扫描到的蓝牙设备


//广播接收者
private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        //如果发现蓝牙设备
        if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
            //BluetoothDevice 代表了一个远程的蓝牙设备, 通过这个类可以查询远程设备的状态信息;
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            //取得蓝牙设备的名字(名字可能为空,空则设置名字为匿名) 以便显示到ListView
            String name = device.getName() == null ? "匿名" : device.getName();
            deviceNames.add(name);
            mAdapter.notifyDataSetChanged();
            devices.add(device);
        }
    }
};
注册广播接收者


@Override
protected void onResume() {
    super.onResume();
    //注册
    registerReceiver(receiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
}

@Override
protected void onPause() {
    super.onPause();
    //解绑
    unregisterReceiver(receiver);
}
暂时效果


3.具体代码(蓝牙连接)

两个蓝牙手机链接,需要有服务器客户端

UUID


//手机连接的UUID
//设备连接的UUID由厂商决定。
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
服务端


class BluetoothServer extends Thread {
    @Override
    public void run() {
        super.run();
        //服务
        BluetoothServerSocket bluetoothServerSocket;
        try {
            bluetoothServerSocket = mBluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(
                    mBluetoothAdapter.getName(),uuid);
            BluetoothSocket socket = bluetoothServerSocket.accept();
            while (socket.isConnected()) {
                InputStream inputStream = socket.getInputStream();
                int len = 0;
                byte[] buffer = new byte[1024];
                while ((len = inputStream.read(buffer)) != -1) {
                    Log.e("TAG",new String(buffer,0,len,"utf-8"));
                }
            }
            //将服务端关闭,不可能1对多,所以,只要获取了客户端,那么服务端就可以关闭了
            bluetoothServerSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
然后在开启蓝牙后开启服务,即在searchBluetooh中调用startServer方法

BluetoothServer server;
public void startServer() {
    if (server == null) {
        server = new BluetoothServer();
        server.start();
    }
}
客户端

MainActivity 实现OnItemClickListener 然后重写方法

mListView.setOnItemClickListener(this);
//客户端 搜索出蓝牙后,ListView Item点击事件 链接服务端
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    //点击列表,去请求服务器
    final BluetoothDevice device = devices.get(position);
    new Thread() {
        @Override
        public void run() {
            super.run();
            try {
                BluetoothSocket socket = device.createInsecureRfcommSocketToServiceRecord(uuid);
                //链接
                socket.connect();
                OutputStream os = socket.getOutputStream();
                os.write("连接蓝牙服务器成功".getBytes());
                os.flush();
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }.start();
}
 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值