Unity for Android使用蓝牙低功耗Bluetooth LE

news2024/12/25 9:31:32

Unity2021.3.35f1

插件:Bluetooth LE for iOS and Android v2.3.unitypackage

1、将插件资源包导入unity中

2.修改插件中的AndroidManifest文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.unity3d.player" android:installLocation="preferExternal" android:versionCode="1" android:versionName="1.0">
  <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
  <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  <uses-permission android:name="android.permission.BLUETOOTH" />
  <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
  <application android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="true">
    <activity android:name="com.unity3d.player.UnityPlayerProxyActivity" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">
    </activity>
    <activity android:name="com.unity3d.player.UnityPlayerActivity" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity android:name="com.unity3d.player.UnityPlayerNativeActivity" android:label="@string/app_name" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen">
      <meta-data android:name="android.app.lib_name" android:value="unity" />
      <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />
    </activity>
    <meta-data android:name="platform_high" android:value="1" />
    <meta-data android:name="enable_entitlementcheck" android:value="0" />
  </application>
</manifest>

3.编写UI

2个按钮:StartScanningBtn(扫描)、DisconnectBtn(断开连接)

2个Text

1个Container(带Vertical Layout Group),用于显示扫描到的终端

4.制作预制体DeviceInfo,一个Button一个Text,点击按钮可连接蓝牙终端

预制体上挂一个脚本DeviceInfo,代码始下

using UnityEngine;
using UnityEngine.UI;

public class DeviceInfo : MonoBehaviour
{
    public Button btnConnect;
    public Text textName;
    public Text textAddress;
}

5.编写BlueToothTest.cs代码

using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;

public class BlueToothTest: MonoBehaviour
{
    //连接的蓝牙mac地址
    private string bleAddress;
    //表示是否开始扫描
    private bool isScanning;
    //表示是否已经蓝牙初始化
    private bool isInit;
    //设备信息预制体 当扫描到一个设备时就会创建一个实例并放到滚动视图中去
    public GameObject deviceInfoPrefab;
    //滚动视图的容器结点
    public Transform container;
    //提示的文本信息框  连接提示。。。
    public Text text;
    //提示的其他文本信息框  接受数据提示。。。
    public Text otherText;
    //断开连接按钮
    public Button disConnectBtn;
    //开始扫描按钮
    public Button startScanningBtn;
    //以设备名字做个存储,相同名字的就忽视不在扫描
    private HashSet<string> deviceHashSet = new HashSet<string>();
    //设备名、设备地址字典
    private Dictionary<string, string> deviceDictionary = new Dictionary<string, string>();

    void Start()
    {
        Input.location.Start(); //定位
        InitBluethood();
        startScanningBtn.onClick.AddListener(() =>
        {
            StartScnnning();
        });
        disConnectBtn.onClick.AddListener(() =>
        {
            DisConnect();
        });        
    }

