当前位置:阳光沙滩 >Android > 查看文章
阿里云优惠码

1.Android中蓝牙开发步骤 (流程)

蓝牙在我们做智能手表中,必须使用到的。即使不同的需求开发,但也可以抽取出下面的步骤。

下面的流程,如果已经完成了这一步,就可以去到下一步。比如说,已经打开了蓝牙,那么蓝牙肯定是可用的。这才真的沒必要检测蓝牙是否可用了。

如果已经打开了,当然也沒有必要再次执行打开的代码啦!是吧!又比如说,已经配对了蓝牙,就沒必要再配对了。在连接之前进行检查一下就可以了嘛!

权限:

<uses-permission android:name="android.permission.BLUETOOTH"/>  
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

 

 

1.1.1、检查是否支持蓝牙设备:

我们通过BluetoothAdapter这个类去获取适配器,如果沒有则不支持蓝牙通信,也就是该设备沒有蓝牙模块。

不管是我们自己的设备一定有蓝牙还是別人的设备知道一定有。大家都要养成习惯,在使用之前检查一下是否支持蓝牙。

 /**
     * 参数 无
     * 返回值 true 表示可以用嘛,否则不可以
     * 异常 无
     * 描述:这个方法用于检查蓝牙是否可用
     */
    public boolean checkBtIsValueble() {

        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null) {
            return false;
        } else {
            return true;
        }

    }

 

 

根据返回值,如果不支持是吧,那只好提示用户不支持蓝牙。如果支持蓝牙,则进行下一步:

1.2.2、判断蓝牙可不可用(有沒有打开?3:打开蓝牙)

判断蓝牙有沒有打开的话,可以通过适配器的isEnable()方法来判断。

打开蓝牙的方法有两种,一种是静默打开(个別系统不同,可能也要用户授权),另外一种则需要让用户授权,可以检测到打开的状态。

  • 第一种打开方式,通过意图的形式来打开,这种形式不需要声明权限,但是要经过用户的授权,请看码:
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);

接着呢?看到 ForResult当然是去接收结果啦,是吧!

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        //判断是不是启动蓝牙的结果
        if (requestCode == REQUEST_ENABLE_BT) {
            if (resultCode == Activity.RESULT_OK) {
                //成功
                Toast.makeText(this, "蓝牙开启成功...", Toast.LENGTH_SHORT).show();
                isOpenBlueToolth = true;
            } else {
                //失败
                Toast.makeText(this, "蓝牙开启失败...", Toast.LENGTH_SHORT).show();
                isOpenBlueToolth = false;
            }
        }
    }

 

RESULT_OK则表示成功,RESULT_CANCELED则表示取消了

或者你也可以监听广播(但要記得注销广播),创建一个广播接收者,设置过滤为:ACTION_STATE_CHANGED

本质:蓝牙的状态发生改变这后,系统就会发出广播的,具体的含义如下:

EXTRA_STATE:直接翻译是额外状态

EXTRA_PREVIOUS_STATE: 这个是这前的状态

这上面两个状态的值是下面的其中一个:

STATE_TURNING_ON:正在玩命打开中…

STATE_ON:已经开启了

STATE_TURNING_OFF:使劲关闭中…

STATE_OFF:已经关闭了

  • 第二种很简单,小手一抖,一行代码的事。但是要添加权限。为静默打开形式,对于某些系统来说,是无效的。还是需要用户的授权
 if (!defaultAdapter.isEnabled()) {
            defaultAdapter.enable();
        }

好,就这样子,就打开了,核心代码就一行。enable()就可以了。不要忘记权限

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

PS:关闭蓝牙为disable();

1.3.3、根据不同的角色,明确需求

这里面的角色,只有两种嘛,要么是客户端,要么是服务端。其实蓝牙是BluetoothSocket,我们小时候学java的时候就学过网络编程,也有Scoket,是吧!

首先是先有服务端,阻塞式地等客户端连接进来。

这里也一样,要分清楚是服务端还是客户端,这是第一点。另外就是要記得,关于网络访问,数据传输这些是耗时操作。要注意线程哈!

1.4.3.1客户端

如果是客户端,那我们的目标是什么?当然是连接到服务端去,是吧!首先呢,我们要找到服务端。这时要进行蓝牙扫描啦!

怎么扫描周围的服务端呢?看码:

//扫描蓝牙
isDiscovering = defaultAdapter.startDiscovery();

//注册一个广播接收者來获取到扫描的蓝牙设备
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);

 

广播接收者的代码如下:

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (BluetoothDevice.ACTION_FOUND.equals(action)) {

                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                Log.d(TAG, "扫描到了 --- > name : " + device.getName() + "-----> address:" + device.getAddress() + isDiscovering);
                mAdapter.add(device.getAddress());
                mAdapter.notifyDataSetChanged();

            }
        }
    };

 

解释一下吧:我们通过开启扫描,然后就进行对周围的设备进行扫描啦,記得好像是扫描12秒的。不太清楚了,想查个究竟的可以上网问,或者自己用秒表测試一下哈,嘻嘻!

