VS2019 Xamarin.Android开发蓝牙通讯

c# 专栏收录该内容
5 篇文章 0 订阅

第一步

新建项目

注意:不要选成移动应用xamarin.Forms要选android应用(Xamarin) xamarin.Forms 和 Xamarin.Android还是有区别的。小项目就用Xamarin.Android就好了

选择空白模板

作为通讯App 必定需要 Server端 所以我们在这里在新建一个Client端 原本的app1项目作为server端

在解决方案上右键 添加新的项目

继续选 Android 应用

起名字叫app1Client

继续选空白模板

OK到这里第一步建立项目就完成了

下一步我们将开始配置项目了。

第二步

配置项目

Android在使用蓝牙时需要添加4个权限

在app1项目上 右键属性 Android清单 内找到 所需权限 勾选

BLUETOOTH(利用这个权限去执行蓝牙通信)

BLUETOOTH_PRIVILEGED(配对连接时需要)

BLUETOOTH_ADMIN(让app拥有启动设备发现或操纵蓝牙设置,必须声明BLUETOOTH_ADMIN权限)

注意:真机android版本6.0及以上使用蓝牙搜索需要开发权限ACCESS_COARSE_LOCATION、ACCESS_FINE_LOCATION

将App1 和 App1Client 2个项目都添加上述权限

第三步 编写代码

怎么添加界面和按钮一类的我就不详细写了 这里主要写怎么实现通讯的部分

1.获得蓝牙设备 这需要用到 BluetoothAdapter 这个类 

private readonly BluetoothAdapter localAdapter; 
localAdapter = BluetoothAdapter.DefaultAdapter;

localAdapter 就是默认蓝牙适配器了

BluetoothAdapter 类 提供了 蓝牙适配器的状态 以及打开蓝牙 关闭蓝牙等一些方法 具体内容请自己点进该类查看

2获取建立服务端的监听和通讯线程

我先写下思路 我们首先需要一个线程来监听是否有客户端来请求建立连接

如果建立连接成功就去建立一个通讯线程来读取Client端发来的数据..是不是很简单

下面我们来是实现

监听线程方法

//在你想要启动监听线程的地方添加这个线程
Thread t = new Thread(Monitor); 
t.Start();