    /// <summary>
    /// 初始化蓝牙设备
    /// </summary>
    private void InitBluethood()
    {
        if (!isInit)
        {
            BluetoothLEHardwareInterface.Initialize(true, false, () =>
            {
                Show("蓝牙初始化成功");//初始化成功执行回调
                isInit = true;
            },
           (error) =>
           {
               Show(error.ToString());//初始化失败的回调响应
           });
        }
    }
    /// <summary>
    /// 扫描设备
    /// </summary>
    private void StartScnnning()
    {
        if (!isScanning && isInit)
        {
            Show("扫描设备中");
            Input.location.Start(); //定位
            Invoke("FindDevice", 1f);
            isScanning = true;
        }
    }
    public void FindDevice()
    {
        BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null, (address, name) =>
        {
            if (deviceHashSet.Contains(name)) return;
            CreationTextPrefab(address, name);
            //扫描处理,加入设备列表              
            AddPeripheral(name, address);
            deviceHashSet.Add(name);

        }, (address, name, rssi, advertisingInfo) =>
        {
            if (deviceHashSet.Contains(name)) return;
            CreationTextPrefab(address, name);
            AddPeripheral(name, address);
            deviceHashSet.Add(name);
        });
    }

    public void Show(string info)
    {
        text.text = info;
    }
    /// <summary>
    /// 创建提示信息预制件
    /// </summary>
    /// <param name="address"></param>
    /// <param name="name"></param>
    private void CreationTextPrefab(string address, string name)
    {
        GameObject game = Instantiate<GameObject>(deviceInfoPrefab);
        DeviceInfo info = game.GetComponent<DeviceInfo>();
        info.textName.text = name;
        info.textAddress.text = address;
        game.transform.localScale = Vector3.one;
        game.transform.SetParent(container);
        info.btnConnect.onClick.AddListener(() =>
        {
            if (deviceHashSet.Contains(name)) //找到名字一样的设备
            {
                BluetoothLEHardwareInterface.StopScan(); //停止扫描
                ConnectBluetooth(deviceDictionary[name]);  //开始连接
            }
        });
    }

    /// <summary>
    /// 更新存储要连接设备的名字,是否扫描到
    /// </summary>
    /// <param name="name"></param>
    /// <param name="address"></param>
    public void AddPeripheral(string name, string address)
    {
        deviceDictionary.Add(name, address);
    }
    /// <summary>
    /// 开始连接设备
    /// </summary>
    public void ConnectBluetooth(string adress)
    {
        Show("开始连接设备");
        try
        {
            BluetoothLEHardwareInterface.ConnectToPeripheral(adress, null, null, (address, serviceUUID, characteristicUUID) =>
            {
                otherText.text += "连接成功\n";
                SubscribeCharacteristicWithDeviceAddress(address, serviceUUID, characteristicUUID);
            });
        }
        catch (Exception e)
        {
            Show("连接失败");
        }
    }

    /// <summary>
    /// 连接成功的回调
    /// </summary>
    private void SubscribeCharacteristicWithDeviceAddress(string address, string serviceUUID, string characteristicUUID)
    {
        if(!string.IsNullOrEmpty(serviceUUID) && !string.IsNullOrEmpty(characteristicUUID))
        {
            otherText.text += "正在订阅消息:"+ serviceUUID + ":" + characteristicUUID + "\n"; 
            bleAddress = address;
            BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress(address, serviceUUID, characteristicUUID, delegate { }, OnCharacteristicNotification);

        }
    }
    /// <summary>
    /// 收到数据
    /// </summary>
    /// <param name="arg1"></param>
    /// <param name="arg2"></param>
    /// <param name="arg3"></param>
    private void OnCharacteristicNotification(string arg1, string arg2, byte[] arg3)
    {
        //Show("接收到数据");
        otherText.text = "连接成功" + "\narg1=" + arg1 + "\narg2=" + arg2 + "\n";
        Show(ByteArrayToString(arg3));
    }
    /// <summary>
    /// 断开连接
    /// </summary>
    public void DisConnect()
    {
        BluetoothLEHardwareInterface.DisconnectPeripheral(bleAddress, (bleAddress) =>
        {
            Show(bleAddress + "已经断开");
            otherText.text = "";
            isScanning = false;
        });
    }
    /// <summary>
    /// 字节组转换为字符串
    /// </summary>
    /// <param name="ba"></param>
    /// <returns></returns>
    public static string ByteArrayToString(byte[] ba)
    {
        string hex = BitConverter.ToString(ba);
        return hex.Replace("-", "");
    }
}

6.挂载脚本并赋值,打包apk运行

注:本文参考了Unity插件-适用于iOS,tvOS和Android的蓝牙LE(2.3)的测试使用方法_unity蓝牙-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2132193.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

交叉编译Python3.8

1. 交叉编译python 工程组织&#xff1a;根目录设置为/home/a123/xxx/tools/4python 内容创作不易&#xff0c;对您有帮助的话&#xff0c;可以支持打赏一下下 配置脚本统一命名为conig_arm/pc_<package>.sh 交叉编译出的头文件以及动态库文件统一放在cross_compile_de…

