Android中经典蓝牙开发步骤 (流程)

来源:互联网 发布:淘宝争议处理规范2016 编辑:程序博客网 时间:2024/06/05 18:17

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

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

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

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

权限:

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

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

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

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

    /**     * 参数 无     * 返回值 true 表示可以用嘛,否则不可以     * 异常 无     * 描述:这个方法用于检查蓝牙是否可用     */    public boolean checkBtIsValueble() {        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();        if (mBluetoothAdapter == null) {            return false;        } else {            return true;        }    }

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

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

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

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

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

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

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来获取输入流。

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

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

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来处理消息

4.0末言

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


0 0
原创粉丝点击