public void Monitor()
        {
            BluetoothServerSocket serverSock = localAdapter.ListenUsingRfcommWithServiceRecord("Bluetooth", Java.Util.UUID.FromString("0000-0000-0000-0000-1234567"));
            BluetoothSocket sock = null;
            while (true)
            {
                try
                {
                    sock = serverSock.Accept();
                }
                catch (System.Exception)
                {
                }
                Thread t = new Thread(Connected);
                t.Start(sock);
            }

核心方法 localAdapter.ListenUsingRfcommWithServiceRecord

        //
        // 摘要:
        //     Create a listening, secure RFCOMM Bluetooth socket with Service Record.
        //
        // 参数:
        //   name:
        //     service name for SDP record
        //
        //   uuid:
        //     uuid for SDP record
        //
        // 返回结果:
        //     To be added.
        //
        // 异常:
        //   T:Java.IO.IOException:
        //     on error, for example Bluetooth not available, or insufficient permissions, or
        //     channel in use.
        //
        // 言论:
        //     Portions of this page are modifications based on work created and shared by the
        //     Android Open Source Project and used according to terms described in the Creative
        //     Commons 2.5 Attribution License.
        [Register("listenUsingRfcommWithServiceRecord", "(Ljava/lang/String;Ljava/util/UUID;)Landroid/bluetooth/BluetoothServerSocket;", "")]
        public BluetoothServerSocket ListenUsingRfcommWithServiceRecord(string name, UUID uuid);

public BluetoothServerSocket ListenUsingRfcommWithServiceRecord(string name, UUID uuid); 该方法 需要个一个连接名称和一个 UUID 并返回一个BluetoothServerSocket 对象 如果你会Socket的话接下来就很简单了。

BluetoothServerSocket 类提供了几个建立连接的方法

Accept()方法返回了一个BluetoothSocket对象

BluetoothSocket 类提供了蓝牙适配输入输出流的操作

public Stream OutputStream { get; } //输入流 读操作使用该流
public Stream InputStream { get; } //输出流 写操作使用该流
public BluetoothDevice RemoteDevice { get; } //远程设备属性

接下来我们要实现通讯线程

                Thread t = new Thread(Connected);
                t.Start(sock);

当建立连接成功 执行该代码来新建一个通讯线程 

由于通讯线程需要该连接的套接字 所以我们要把建立连接成功后的套接字作为参数传递到线程函数内

通讯线程方法

        public void Connected(object sock)
        {
            BluetoothSocket mSock = (BluetoothSocket)sock;
            byte[] rebuf = new byte[1024];         
            while (true)
            {
                int len =  mSock.InputStream.Read(rebuf,0, rebuf.Length);

                if (len > 0)
                {
                    byte[] rebuf2 = new byte[len];
                    Array.Copy(rebuf, 0, rebuf2, 0, len);
                    string str = System.Text.Encoding.ASCII.GetString(rebuf2);
                    Toast.MakeText(this, str, ToastLength.Short).Show();

                }
                Thread.Sleep(100);
                
            }

由于线程启动时传递的参数只能是Object对象所以先将 Object对象转换为BluetoothSocket 对象  BluetoothSocket mSock = (BluetoothSocket)sock;

然后我们在新建一个缓冲区 用来读取数据 由于我们现在还不知道将要读取的数据有多大。我们可以先建立一个和蓝牙读取缓冲区大小一样的byte数组 byte[] rebuf = new byte[1024]; 当然我这里只用了1KB 蓝牙的读取缓冲区默认好像是4KB 

接下来我们就每100毫秒区读一下是否有数据 当然你可以用更快的速度来读取如果你一个包的大小很小的话

//
        // 摘要:
        //     当在派生类中重写时,从当前流读取字节序列,并将此流中的位置提升读取的字节数。
        //
        // 参数:
        //   buffer:
        //     字节数组。 当此方法返回时,此缓冲区包含指定的字符数组,此数组中 offset 和 (offset + count - 1) 之间的值被从当前源中读取的字节所替换。
        //
        //   offset:
        //     buffer 中的从零开始的字节偏移量,从此处开始存储从当前流中读取的数据。
        //
        //   count:
        //     要从当前流中最多读取的字节数。
        //
        // 返回结果:
        //     读入缓冲区中的总字节数。 如果很多字节当前不可用,则总字节数可能小于请求的字节数;如果已到达流结尾,则为零 (0)。
        //
        // 异常:
        //   T:System.ArgumentException:
        //     offset 和 count 的总和大于缓冲区长度。
        //
        //   T:System.ArgumentNullException:
        //     buffer 为 null。
        //
        //   T:System.ArgumentOutOfRangeException:
        //     offset 或 count 为负数。
        //
        //   T:System.IO.IOException:
        //     出现 I/O 错误。
        //
        //   T:System.NotSupportedException:
        //     流不支持读取。
        //
        //   T:System.ObjectDisposedException:
        //     在流关闭后调用方法。
        public abstract int Read(byte[] buffer, int offset, int count);


        int len =  mSock.InputStream.Read(rebuf,0, rebuf.Length);

Read方法返回一个int 类型的对象 表示读到的数据长度

如果数据长度 > 0

我们就可以解析了

byte[] rebuf2 = new byte[len];                   
Array.Copy(rebuf, 0, rebuf2, 0, len);
string str = System.Text.Encoding.ASCII.GetString(rebuf2);

新建一个 读取到长度大小的byte数组 将读到的数据拷贝到新的数组内进行解析。到这一步 一个最基础的服务端就完成了

To be continued .......

下集预告:明天我们将讲解如何写一个客户端来与服务端建立连接

-------------------------------------------------------------------------------------------------

本想把客户端的也好好写一篇。可惜工作太忙时间有限。

我把源码放出来。。

BLETEST.rar_Xamarin蓝牙通讯-Android代码类资源-CSDN下载

有需求的自己下载吧

----------------------------------------------------------------------------------------

对一些大家提出的问题回答

1.说缺少文件的。应该是缺少Xamarin

感谢下载 Xamarin - Visual Studio

 添加Xamarin

2.无法连接服务端的

 

请修改client端

MainActivity.cs文件内的代码

void Monitor() 函数内我限定了服务端是HUAWEI P30的设备,请修改为你自己做服务端的设备名称。

  • 8
    点赞
  • 9
    评论
  • 12
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值