“爱学术”期刊采编系统的设计与实现---附源码 76126

摘 要 随着互联网趋势的到来&#xff0c;各行各业都在考虑利用互联网将自己推广出去&#xff0c;最好方式就是建立自己的互联网系统&#xff0c;并对其进行维护和管理。在现实运用中&#xff0c;应用软件的工作规则和开发步骤&#xff0c;采用SpringBoot技术建设“爱学术”期刊…

【Qt】样式属性

样式属性 QSS 中的样式属性⾮常多, 不需要都记住. 核⼼原则还是⽤到了就去查. ⽂档的 Qt Style Sheets Reference 章节详细介绍了哪些控件可以设置属性, 每个控 件都能设置哪些属性等. 在样式属性中有一个“盒子模型需要重点介绍” 盒子模型 在⽂档的 Customizing Qt Widget…

Kubernetes从零到精通(10-服务Service)

Service简介 Deployment这种工作负载能管理我们应用Pod的副本数&#xff0c;并实现动态的创建和销毁&#xff0c;所以Pod本身是临时资源&#xff08;IP随时可能变化&#xff09;。现在如果某组Pod A需要访问另一组Pod B&#xff0c;A就需要在应用的配置参数里动态跟踪并更改B的…

java(1)数据类型,运算符,逻辑控制语句以及基本应用

目录 ​编辑 1.前言 2.正文 2.1数据类型与变量 2.1.1字面常量 2.1.2数据类型 2.1.3变量 2.1.3.1整型 2.1.3.2浮点型 2.1.3.3字符型 2.1.3.4布尔型 2.1.4类型转换与类型提升 2.1.4.1字符串的拼接 2.1.4.2整型转字符串 2.1.4.3字符串转整数 2.2运算符 2.2.1算术运…

【效果+教程】免费!实操用AI设计图标Logo,不仅省了设计费,还是副业新赛道!

Logo是一个品牌或公司的视觉标识 一个好的logo可以帮助消费者快速识别品牌&#xff0c;增强品牌的可见性和记忆度。 一个专业设计的logo能够提升品牌的可信度&#xff0c;给人一种专业和可靠的印象。 一个设计精美且富有意义的logo能够与消费者建立情感联系&#xff0c;增强…

10887辆 捷途旅行者8月再夺方盒子销冠

近日&#xff0c;8月汽车销量排行榜正式出炉。捷途旅行者年内第四次实现月销过万&#xff0c;以10887辆的优异成绩&#xff0c;持续领跑方盒子市场。作为名副其实的畅销车型&#xff0c;捷途旅行者自去年上市以来&#xff0c;不仅连续三个季度卫冕方盒子销量冠军&#xff0c;创…

C++类与对象(下)--最后的收尾

内部类 • 如果⼀个类定义在另⼀个类的内部&#xff0c;这个内部类就叫做内部类。内部类是⼀个独⽴的类&#xff0c;跟定义在 全局相⽐&#xff0c;他只是受外部类类域限制和访问限定符限制&#xff0c;所以外部类定义的对象中不包含内部类。 #include<iostream> using…

C++中string使用

目录 介绍 使用 迭代器&#xff08;Iterator&#xff09; begin&#xff0c;end rbegin&#xff0c;rend 容量&#xff08;Capacity&#xff09; size&#xff0c;length capacity empty clear resize reserve 元素访问&#xff08;Element access&#xff09; ope…

美国陆军发布下一代目标识别和感知倡议

文章目录 前言一、下一代目标识别与感知倡议的内容二、下一代目标识别与感知倡议重点关注领域(1)目标标记、跟踪和定位 (TTL)(2)侦察和监视 (R&S)(3)无人系统 (UMS)前言 2024年7月23日,美国陆军发布了下一代目标识别与感知倡议,希望工业界能够开发战场态势感知、侦…

LeetCode 692.前K个高频单词