每扫描到一个设备的话,就会收到一次广播啦。这里要一定要注意哈,设备的名字可能是空的,但地址一定是有的。所以在使用设备名字时,一定要記得判空哪

就这样子,我们静悄悄地就可以发现周围的设备了,或许你又有疑问了,为什么手机谁连谁都可以呢?这到底是为什么呢?因为他们同时实现了客户端和服务端的功能。实际开发中也可以根据需求这样做。

有了设备之后,我们可以获取到设别的物理地址。接下来就是要进行配对了。这里要说一下的时, 配对和连接是两个不同的概念哦!

你可以理解为,配对是为了验证身份,而连接则是创建传送数据的通道

在配对之前,要获取到远程的设备(服务端),怎么获取呢,看下面的代码吧:

 if (mBluetoothAdapter == null) {
                mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
                updateMsg("去获取适配器...");
            }
            updateMsg("去获取远程设备...");
            mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(macAddress);

            try {
                updateMsg("去获取...BluetoothSocket...");
                socket = mBluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString(UUID_STR));
            } catch (IOException e) {

                updateMsg("错误:socket获取失败..." + e.toString());
            }

 

这里面要理解的是通过物理地址来获取到远程的设备,然后需要UUID作为了一个标识。类比我们小时候学的Socket,这里的mac地址呢,就类似于Ip地址,而UUID则类似于端口号。这样相信聪明的你一定理解了是吧!

怎么进行配对和判断有沒有配对呢?

先来判断是否有配对吧:

在配对之前呢,我们要习惯先取消掉发现设备(Discovery()):cancelDiscovery();

updateMsg("取消蓝牙查找(搜索)...");
            mBluetoothAdapter.cancelDiscovery();

            // 连接建立之前的先配对
            try {
                if (mBluetoothDevice.getBondState() == BluetoothDevice.BOND_NONE) {
                    Method creMethod = BluetoothDevice.class.getMethod("createBond");

                    updateMsg("正开始进行配对蓝牙...");

                    creMethod.invoke(mBluetoothDevice);
                } else {
                    updateMsg("已经配对");
                }

            } catch (Exception e) {
                updateMsg("无法进行配对..." + e.toString());
            }

 

如果上面沒有什么问题的主知,那么就可以连接了,是吧!哈哈,此处应有掌声哈!

话不多说,程序员更多的是用代码来表达自己的想法:

//连接操作
            try {
                socket.connect();
                updateMsg("连接状态..." + socket.isConnected());


            } catch (IOException e) {

                updateMsg("连接失败" + e.toString());

                try {
                    if (socket != null) {
                        socket.close();
                        socket = null;
                    }
                } catch (IOException e2) {
                    updateMsg("关闭socket失败" + e2.toString());
                }

            }

 

这样子,连接了。这和Socket是一样的道理嘛!

到这里的话,客户端的准备工作就搞定了。但是这些操作要在子线程中完成,知道嗎?

接下来,当然是发数据和接收数据,可以通过getInputStream(),来获取输入流,用getOutputStream来获取输入流。

使用完成之后要記得关闭流,对于异常可以统一处理,使用代号也行,按自己的习惯或者公司的开发标准。

到这里就不说发送数据了,你爱咋咋地!下面就说说服务端吧!

1.5.3.2服务端的业务逻辑

蓝牙和Socket不同的是mac地址不是和ip地址那样预先知道的。所以服务端要被客户端扫描到。一般情况下,是不可见的。那么这个时候,客户端对服务端进行扫描时,就需要让服务端可见啦!

 Intent btIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
 //设置蓝牙的可见时间
 btIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 3600);
 startActivity(btIntent);
 Toast.makeText(WearMainActivity.this, "正打开蓝牙可见..", Toast.LENGTH_SHORT).show();

这里参数哈,我靠,一看3600是吧,那我就不客气了,来个10000怎么样呢?其实,最多只能是3600秒。默认貌似是120秒吧,我忘记了,老了!

作为服务端,它应该和ServiceSocket一样,去等待着客户端连接进来。一般在子线程中开一个死循环去等待。由于app在多数情况下是一对一的。accept方法是阻塞的。所以呢,可以不死循环去accept()客户端进来。

当然,这里要根据需求来定啦。不能这么死板。多数情况下,我们会使用可控制的循环去等待客户端进来。下面例子直接等待一个连接进来就完事了哈:

  try {
        socket = mmServerSocket.accept();
       } catch (IOException e) {
        updateViewSafely("accept失败.." + e.toString());
       }

如果有客户端进来的话,那么就可以获取到了socket。那么还是一样的方法,通过socket来获取到输入输出流。

InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();

接下来想干嘛干嘛去,要注意对异常的处理,关流等操作。一般来说,操作这些数据的在子线程,如果要更新UI,不要搞错线程。通常用Handler来处理消息

1.6.4.0末言

到这里貌似写完了哈,不详细的地方自己想去,也可以问我,反正我也不会告诉你的。有错的地方嘛,可以到社区当众指出!

7K
相关文章
为您推荐
各种观点

报歉!评论已关闭.