LeetCode 692.前K个高频单词 C 思路&#x1f9d0;&#xff1a; 首先用map存储该字典&#xff0c;然后放进vector进行排序&#xff0c;注意sort的排序规则与我们想要的规则不一致&#xff0c;所以我们需要写一个伪函数来判断second(value值)&#xff0c;由于该题要求了稳定性&am…

Rider使用习惯

1.修改rider的快捷方式为VSCode样式的&#xff0c;修改设置方式 2.在项目中点击某个脚本文件&#xff0c;即在项目视图中选中这个文件&#xff0c;设置方式如下&#xff1a; 暂时先记录这么多&#xff0c;以后有零碎的随时记录

VUE,element-ui,优化tabs组件每次点击,所有子页面都重新渲染问题

1.在data中定义每个子组件相应的值&#xff0c;ture为加载&#xff0c;false为不加载。 2.在子组件中使用v-if来判断是否渲染当前页面 3.在函数中对子组件的值进行切换。 handleClick(){if(this.activeNamefirst){this.pageOne truethis.pageTwo false}else if(this.active…

通过 4EVERLAND 的终极 4EVER Boost 活动增强你的活动能力!

介绍 近日&#xff0c;4EVERLAND宣布启动最新、最激动人心的计划 — 4EVER Boost 活动&#xff01;4EVER Boost 活动旨在吸引更多社区成员加入并加速去中心化物理基础设施4EVER 网络的发展。用户可以参与节点质押、日常任务和 T4EVER/NFT 质押&#xff0c;以加快获得 $4EVER 积…

Spring Security认证与授权

1 Spring Security介绍 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。由于它是Spring生态系统中的一员&#xff0c;因此它伴随着整个Spring生态系统不断修正、升级&#xff0c;在spring boot项目中加入springsecurity更是…

隔离DCDC模块B0505/B0503对RS485和CAN总线进行电源隔离

CAN和485都是工业通信中常用的现场总线&#xff0c;做好通信总线的隔离防护是产品可靠、稳定的重要前 提。 一、通信总线为什么要隔离&#xff1f; 目前大多数产品对外通讯部分可总结为&#xff1a; MCU收发器外部总线&#xff0c;其中大多数常用的MCU都集成有CAN或UART链路层…

Linux中的简单命令2

一.echo指令 echo的作用是显式文本内容 #echo ‘字符串’ #echo “字符串” echo会将后面的内容当作字符串直接打印在屏幕上&#xff0c;后面的内容需要用单引号或者双引号括起来 注意&#xff1a;echo会自动在字符串后面加上一个换行符。 可以与printf进行对比&#xff1a; …

从Zotero6到Zotero7的数据迁移尝试?(有错勿喷,多多指教!)

从Zotero6到Zotero7的数据迁移尝试 0 前言 之前在主机上一直用的Zotero6&#xff08;实验室主机&#xff09;&#xff0c;最近发现在个人笔记本上看论文更频繁&#xff0c;尝试重新部署Zotero&#xff0c;才发现竟然更新了&#xff01;所以这里简单记录一下数据迁移过程&…

水厂中的反冲洗工艺

滤池作为水厂的重要的处理单元之一,滤池的形式多种多样,但其截留水中杂质的原理基本相同。我们以常见的V型滤池为例,介绍一下水厂中的反冲洗工艺。 V型滤池是快滤池的一种形式,因为其进水槽形状呈V字形而得名,也叫均粒滤料滤池(其滤料采用均质滤料,即均粒径滤料)、六阀滤…

代码随想录算法训练营第14天|226. 翻转二叉树、101. 对称二叉树、104. 二叉树的最大深度、111. 二叉树的最小深度

目录 226. 翻转二叉树1、题目描述2、思路3、code&#xff08;后序递归&#xff09; 101. 对称二叉树1、题目描述2、思路3、code 104. 二叉树的最大深度1、题目描述2、思路3、code 111. 二叉树的最小深度1、题目描述2、思路3、code 226. 翻转二叉树 题目链接&#xff1a;link …