diff --git a/Assets/Plugins/Android/AndroidManifest.xml b/Assets/Plugins/Android/AndroidManifest.xml
index 3e6a69ac..2b65ae5c 100644
--- a/Assets/Plugins/Android/AndroidManifest.xml
+++ b/Assets/Plugins/Android/AndroidManifest.xml
@@ -1,17 +1,19 @@
-
-
-
+
+
+
+
-
-
-
-
-
+
+
-
\ No newline at end of file
+
+
+
+
+
diff --git a/Assets/Plugins/Android/AndroidManifest.xml.meta b/Assets/Plugins/Android/AndroidManifest.xml.meta
index 83e598e6..99cac0a9 100644
--- a/Assets/Plugins/Android/AndroidManifest.xml.meta
+++ b/Assets/Plugins/Android/AndroidManifest.xml.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 506e447c8b55f0449ae2b5b5ed37dd99
+guid: 4abd69b18c4ab45ec976851430122248
TextScriptImporter:
externalObjects: {}
userData:
diff --git a/Assets/Plugins/Android/unityandroidbluetoothlelib.jar b/Assets/Plugins/Android/unityandroidbluetoothlelib.jar
new file mode 100644
index 00000000..588e1621
Binary files /dev/null and b/Assets/Plugins/Android/unityandroidbluetoothlelib.jar differ
diff --git a/Assets/Plugins/Android/unityandroidbluetoothlelib.jar.meta b/Assets/Plugins/Android/unityandroidbluetoothlelib.jar.meta
new file mode 100644
index 00000000..003a44eb
--- /dev/null
+++ b/Assets/Plugins/Android/unityandroidbluetoothlelib.jar.meta
@@ -0,0 +1,32 @@
+fileFormatVersion: 2
+guid: f158ceee465c745bc89002ae57bc033e
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Android: Android
+ second:
+ enabled: 1
+ settings: {}
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 0
+ settings:
+ DefaultValueInitialized: true
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/BluetoothDeviceScript.cs b/Assets/Plugins/BluetoothDeviceScript.cs
new file mode 100644
index 00000000..102148b9
--- /dev/null
+++ b/Assets/Plugins/BluetoothDeviceScript.cs
@@ -0,0 +1,391 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class BluetoothDeviceScript : MonoBehaviour
+{
+#if UNITY_IOS
+ public Dictionary BLEStandardUUIDs = new Dictionary();
+#endif
+
+ public List DiscoveredDeviceList;
+
+ public Action InitializedAction { get; set; }
+ public Action DeinitializedAction;
+ public Action ErrorAction;
+ public Action ServiceAddedAction;
+ public Action BleStatusChangedAction;
+ public Action StartedAdvertisingAction;
+ public Action StoppedAdvertisingAction;
+ public Action DiscoveredPeripheralAction;
+ public Action DiscoveredPeripheralWithAdvertisingInfoAction;
+ public Action DiscoveredBeaconAction;
+ public Action RetrievedConnectedPeripheralAction;
+ public Action PeripheralReceivedWriteDataAction;
+ public Action ConnectedPeripheralAction;
+ public Action ConnectedDisconnectPeripheralAction;
+ public Action DisconnectedPeripheralAction;
+ public Action DiscoveredServiceAction;
+ public Action DiscoveredCharacteristicAction;
+ public Action DidWriteCharacteristicAction;
+ public Dictionary>> DidUpdateNotificationStateForCharacteristicAction;
+ public Dictionary>> DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction;
+ public Dictionary>> DidUpdateCharacteristicValueAction;
+ public Dictionary>> DidUpdateCharacteristicValueWithDeviceAddressAction;
+ public Action RequestMtuAction;
+
+ // Use this for initialization
+ void Start ()
+ {
+ DiscoveredDeviceList = new List ();
+ DidUpdateNotificationStateForCharacteristicAction = new Dictionary>> ();
+ DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction = new Dictionary>> ();
+ DidUpdateCharacteristicValueAction = new Dictionary>> ();
+ DidUpdateCharacteristicValueWithDeviceAddressAction = new Dictionary>> ();
+
+#if UNITY_IOS
+ BLEStandardUUIDs["Heart Rate Measurement"] = "00002A37-0000-1000-8000-00805F9B34FB";
+#endif
+ }
+
+ // Update is called once per frame
+ void Update ()
+ {
+ }
+
+ const string deviceInitializedString = "Initialized";
+ const string deviceDeInitializedString = "DeInitialized";
+ const string deviceErrorString = "Error";
+ const string deviceServiceAdded = "ServiceAdded";
+ const string deviceStartedAdvertising = "StartedAdvertising";
+ const string deviceStoppedAdvertising = "StoppedAdvertising";
+ const string deviceDiscoveredPeripheral = "DiscoveredPeripheral";
+ const string deviceDiscoveredBeacon = "DiscoveredBeacon";
+ const string deviceRetrievedConnectedPeripheral = "RetrievedConnectedPeripheral";
+ const string devicePeripheralReceivedWriteData = "PeripheralReceivedWriteData";
+ const string deviceConnectedPeripheral = "ConnectedPeripheral";
+ const string deviceDisconnectedPeripheral = "DisconnectedPeripheral";
+ const string deviceDiscoveredService = "DiscoveredService";
+ const string deviceDiscoveredCharacteristic = "DiscoveredCharacteristic";
+ const string deviceDidWriteCharacteristic = "DidWriteCharacteristic";
+ const string deviceDidUpdateNotificationStateForCharacteristic = "DidUpdateNotificationStateForCharacteristic";
+ const string deviceDidUpdateValueForCharacteristic = "DidUpdateValueForCharacteristic";
+ const string deviceLog = "Log";
+ const string deviceRequestMtu = "MtuChanged";
+ const string bleStatusChanged = "BleStatusChanged";
+
+ public void OnBluetoothMessage (string message)
+ {
+ if (message != null)
+ {
+ char[] delim = new char[] { '~' };
+ string[] parts = message.Split (delim);
+ if (parts[0].Equals("DeviceStateChanged"))
+ {
+ //throw new Exception("test");
+ }
+ if (parts[0].Equals(bleStatusChanged))
+ {
+ if (BleStatusChangedAction != null)
+ {
+ BleStatusChangedAction(int.Parse(parts[1]));
+ }
+ }
+ for (int i = 0; i < parts.Length; ++i)
+ BluetoothLEHardwareInterface.Log(string.Format("Part: {0} - {1}", i, parts[i]));
+
+ if (message.Length >= deviceInitializedString.Length && message.Substring (0, deviceInitializedString.Length) == deviceInitializedString)
+ {
+ if (InitializedAction != null)
+ InitializedAction ();
+ }
+ else if (message.Length >= deviceLog.Length && message.Substring (0, deviceLog.Length) == deviceLog)
+ {
+ BluetoothLEHardwareInterface.Log (parts[1]);
+ }
+ else if (message.Length >= deviceDeInitializedString.Length && message.Substring (0, deviceDeInitializedString.Length) == deviceDeInitializedString)
+ {
+ BluetoothLEHardwareInterface.FinishDeInitialize ();
+
+ if (DeinitializedAction != null)
+ DeinitializedAction ();
+ }
+ else if (message.Length >= deviceErrorString.Length && message.Substring (0, deviceErrorString.Length) == deviceErrorString)
+ {
+ string error = "";
+
+ if (parts.Length >= 2)
+ error = parts[1];
+
+ if (ErrorAction != null)
+ ErrorAction (error);
+ }
+ else if (message.Length >= deviceServiceAdded.Length && message.Substring (0, deviceServiceAdded.Length) == deviceServiceAdded)
+ {
+ if (parts.Length >= 2)
+ {
+ if (ServiceAddedAction != null)
+ ServiceAddedAction (parts[1]);
+ }
+ }
+ else if (message.Length >= deviceStartedAdvertising.Length && message.Substring (0, deviceStartedAdvertising.Length) == deviceStartedAdvertising)
+ {
+ BluetoothLEHardwareInterface.Log ("Started Advertising");
+
+ if (StartedAdvertisingAction != null)
+ StartedAdvertisingAction ();
+ }
+ else if (message.Length >= deviceStoppedAdvertising.Length && message.Substring (0, deviceStoppedAdvertising.Length) == deviceStoppedAdvertising)
+ {
+ BluetoothLEHardwareInterface.Log ("Stopped Advertising");
+
+ if (StoppedAdvertisingAction != null)
+ StoppedAdvertisingAction ();
+ }
+ else if (message.Length >= deviceDiscoveredPeripheral.Length && message.Substring (0, deviceDiscoveredPeripheral.Length) == deviceDiscoveredPeripheral)
+ {
+ if (parts.Length >= 3)
+ {
+ // the first callback will only get called the first time this device is seen
+ // this is because it gets added to the a list in the DiscoveredDeviceList
+ // after that only the second callback will get called and only if there is
+ // advertising data available
+ if (!DiscoveredDeviceList.Contains (parts[1] + "|" + parts[2]))
+ {
+ DiscoveredDeviceList.Add (parts[1] + "|" + parts[2]);
+
+ if (DiscoveredPeripheralAction != null)
+ DiscoveredPeripheralAction (parts[1], parts[2]);
+ }
+
+ if (parts.Length >= 5 && DiscoveredPeripheralWithAdvertisingInfoAction != null)
+ {
+ // get the rssi from the 4th value
+ int rssi = 0;
+ if (!int.TryParse (parts[3], out rssi))
+ rssi = 0;
+ List uuidList = new List();
+ if (parts[4].Contains(","))
+ {
+ string[] s = parts[4].Split(',');
+ foreach (var o in s)
+ {
+ if (!string.IsNullOrEmpty(o))
+ {
+ uuidList.Add(o);
+ }
+ }
+ }
+ //// parse the base 64 encoded data that is the 5th value
+ //byte[] bytes = System.Convert.FromBase64String (parts[4]);
+
+ DiscoveredPeripheralWithAdvertisingInfoAction (parts[1], parts[2], rssi, uuidList.ToArray());
+ }
+ }
+ }
+ else if (message.Length >= deviceDiscoveredBeacon.Length && message.Substring (0, deviceDiscoveredBeacon.Length) == deviceDiscoveredBeacon)
+ {
+ if (parts.Length >= 7)
+ {
+ var iBeaconData = new BluetoothLEHardwareInterface.iBeaconData ();
+
+ iBeaconData.UUID = parts[1];
+ if (!int.TryParse (parts[2], out iBeaconData.Major))
+ iBeaconData.Major = 0;
+ if (!int.TryParse (parts[3], out iBeaconData.Minor))
+ iBeaconData.Minor = 0;
+ if (!int.TryParse (parts[4], out iBeaconData.RSSI))
+ iBeaconData.RSSI = 0;
+ if (!int.TryParse (parts[5], out iBeaconData.AndroidSignalPower))
+ iBeaconData.AndroidSignalPower = 0;
+ int iOSProximity = 0;
+ if (!int.TryParse (parts[6], out iOSProximity))
+ iOSProximity = 0;
+ iBeaconData.iOSProximity = (BluetoothLEHardwareInterface.iOSProximity)iOSProximity;
+
+ if (DiscoveredBeaconAction != null)
+ DiscoveredBeaconAction (iBeaconData);
+ }
+ }
+ else if (message.Length >= deviceRetrievedConnectedPeripheral.Length && message.Substring (0, deviceRetrievedConnectedPeripheral.Length) == deviceRetrievedConnectedPeripheral)
+ {
+ if (parts.Length >= 3)
+ {
+ DiscoveredDeviceList.Add (parts[1]);
+
+ if (RetrievedConnectedPeripheralAction != null)
+ RetrievedConnectedPeripheralAction (parts[1], parts[2]);
+ }
+ }
+ else if (message.Length >= devicePeripheralReceivedWriteData.Length && message.Substring (0, devicePeripheralReceivedWriteData.Length) == devicePeripheralReceivedWriteData)
+ {
+ if (parts.Length >= 3)
+ OnPeripheralData (parts[1], parts[2]);
+ }
+ else if (message.Length >= deviceConnectedPeripheral.Length && message.Substring (0, deviceConnectedPeripheral.Length) == deviceConnectedPeripheral)
+ {
+ if (parts.Length >= 2 && ConnectedPeripheralAction != null)
+ ConnectedPeripheralAction (parts[1]);
+ }
+ else if (message.Length >= deviceDisconnectedPeripheral.Length && message.Substring (0, deviceDisconnectedPeripheral.Length) == deviceDisconnectedPeripheral)
+ {
+ if (parts.Length >= 2)
+ {
+ if (ConnectedDisconnectPeripheralAction != null)
+ ConnectedDisconnectPeripheralAction (parts[1]);
+
+ if (DisconnectedPeripheralAction != null)
+ DisconnectedPeripheralAction (parts[1]);
+ }
+ }
+ else if (message.Length >= deviceDiscoveredService.Length && message.Substring (0, deviceDiscoveredService.Length) == deviceDiscoveredService)
+ {
+ if (parts.Length >= 3 && DiscoveredServiceAction != null)
+ DiscoveredServiceAction (parts[1], parts[2]);
+ }
+ else if (message.Length >= deviceDiscoveredCharacteristic.Length && message.Substring (0, deviceDiscoveredCharacteristic.Length) == deviceDiscoveredCharacteristic)
+ {
+ if (parts.Length >= 4 && DiscoveredCharacteristicAction != null)
+ DiscoveredCharacteristicAction (parts[1], parts[2], parts[3]);
+ }
+ else if (message.Length >= deviceDidWriteCharacteristic.Length && message.Substring (0, deviceDidWriteCharacteristic.Length) == deviceDidWriteCharacteristic)
+ {
+ if (parts.Length >= 2 && DidWriteCharacteristicAction != null)
+ DidWriteCharacteristicAction (parts[1]);
+ }
+ else if (message.Length >= deviceDidUpdateNotificationStateForCharacteristic.Length && message.Substring (0, deviceDidUpdateNotificationStateForCharacteristic.Length) == deviceDidUpdateNotificationStateForCharacteristic)
+ {
+ if (parts.Length >= 3)
+ {
+ if (DidUpdateNotificationStateForCharacteristicAction != null && DidUpdateNotificationStateForCharacteristicAction.ContainsKey (parts[1]))
+ {
+ var characteristicAction = DidUpdateNotificationStateForCharacteristicAction[parts[1]];
+ if (characteristicAction != null && characteristicAction.ContainsKey (parts[2]))
+ {
+ var action = characteristicAction[parts[2]];
+ if (action != null)
+ action (parts[2]);
+ }
+ }
+
+ if (DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction != null && DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction.ContainsKey (parts[1]))
+ {
+ var characteristicAction = DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction[parts[1]];
+ if (characteristicAction != null && characteristicAction.ContainsKey (parts[2]))
+ {
+ var action = characteristicAction[parts[2]];
+ if (action != null)
+ action (parts[1], parts[2]);
+ }
+ }
+ }
+ }
+ else if (message.Length >= deviceDidUpdateValueForCharacteristic.Length && message.Substring (0, deviceDidUpdateValueForCharacteristic.Length) == deviceDidUpdateValueForCharacteristic)
+ {
+ if (parts.Length >= 4)
+ OnBluetoothData (parts[1], parts[2], parts[3]);
+ }
+ else if (message.Length >= deviceRequestMtu.Length && message.Substring(0, deviceRequestMtu.Length) == deviceRequestMtu)
+ {
+ if (parts.Length >= 3)
+ {
+ if (RequestMtuAction != null)
+ {
+ int mtu = 0;
+ if (int.TryParse(parts[2], out mtu))
+ RequestMtuAction(parts[1], mtu);
+ }
+ }
+ }
+ }
+ }
+
+ public void OnBluetoothData (string base64Data)
+ {
+ OnBluetoothData ("", "", base64Data);
+ }
+
+ public void OnBluetoothData (string deviceAddress, string characteristic, string base64Data)
+ {
+ if (base64Data != null)
+ {
+ byte[] bytes = System.Convert.FromBase64String (base64Data);
+ if (bytes.Length > 0)
+ {
+ deviceAddress = deviceAddress.ToUpper ();
+ characteristic = characteristic.ToUpper ();
+
+#if UNITY_IOS
+ if (BLEStandardUUIDs.ContainsKey(characteristic))
+ characteristic = BLEStandardUUIDs[characteristic];
+#endif
+
+ BluetoothLEHardwareInterface.Log ("Device: " + deviceAddress + " Characteristic Received: " + characteristic);
+
+ string byteString = "";
+ foreach (byte b in bytes)
+ byteString += string.Format ("{0:X2}", b);
+
+ BluetoothLEHardwareInterface.Log (byteString);
+
+ if (DidUpdateCharacteristicValueAction != null && DidUpdateCharacteristicValueAction.ContainsKey (deviceAddress))
+ {
+ var characteristicAction = DidUpdateCharacteristicValueAction[deviceAddress];
+#if UNITY_ANDROID
+ characteristic = characteristic.ToLower ();
+#endif
+ if (characteristicAction != null && characteristicAction.ContainsKey (characteristic))
+ {
+ var action = characteristicAction[characteristic];
+ if (action != null)
+ action (characteristic, bytes);
+ }
+ }
+
+ if (DidUpdateCharacteristicValueWithDeviceAddressAction != null && DidUpdateCharacteristicValueWithDeviceAddressAction.ContainsKey (deviceAddress))
+ {
+ var characteristicAction = DidUpdateCharacteristicValueWithDeviceAddressAction[deviceAddress];
+#if UNITY_ANDROID
+ characteristic = characteristic.ToLower ();
+#endif
+ if (characteristicAction != null && characteristicAction.ContainsKey (characteristic))
+ {
+ var action = characteristicAction[characteristic];
+ if (action != null)
+ action (deviceAddress, characteristic, bytes);
+ }
+ }
+ }
+ }
+ }
+
+ public void OnPeripheralData (string characteristic, string base64Data)
+ {
+ if (base64Data != null)
+ {
+ byte[] bytes = System.Convert.FromBase64String (base64Data);
+ if (bytes.Length > 0)
+ {
+ BluetoothLEHardwareInterface.Log ("Peripheral Received: " + characteristic);
+
+ string byteString = "";
+ foreach (byte b in bytes)
+ byteString += string.Format ("{0:X2}", b);
+
+ BluetoothLEHardwareInterface.Log (byteString);
+
+ if (PeripheralReceivedWriteDataAction != null)
+ PeripheralReceivedWriteDataAction (characteristic, bytes);
+ }
+ }
+ }
+
+#if UNITY_IOS
+ private void IncludeCoreLocationFramework()
+ {
+ // this method is here because Unity now only includes CoreLocation
+ // if there are methods in the .cs code that access it
+ Input.location.Stop ();
+ }
+#endif
+}
diff --git a/Assets/Plugins/BluetoothDeviceScript.cs.meta b/Assets/Plugins/BluetoothDeviceScript.cs.meta
new file mode 100644
index 00000000..e31cb904
--- /dev/null
+++ b/Assets/Plugins/BluetoothDeviceScript.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b188ba3ac565e48f58fc50dd5db4818d
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Assets/Plugins/BluetoothHardwareInterface.cs b/Assets/Plugins/BluetoothHardwareInterface.cs
new file mode 100644
index 00000000..4c80d913
--- /dev/null
+++ b/Assets/Plugins/BluetoothHardwareInterface.cs
@@ -0,0 +1,999 @@
+#define EXPERIMENTAL_MACOS_EDITOR
+/*
+
+This build includes an experimental implementation for the macOS editor of Unity
+It is experiemental because of the way that the Unity editor hangs on to plugin
+instances after leaving play mode. This causes this plugin to not free up its
+resources and therefore can cause crashes in the Unity editor on macOS.
+
+Since Unity does not give plugins or apps a chance to do anything when the user
+hits the play / stop button in the Editor there isn't a chance for the app to
+deinitialize this plugin.
+
+What I have found in my own use of this is that if you put a button on your app
+somewhere that you can press before hitting the stop button in the editor and
+then in that button handler call this plugin's Deinitialize method it seems to
+minimize how often the editor crashes.
+
+WARNING: using the macOS editor can cause the editor to crash an loose your work
+and settings. Save often. You have been warned, so please don't contact me if
+you have lost work becausee of this problem. This is experimental only. Use at
+your own risk.
+
+*/
+
+using UnityEngine;
+using System;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+
+#if UNITY_2018_3_OR_NEWER
+#if UNITY_ANDROID
+using UnityEngine.Android;
+#endif
+#endif
+
+public class BluetoothLEHardwareInterface
+{
+ public enum CBCharacteristicProperties
+ {
+ CBCharacteristicPropertyBroadcast = 0x01,
+ CBCharacteristicPropertyRead = 0x02,
+ CBCharacteristicPropertyWriteWithoutResponse = 0x04,
+ CBCharacteristicPropertyWrite = 0x08,
+ CBCharacteristicPropertyNotify = 0x10,
+ CBCharacteristicPropertyIndicate = 0x20,
+ CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40,
+ CBCharacteristicPropertyExtendedProperties = 0x80,
+ CBCharacteristicPropertyNotifyEncryptionRequired = 0x100,
+ CBCharacteristicPropertyIndicateEncryptionRequired = 0x200,
+ };
+
+ public enum ScanMode
+ {
+ LowPower = 0,
+ Balanced = 1,
+ LowLatency = 2
+ }
+
+ public enum ConnectionPriority
+ {
+ LowPower = 0,
+ Balanced = 1,
+ High = 2,
+ }
+
+ public enum iOSProximity
+ {
+ Unknown = 0,
+ Immediate = 1,
+ Near = 2,
+ Far = 3,
+ }
+
+ public struct iBeaconData
+ {
+ public string UUID;
+ public int Major;
+ public int Minor;
+ public int RSSI;
+ public int AndroidSignalPower;
+ public iOSProximity iOSProximity;
+ }
+
+#if UNITY_ANDROID
+ public enum CBAttributePermissions
+ {
+ CBAttributePermissionsReadable = 0x01,
+ CBAttributePermissionsWriteable = 0x10,
+ CBAttributePermissionsReadEncryptionRequired = 0x02,
+ CBAttributePermissionsWriteEncryptionRequired = 0x20,
+ };
+#else
+ public enum CBAttributePermissions
+ {
+ CBAttributePermissionsReadable = 0x01,
+ CBAttributePermissionsWriteable = 0x02,
+ CBAttributePermissionsReadEncryptionRequired = 0x04,
+ CBAttributePermissionsWriteEncryptionRequired = 0x08,
+ };
+#endif
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+
+ public delegate void UnitySendMessageCallbackDelegate (IntPtr objectName, IntPtr commandName, IntPtr commandData);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void ConnectUnitySendMessageCallback ([MarshalAs (UnmanagedType.FunctionPtr)]UnitySendMessageCallbackDelegate callbackMethod);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLELog (string message);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLEInitialize ([MarshalAs (UnmanagedType.Bool)]bool asCentral, [MarshalAs (UnmanagedType.Bool)]bool asPeripheral);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLEDeInitialize ();
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLEPauseMessages (bool isPaused);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLEScanForPeripheralsWithServices (string serviceUUIDsString, bool allowDuplicates, bool rssiOnly, bool clearPeripheralList);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLERetrieveListOfPeripheralsWithServices (string serviceUUIDsString);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLEStopScan ();
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLEConnectToPeripheral (string name);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLEDisconnectAll ();
+
+ [DllImport("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLERequestMtu (string name, int mtu);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLEDisconnectPeripheral (string name);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLEReadCharacteristic (string name, string service, string characteristic);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLEWriteCharacteristic (string name, string service, string characteristic, byte[] data, int length, bool withResponse);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLESubscribeCharacteristic (string name, string service, string characteristic);
+
+ [DllImport ("BluetoothLEOSX")]
+ private static extern void OSXBluetoothLEUnSubscribeCharacteristic (string name, string service, string characteristic);
+
+#endif
+
+#if UNITY_IOS || UNITY_TVOS
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLELog (string message);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEInitialize (bool asCentral, bool asPeripheral);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEDeInitialize ();
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEPauseMessages (bool isPaused);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEScanForPeripheralsWithServices (string serviceUUIDsString, bool allowDuplicates, bool rssiOnly, bool clearPeripheralList);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLERetrieveListOfPeripheralsWithServices (string serviceUUIDsString);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEStopScan ();
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEConnectToPeripheral (string name);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEDisconnectPeripheral (string name);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEReadCharacteristic (string name, string service, string characteristic);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEWriteCharacteristic (string name, string service, string characteristic, byte[] data, int length, bool withResponse);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLESubscribeCharacteristic (string name, string service, string characteristic);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEUnSubscribeCharacteristic (string name, string service, string characteristic);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEDisconnectAll ();
+
+#if !UNITY_TVOS
+ [DllImport("__Internal")]
+ private static extern void _iOSBluetoothLERequestMtu(string name, int mtu);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEScanForBeacons (string proximityUUIDsString);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEStopBeaconScan ();
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEPeripheralName (string newName);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLECreateService (string uuid, bool primary);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLERemoveService (string uuid);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLERemoveServices ();
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLECreateCharacteristic (string uuid, int properties, int permissions, byte[] data, int length);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLERemoveCharacteristic (string uuid);
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLERemoveCharacteristics ();
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEStartAdvertising ();
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEStopAdvertising ();
+
+ [DllImport ("__Internal")]
+ private static extern void _iOSBluetoothLEUpdateCharacteristicValue (string uuid, byte[] data, int length);
+#endif
+#elif UNITY_ANDROID
+ static AndroidJavaObject _android = null;
+#endif
+
+
+ private static BluetoothDeviceScript bluetoothDeviceScript;
+
+ public static void Log (string message)
+ {
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ Debug.Log(message);
+#else
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLELog (message);
+#elif UNITY_ANDROID
+ if (_android == null)
+ {
+ AndroidJavaClass javaClass = new AndroidJavaClass ("com.shatalmic.unityandroidbluetoothlelib.UnityBluetoothLE");
+ _android = javaClass.CallStatic ("getInstance");
+ }
+
+ if (_android != null)
+ _android.Call ("androidBluetoothLog", message);
+#endif
+ }
+#endif
+ }
+
+ public static BluetoothDeviceScript Initialize (bool asCentral, bool asPeripheral, Action action, Action errorAction, Action statusAction)
+ {
+ bluetoothDeviceScript = null;
+
+#if UNITY_2018_3_OR_NEWER
+#if UNITY_ANDROID
+ if (!Permission.HasUserAuthorizedPermission (Permission.FineLocation))
+ Permission.RequestUserPermission (Permission.FineLocation);
+#endif
+#endif
+
+ GameObject bluetoothLEReceiver = GameObject.Find("BluetoothLEReceiver");
+ if (bluetoothLEReceiver == null)
+ bluetoothLEReceiver = new GameObject ("BluetoothLEReceiver");
+
+ if (bluetoothLEReceiver != null)
+ {
+ bluetoothDeviceScript = bluetoothLEReceiver.GetComponent ();
+ if (bluetoothDeviceScript == null)
+ bluetoothDeviceScript = bluetoothLEReceiver.AddComponent ();
+
+ if (bluetoothDeviceScript != null)
+ {
+ bluetoothDeviceScript.BleStatusChangedAction = statusAction;
+ bluetoothDeviceScript.InitializedAction = action;
+ bluetoothDeviceScript.ErrorAction = errorAction;
+ }
+ }
+
+ GameObject.DontDestroyOnLoad (bluetoothLEReceiver);
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ ConnectUnitySendMessageCallback ((objectName, commandName, commandData) => {
+ string name = Marshal.PtrToStringAuto (objectName);
+ string command = Marshal.PtrToStringAuto (commandName);
+ string data = Marshal.PtrToStringAuto (commandData);
+
+ GameObject foundObject = GameObject.Find (name);
+ if (foundObject != null)
+ foundObject.SendMessage (command, data);
+ });
+
+ BluetoothLEHardwareInterface.OSXBluetoothLEInitialize (asCentral, asPeripheral);
+#else
+ if (Application.isEditor)
+ {
+ if (bluetoothDeviceScript != null)
+ bluetoothDeviceScript.SendMessage ("OnBluetoothMessage", "Initialized");
+ }
+ else
+ {
+#if UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLEInitialize (asCentral, asPeripheral);
+#elif UNITY_ANDROID
+ if (_android == null)
+ {
+ AndroidJavaClass javaClass = new AndroidJavaClass ("com.shatalmic.unityandroidbluetoothlelib.UnityBluetoothLE");
+ _android = javaClass.CallStatic ("getInstance");
+ }
+
+ if (_android != null)
+ _android.Call ("androidBluetoothInitialize", asCentral, asPeripheral);
+#endif
+ }
+#endif
+
+ return bluetoothDeviceScript;
+ }
+
+ public static void DeInitialize (Action action)
+ {
+ if (bluetoothDeviceScript != null)
+ bluetoothDeviceScript.DeinitializedAction = action;
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ BluetoothLEHardwareInterface.OSXBluetoothLEDeInitialize ();
+#else
+ if (Application.isEditor)
+ {
+ if (bluetoothDeviceScript != null)
+ bluetoothDeviceScript.SendMessage ("OnBluetoothMessage", "DeInitialized");
+ }
+ else
+ {
+#if UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLEDeInitialize ();
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothDeInitialize");
+#endif
+ }
+#endif
+ }
+
+ public static void FinishDeInitialize ()
+ {
+ GameObject bluetoothLEReceiver = GameObject.Find("BluetoothLEReceiver");
+ if (bluetoothLEReceiver != null)
+ GameObject.Destroy(bluetoothLEReceiver);
+ }
+
+ public static void BluetoothEnable (bool enable)
+ {
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS || UNITY_TVOS
+ //_iOSBluetoothLELog (message);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothEnable", enable);
+#endif
+ }
+ }
+
+ public static void BluetoothScanMode (ScanMode scanMode)
+ {
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS || UNITY_TVOS
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothScanMode", (int)scanMode);
+#endif
+ }
+ }
+
+ public static void BluetoothConnectionPriority (ConnectionPriority connectionPriority)
+ {
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS || UNITY_TVOS
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothConnectionPriority", (int)connectionPriority);
+#endif
+ }
+ }
+
+ public static void PauseMessages (bool isPaused)
+ {
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLEPauseMessages (isPaused);
+#else
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLEPauseMessages (isPaused);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothPause", isPaused);
+#endif
+ }
+#endif
+ }
+
+ // scanning for beacons requires that you know the Proximity UUID
+ public static void ScanForBeacons (string[] proximityUUIDs, Action actionBeaconResponse)
+ {
+ if (proximityUUIDs != null && proximityUUIDs.Length >= 0)
+ {
+ if (!Application.isEditor)
+ {
+ if (bluetoothDeviceScript != null)
+ bluetoothDeviceScript.DiscoveredBeaconAction = actionBeaconResponse;
+
+ string proximityUUIDsString = null;
+
+ if (proximityUUIDs != null && proximityUUIDs.Length > 0)
+ {
+ proximityUUIDsString = "";
+
+ foreach (string proximityUUID in proximityUUIDs)
+ proximityUUIDsString += proximityUUID + "|";
+
+ proximityUUIDsString = proximityUUIDsString.Substring (0, proximityUUIDsString.Length - 1);
+ }
+
+#if UNITY_IOS
+ _iOSBluetoothLEScanForBeacons (proximityUUIDsString);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothScanForBeacons", proximityUUIDsString);
+#endif
+ }
+ }
+ }
+
+ public static void RequestMtu(string name, int mtu, Action action)
+ {
+ if (bluetoothDeviceScript != null)
+ {
+ bluetoothDeviceScript.RequestMtuAction = action;
+ }
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ if (mtu > 184)
+ mtu = 184;
+ OSXBluetoothLERequestMtu(name, mtu);
+#elif UNITY_IOS || UNITY_TVOS
+ if (mtu > 180)
+ mtu = 180;
+ _iOSBluetoothLERequestMtu (name, mtu);
+#elif UNITY_ANDROID
+ if (_android != null)
+ {
+ _android.Call ("androidBluetoothRequestMtu", name, mtu);
+ }
+#endif
+ }
+
+ public static void ScanForPeripheralsWithServices (string[] serviceUUIDs, Action action = null, Action actionAdvertisingInfo = null, bool rssiOnly = false, bool clearPeripheralList = true, int recordType = 0xFF)
+ {
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ if (!Application.isEditor)
+ {
+#endif
+ if (bluetoothDeviceScript != null)
+ {
+ bluetoothDeviceScript.DiscoveredPeripheralAction = action;
+ bluetoothDeviceScript.DiscoveredPeripheralWithAdvertisingInfoAction = actionAdvertisingInfo;
+
+ if (bluetoothDeviceScript.DiscoveredDeviceList != null)
+ bluetoothDeviceScript.DiscoveredDeviceList.Clear ();
+ }
+
+ string serviceUUIDsString = null;
+
+ if (serviceUUIDs != null && serviceUUIDs.Length > 0)
+ {
+ serviceUUIDsString = "";
+
+ foreach (string serviceUUID in serviceUUIDs)
+ serviceUUIDsString += serviceUUID + "|";
+
+ serviceUUIDsString = serviceUUIDsString.Substring (0, serviceUUIDsString.Length - 1);
+ }
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLEScanForPeripheralsWithServices (serviceUUIDsString, (actionAdvertisingInfo != null), rssiOnly, clearPeripheralList);
+#elif UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLEScanForPeripheralsWithServices (serviceUUIDsString, (actionAdvertisingInfo != null), rssiOnly, clearPeripheralList);
+#elif UNITY_ANDROID
+ if (_android != null)
+ {
+ if (serviceUUIDsString == null)
+ serviceUUIDsString = "";
+
+ _android.Call ("androidBluetoothScanForPeripheralsWithServices", serviceUUIDsString, rssiOnly, recordType);
+ }
+#endif
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ }
+#endif
+ }
+
+ public static void RetrieveListOfPeripheralsWithServices (string[] serviceUUIDs, Action action)
+ {
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ if (!Application.isEditor)
+ {
+#endif
+ if (bluetoothDeviceScript != null)
+ {
+ bluetoothDeviceScript.RetrievedConnectedPeripheralAction = action;
+
+ if (bluetoothDeviceScript.DiscoveredDeviceList != null)
+ bluetoothDeviceScript.DiscoveredDeviceList.Clear ();
+ }
+
+ string serviceUUIDsString = serviceUUIDs.Length > 0 ? "" : null;
+
+ foreach (string serviceUUID in serviceUUIDs)
+ serviceUUIDsString += serviceUUID + "|";
+
+ // strip the last delimeter
+ serviceUUIDsString = serviceUUIDsString.Substring (0, serviceUUIDsString.Length - 1);
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLERetrieveListOfPeripheralsWithServices (serviceUUIDsString);
+#elif UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLERetrieveListOfPeripheralsWithServices (serviceUUIDsString);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothRetrieveListOfPeripheralsWithServices", serviceUUIDsString);
+#endif
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ }
+#endif
+ }
+
+ public static void StopScan ()
+ {
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLEStopScan ();
+#else
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLEStopScan ();
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothStopScan");
+#endif
+ }
+#endif
+ }
+
+ public static void StopBeaconScan ()
+ {
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS
+ _iOSBluetoothLEStopBeaconScan ();
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothStopBeaconScan");
+#endif
+ }
+ }
+
+ public static void DisconnectAll ()
+ {
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLEDisconnectAll ();
+#else
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLEDisconnectAll ();
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothDisconnectAll");
+#endif
+ }
+#endif
+ }
+
+ public static void ConnectToPeripheral (string name, Action connectAction, Action serviceAction, Action characteristicAction, Action disconnectAction = null)
+ {
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ if (!Application.isEditor)
+ {
+#endif
+ if (bluetoothDeviceScript != null)
+ {
+ bluetoothDeviceScript.ConnectedPeripheralAction = connectAction;
+ bluetoothDeviceScript.DiscoveredServiceAction = serviceAction;
+ bluetoothDeviceScript.DiscoveredCharacteristicAction = characteristicAction;
+ bluetoothDeviceScript.ConnectedDisconnectPeripheralAction = disconnectAction;
+ }
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLEConnectToPeripheral (name);
+#elif UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLEConnectToPeripheral (name);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothConnectToPeripheral", name);
+#endif
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ }
+#endif
+ }
+
+ public static void DisconnectPeripheral (string name, Action action)
+ {
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ if (!Application.isEditor)
+ {
+#endif
+ if (bluetoothDeviceScript != null)
+ bluetoothDeviceScript.DisconnectedPeripheralAction = action;
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLEDisconnectPeripheral (name);
+#elif UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLEDisconnectPeripheral (name);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidBluetoothDisconnectPeripheral", name);
+#endif
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ }
+#endif
+ }
+
+ public static void ReadCharacteristic (string name, string service, string characteristic, Action action)
+ {
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ if (!Application.isEditor)
+ {
+#endif
+ if (bluetoothDeviceScript != null)
+ {
+ if (!bluetoothDeviceScript.DidUpdateCharacteristicValueAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateCharacteristicValueAction[name] = new Dictionary>();
+
+#if UNITY_IOS || UNITY_TVOS || (EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX))
+ bluetoothDeviceScript.DidUpdateCharacteristicValueAction [name] [characteristic] = action;
+#elif UNITY_ANDROID
+ bluetoothDeviceScript.DidUpdateCharacteristicValueAction [name] [FullUUID (characteristic).ToLower ()] = action;
+#endif
+ }
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLEReadCharacteristic (name, service, characteristic);
+#elif UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLEReadCharacteristic (name, service, characteristic);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidReadCharacteristic", name, service, characteristic);
+#endif
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ }
+#endif
+ }
+
+ public static void WriteCharacteristic (string name, string service, string characteristic, byte[] data, int length, bool withResponse, Action action)
+ {
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ if (!Application.isEditor)
+ {
+#endif
+ if (bluetoothDeviceScript != null)
+ bluetoothDeviceScript.DidWriteCharacteristicAction = action;
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLEWriteCharacteristic(name, service, characteristic, data, length, withResponse);
+#elif UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLEWriteCharacteristic (name, service, characteristic, data, length, withResponse);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidWriteCharacteristic", name, service, characteristic, data, length, withResponse);
+#endif
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ }
+#endif
+ }
+
+ public static void SubscribeCharacteristic (string name, string service, string characteristic, Action notificationAction, Action action)
+ {
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ if (!Application.isEditor)
+ {
+#endif
+ if (bluetoothDeviceScript != null)
+ {
+ name = name.ToUpper ();
+ service = service.ToUpper ();
+ characteristic = characteristic.ToUpper ();
+
+#if UNITY_IOS || UNITY_TVOS || (EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX))
+ if (!bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction [name] = new Dictionary> ();
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction [name] [characteristic] = notificationAction;
+
+ if (!bluetoothDeviceScript.DidUpdateCharacteristicValueAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateCharacteristicValueAction [name] = new Dictionary> ();
+ bluetoothDeviceScript.DidUpdateCharacteristicValueAction [name] [characteristic] = action;
+#elif UNITY_ANDROID
+ if (!bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction [name] = new Dictionary> ();
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction [name] [FullUUID (characteristic).ToLower ()] = notificationAction;
+
+ if (!bluetoothDeviceScript.DidUpdateCharacteristicValueAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateCharacteristicValueAction [name] = new Dictionary> ();
+ bluetoothDeviceScript.DidUpdateCharacteristicValueAction [name] [FullUUID (characteristic).ToLower ()] = action;
+#endif
+ }
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLESubscribeCharacteristic (name, service, characteristic);
+#elif UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLESubscribeCharacteristic (name, service, characteristic);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidSubscribeCharacteristic", name, service, characteristic);
+#endif
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ }
+#endif
+ }
+
+ public static void SubscribeCharacteristicWithDeviceAddress (string name, string service, string characteristic, Action notificationAction, Action action)
+ {
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ if (!Application.isEditor)
+ {
+#endif
+ if (bluetoothDeviceScript != null)
+ {
+ name = name.ToUpper ();
+ service = service.ToUpper ();
+ characteristic = characteristic.ToUpper ();
+
+#if UNITY_IOS || UNITY_TVOS || (EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX))
+ if (!bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction[name] = new Dictionary>();
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction[name][characteristic] = notificationAction;
+
+ if (!bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction[name] = new Dictionary>();
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction[name][characteristic] = null;
+
+ if (!bluetoothDeviceScript.DidUpdateCharacteristicValueWithDeviceAddressAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateCharacteristicValueWithDeviceAddressAction[name] = new Dictionary>();
+ bluetoothDeviceScript.DidUpdateCharacteristicValueWithDeviceAddressAction[name][characteristic] = action;
+#elif UNITY_ANDROID
+ if (!bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction[name] = new Dictionary>();
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction[name][FullUUID (characteristic).ToLower ()] = notificationAction;
+
+ if (!bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction.ContainsKey(name))
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction[name] = new Dictionary>();
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction[name][FullUUID (characteristic).ToLower ()] = null;
+
+ if (!bluetoothDeviceScript.DidUpdateCharacteristicValueWithDeviceAddressAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateCharacteristicValueWithDeviceAddressAction[name] = new Dictionary>();
+ bluetoothDeviceScript.DidUpdateCharacteristicValueWithDeviceAddressAction[name][FullUUID (characteristic).ToLower ()] = action;
+#endif
+ }
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLESubscribeCharacteristic (name, service, characteristic);
+#elif UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLESubscribeCharacteristic (name, service, characteristic);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidSubscribeCharacteristic", name, service, characteristic);
+#endif
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ }
+#endif
+ }
+
+ public static void UnSubscribeCharacteristic (string name, string service, string characteristic, Action action)
+ {
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ if (!Application.isEditor)
+ {
+#endif
+ if (bluetoothDeviceScript != null)
+ {
+ name = name.ToUpper ();
+ service = service.ToUpper ();
+ characteristic = characteristic.ToUpper ();
+
+#if UNITY_IOS || UNITY_TVOS || (EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX))
+ if (!bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction[name] = new Dictionary>();
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction[name][characteristic] = null;
+
+ if (!bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction[name] = new Dictionary> ();
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction[name][characteristic] = action;
+#elif UNITY_ANDROID
+ if (!bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction[name] = new Dictionary>();
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicWithDeviceAddressAction[name][FullUUID (characteristic).ToLower ()] = null;
+
+ if (!bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction.ContainsKey (name))
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction[name] = new Dictionary> ();
+ bluetoothDeviceScript.DidUpdateNotificationStateForCharacteristicAction[name][FullUUID (characteristic).ToLower ()] = action;
+#endif
+ }
+
+#if EXPERIMENTAL_MACOS_EDITOR && (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
+ OSXBluetoothLEUnSubscribeCharacteristic (name, service, characteristic);
+#elif UNITY_IOS || UNITY_TVOS
+ _iOSBluetoothLEUnSubscribeCharacteristic (name, service, characteristic);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidUnsubscribeCharacteristic", name, service, characteristic);
+#endif
+#if !UNITY_EDITOR_OSX || !EXPERIMENTAL_MACOS_EDITOR
+ }
+#endif
+ }
+
+ public static void PeripheralName (string newName)
+ {
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS
+ _iOSBluetoothLEPeripheralName (newName);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidPeripheralName", newName);
+#endif
+ }
+ }
+
+ public static void CreateService (string uuid, bool primary, Action action)
+ {
+ if (!Application.isEditor)
+ {
+ if (bluetoothDeviceScript != null)
+ bluetoothDeviceScript.ServiceAddedAction = action;
+
+#if UNITY_IOS
+ _iOSBluetoothLECreateService (uuid, primary);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidCreateService", uuid, primary);
+#endif
+ }
+ }
+
+ public static void RemoveService (string uuid)
+ {
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS
+ _iOSBluetoothLERemoveService (uuid);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidRemoveService", uuid);
+#endif
+ }
+ }
+
+ public static void RemoveServices ()
+ {
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS
+ _iOSBluetoothLERemoveServices ();
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidRemoveServices");
+#endif
+ }
+ }
+
+ public static void CreateCharacteristic (string uuid, CBCharacteristicProperties properties, CBAttributePermissions permissions, byte[] data, int length, Action action)
+ {
+ if (!Application.isEditor)
+ {
+ if (bluetoothDeviceScript != null)
+ bluetoothDeviceScript.PeripheralReceivedWriteDataAction = action;
+
+#if UNITY_IOS
+ _iOSBluetoothLECreateCharacteristic (uuid, (int)properties, (int)permissions, data, length);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidCreateCharacteristic", uuid, (int)properties, (int)permissions, data, length);
+#endif
+ }
+ }
+
+ public static void RemoveCharacteristic (string uuid)
+ {
+ if (!Application.isEditor)
+ {
+ if (bluetoothDeviceScript != null)
+ bluetoothDeviceScript.PeripheralReceivedWriteDataAction = null;
+
+#if UNITY_IOS
+ _iOSBluetoothLERemoveCharacteristic (uuid);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidRemoveCharacteristic", uuid);
+#endif
+ }
+ }
+
+ public static void RemoveCharacteristics ()
+ {
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS
+ _iOSBluetoothLERemoveCharacteristics ();
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidRemoveCharacteristics");
+#endif
+ }
+ }
+
+ public static void StartAdvertising (Action action)
+ {
+ if (!Application.isEditor)
+ {
+ if (bluetoothDeviceScript != null)
+ bluetoothDeviceScript.StartedAdvertisingAction = action;
+
+#if UNITY_IOS
+ _iOSBluetoothLEStartAdvertising ();
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidStartAdvertising");
+#endif
+ }
+ }
+
+ public static void StopAdvertising (Action action)
+ {
+ if (!Application.isEditor)
+ {
+ if (bluetoothDeviceScript != null)
+ bluetoothDeviceScript.StoppedAdvertisingAction = action;
+
+#if UNITY_IOS
+ _iOSBluetoothLEStopAdvertising ();
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidStopAdvertising");
+#endif
+ }
+ }
+
+ public static void UpdateCharacteristicValue (string uuid, byte[] data, int length)
+ {
+ if (!Application.isEditor)
+ {
+#if UNITY_IOS
+ _iOSBluetoothLEUpdateCharacteristicValue (uuid, data, length);
+#elif UNITY_ANDROID
+ if (_android != null)
+ _android.Call ("androidUpdateCharacteristicValue", uuid, data, length);
+#endif
+ }
+ }
+
+ public static string FullUUID (string uuid)
+ {
+ if (uuid.Length == 4)
+ return "0000" + uuid + "-0000-1000-8000-00805F9B34FB";
+ return uuid;
+ }
+}
diff --git a/Assets/Plugins/BluetoothHardwareInterface.cs.meta b/Assets/Plugins/BluetoothHardwareInterface.cs.meta
new file mode 100644
index 00000000..f3b5a0a6
--- /dev/null
+++ b/Assets/Plugins/BluetoothHardwareInterface.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b8496a9b1a1df40af9ada2311d1d6d09
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/Assets/Plugins/BluetoothLEOSX.bundle.meta b/Assets/Plugins/BluetoothLEOSX.bundle.meta
new file mode 100644
index 00000000..f7075f6e
--- /dev/null
+++ b/Assets/Plugins/BluetoothLEOSX.bundle.meta
@@ -0,0 +1,43 @@
+fileFormatVersion: 2
+guid: 5383f7d08256547f6b36ee834b840062
+folderAsset: yes
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 1
+ settings:
+ DefaultValueInitialized: true
+ - first:
+ Standalone: OSXIntel
+ second:
+ enabled: 1
+ settings: {}
+ - first:
+ Standalone: OSXIntel64
+ second:
+ enabled: 1
+ settings: {}
+ - first:
+ Standalone: OSXUniversal
+ second:
+ enabled: 1
+ settings: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/BluetoothLEOSX.bundle/Contents.meta b/Assets/Plugins/BluetoothLEOSX.bundle/Contents.meta
new file mode 100644
index 00000000..93308905
--- /dev/null
+++ b/Assets/Plugins/BluetoothLEOSX.bundle/Contents.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 34c7c97d38c834839be439bcf96a0267
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/BluetoothLEOSX.bundle/Contents/Info.plist b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/Info.plist
new file mode 100644
index 00000000..f1fbd9b3
--- /dev/null
+++ b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/Info.plist
@@ -0,0 +1,48 @@
+
+
+
+
+ BuildMachineOSBuild
+ 19F101
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ BluetoothLEOSX
+ CFBundleIdentifier
+ com.shatalmic.BluetoothLEOSX
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ BluetoothLEOSX
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleSupportedPlatforms
+
+ MacOSX
+
+ CFBundleVersion
+ 1
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 11E608c
+ DTPlatformVersion
+ GM
+ DTSDKBuild
+ 19E258
+ DTSDKName
+ macosx10.15
+ DTXcode
+ 1150
+ DTXcodeBuild
+ 11E608c
+ LSMinimumSystemVersion
+ 10.11
+ NSHumanReadableCopyright
+ Copyright © 2016 Shatalmic. All rights reserved.
+
+
diff --git a/Assets/Plugins/BluetoothLEOSX.bundle/Contents/Info.plist.meta b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/Info.plist.meta
new file mode 100644
index 00000000..50ad560e
--- /dev/null
+++ b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/Info.plist.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 8e7811284d1734fc2ba4b29fccd3ccf7
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/BluetoothLEOSX.bundle/Contents/MacOS.meta b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/MacOS.meta
new file mode 100644
index 00000000..bea35c1b
--- /dev/null
+++ b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/MacOS.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4e9d68945c9234df3b7855f4e1006f0f
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/BluetoothLEOSX.bundle/Contents/MacOS/BluetoothLEOSX b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/MacOS/BluetoothLEOSX
new file mode 100644
index 00000000..e15d6a5b
Binary files /dev/null and b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/MacOS/BluetoothLEOSX differ
diff --git a/Assets/Plugins/BluetoothLEOSX.bundle/Contents/MacOS/BluetoothLEOSX.meta b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/MacOS/BluetoothLEOSX.meta
new file mode 100644
index 00000000..34e31722
--- /dev/null
+++ b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/MacOS/BluetoothLEOSX.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 1a83baeb98e0141f587d978b89ecd37d
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/BluetoothLEOSX.bundle/Contents/_CodeSignature.meta b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/_CodeSignature.meta
new file mode 100644
index 00000000..719d57c0
--- /dev/null
+++ b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/_CodeSignature.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 673293518de2c4fbf913749ebdb36dd1
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/BluetoothLEOSX.bundle/Contents/_CodeSignature/CodeResources b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/_CodeSignature/CodeResources
new file mode 100644
index 00000000..d5d0fd74
--- /dev/null
+++ b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/_CodeSignature/CodeResources
@@ -0,0 +1,115 @@
+
+
+
+
+ files
+
+ files2
+
+ rules
+
+ ^Resources/
+
+ ^Resources/.*\.lproj/
+
+ optional
+
+ weight
+ 1000
+
+ ^Resources/.*\.lproj/locversion.plist$
+
+ omit
+
+ weight
+ 1100
+
+ ^Resources/Base\.lproj/
+
+ weight
+ 1010
+
+ ^version.plist$
+
+
+ rules2
+
+ .*\.dSYM($|/)
+
+ weight
+ 11
+
+ ^(.*/)?\.DS_Store$
+
+ omit
+
+ weight
+ 2000
+
+ ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/
+
+ nested
+
+ weight
+ 10
+
+ ^.*
+
+ ^Info\.plist$
+
+ omit
+
+ weight
+ 20
+
+ ^PkgInfo$
+
+ omit
+
+ weight
+ 20
+
+ ^Resources/
+
+ weight
+ 20
+
+ ^Resources/.*\.lproj/
+
+ optional
+
+ weight
+ 1000
+
+ ^Resources/.*\.lproj/locversion.plist$
+
+ omit
+
+ weight
+ 1100
+
+ ^Resources/Base\.lproj/
+
+ weight
+ 1010
+
+ ^[^/]+$
+
+ nested
+
+ weight
+ 10
+
+ ^embedded\.provisionprofile$
+
+ weight
+ 20
+
+ ^version\.plist$
+
+ weight
+ 20
+
+
+
+
diff --git a/Assets/Plugins/BluetoothLEOSX.bundle/Contents/_CodeSignature/CodeResources.meta b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/_CodeSignature/CodeResources.meta
new file mode 100644
index 00000000..44cf6eb6
--- /dev/null
+++ b/Assets/Plugins/BluetoothLEOSX.bundle/Contents/_CodeSignature/CodeResources.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 2b362acd4e35f4bb380341cd3df2b9c0
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/iOS.meta b/Assets/Plugins/iOS.meta
index 104ce4a9..b120dcb2 100644
--- a/Assets/Plugins/iOS.meta
+++ b/Assets/Plugins/iOS.meta
@@ -1,8 +1,5 @@
fileFormatVersion: 2
-guid: 7cce98d172bfd2f4fa235200a8c37ffd
+guid: 8d3303514acc04853a1fbd8393630e00
folderAsset: yes
DefaultImporter:
- externalObjects: {}
userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/Plugins/iOS/UnityBluetoothLE.h b/Assets/Plugins/iOS/UnityBluetoothLE.h
new file mode 100644
index 00000000..ce91cfc0
--- /dev/null
+++ b/Assets/Plugins/iOS/UnityBluetoothLE.h
@@ -0,0 +1,107 @@
+//
+// UnityBluetoothLE.h
+// Unity-iPhone
+//
+// Created by Tony Pitman on 03/05/2014.
+//
+//
+
+#import
+#import
+
+#if !TARGET_OS_TV
+#import
+
+@interface UnityBluetoothLE : NSObject
+#else
+@interface UnityBluetoothLE : NSObject
+#endif
+
+{
+ CBCentralManager *_centralManager;
+#if !TARGET_OS_TV
+ CLLocationManager *_locationManager;
+#endif
+ NSMutableDictionary *_peripherals;
+
+#if !TARGET_OS_TV
+ CBPeripheralManager *_peripheralManager;
+
+ NSString *_peripheralName;
+
+ NSMutableDictionary *_services;
+ NSMutableDictionary *_characteristics;
+#endif
+
+ NSMutableArray *_backgroundMessages;
+ BOOL _isPaused;
+ BOOL _alreadyNotified;
+ BOOL _isInitializing;
+ BOOL _rssiOnly;
+ int _recordType;
+
+ long _mtu;
+
+ unsigned char *_writeCharacteristicBytes;
+ long _writeCharacteristicLength;
+ long _writeCharacteristicPosition;
+ long _writeCharacteristicBytesToWrite;
+ CBCharacteristicWriteType _writeCharacteristicWithResponse;
+ int _writeCharacteristicRetries;
+}
+
+@property (atomic, strong) NSMutableDictionary *_peripherals;
+@property (atomic) BOOL _rssiOnly;
+
+- (void)initialize:(BOOL)asCentral asPeripheral:(BOOL)asPeripheral;
+- (void)deInitialize;
+- (void)scanForPeripheralsWithServices:(NSArray *)serviceUUIDs options:(NSDictionary *)options clearPeripheralList:(BOOL)clearPeripheralList recordType:(int)recordType;
+- (void)stopScan;
+- (void)retrieveListOfPeripheralsWithServices:(NSArray *)serviceUUIDs;
+- (void)connectToPeripheral:(NSString *)name;
+- (void)disconnectPeripheral:(NSString *)name;
+- (CBCharacteristic *)getCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString;
+- (void)readCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString;
+- (void)writeCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString data:(NSData *)data withResponse:(BOOL)withResponse;
+- (void)subscribeCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString;
+- (void)unsubscribeCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString;
+- (void)writeCharactersticBytesReset;
+- (void)writeCharactersticBytes:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic data:(NSData *)data withResponse:(CBCharacteristicWriteType)withResponse;
+- (void)writeNextPacket:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic;
+
+#if !TARGET_OS_TV
+- (void)requestMtu:(NSString *)name mtu:(int)mtu;
+- (void)scanForBeacons:(NSArray *)beaconRegions;
+- (void)stopBeaconScan;
+
+- (void)peripheralName:(NSString *)newName;
+- (void)createService:(NSString *)uuid primary:(BOOL)primary;
+- (void)removeService:(NSString *)uuid;
+- (void)removeServices;
+- (void)createCharacteristic:(NSString *)uuid properties:(CBCharacteristicProperties)properties permissions:(CBAttributePermissions)permissions value:(NSData *)value;
+- (void)removeCharacteristic:(NSString *)uuid;
+- (void)removeCharacteristics;
+- (void)startAdvertising;
+- (void)stopAdvertising;
+- (void)updateCharacteristicValue:(NSString *)uuid value:(NSData *)value;
+#endif
+
+- (void)pauseMessages:(BOOL)isPaused;
+- (void)sendUnityMessage:(BOOL)isString message:(NSString *)message;
+
++ (NSString *) base64StringFromData:(NSData *)data length:(int)length;
+
+@end
+
+@interface UnityMessage : NSObject
+
+{
+ BOOL _isString;
+ NSString *_message;
+}
+
+- (void)initialize:(BOOL)isString message:(NSString *)message;
+- (void)deInitialize;
+- (void)sendUnityMessage;
+
+@end
diff --git a/Assets/Plugins/iOS/UnityBluetoothLE.h.meta b/Assets/Plugins/iOS/UnityBluetoothLE.h.meta
new file mode 100644
index 00000000..4bab6c82
--- /dev/null
+++ b/Assets/Plugins/iOS/UnityBluetoothLE.h.meta
@@ -0,0 +1,95 @@
+fileFormatVersion: 2
+guid: 89fad22a839074ac08f9f7ffc9dbce4e
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ '': Linux
+ second:
+ enabled: 0
+ settings:
+ CPU: x86
+ - first:
+ '': OSXIntel
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ '': OSXIntel64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Android: Android
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ DefaultValueInitialized: true
+ OS: AnyOS
+ - first:
+ Facebook: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Facebook: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Linux64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ iPhone: iOS
+ second:
+ enabled: 1
+ settings:
+ CompileFlags:
+ FrameworkDependencies:
+ - first:
+ tvOS: tvOS
+ second:
+ enabled: 1
+ settings: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/iOS/UnityBluetoothLE.mm b/Assets/Plugins/iOS/UnityBluetoothLE.mm
new file mode 100644
index 00000000..7691553a
--- /dev/null
+++ b/Assets/Plugins/iOS/UnityBluetoothLE.mm
@@ -0,0 +1,1316 @@
+//
+// UnityBluetoothLE.h
+// Unity-iPhone
+//
+// Created by Tony Pitman on 03/05/2014.
+//
+//
+
+#import "UnityBluetoothLE.h"
+
+const char _messageDelimeter = '~';
+
+extern "C" {
+
+ UnityBluetoothLE *_unityBluetoothLE = nil;
+
+ void _iOSBluetoothLELogString (NSString *message) {
+
+ NSLog (message);
+ }
+
+ void _iOSBluetoothLELog (char *message) {
+
+ _iOSBluetoothLELogString ([NSString stringWithFormat:@"%s", message]);
+ }
+
+ void _iOSBluetoothLEInitialize (BOOL asCentral, BOOL asPeripheral) {
+
+ _unityBluetoothLE = [UnityBluetoothLE new];
+ [_unityBluetoothLE initialize:asCentral asPeripheral:asPeripheral];
+ }
+
+ void _iOSBluetoothLEDeInitialize () {
+
+ if (_unityBluetoothLE != nil) {
+
+ [_unityBluetoothLE deInitialize];
+ [_unityBluetoothLE release];
+ _unityBluetoothLE = nil;
+
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", "DeInitialized");
+ }
+ }
+
+ void _iOSBluetoothLEPauseMessages (BOOL pause) {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE pauseMessages:pause];
+ }
+
+ void _iOSBluetoothLEScanForPeripheralsWithServices (char *serviceUUIDsStringRaw, bool allowDuplicates, bool rssiOnly, bool clearPeripheralList, int recordType) {
+
+ if (_unityBluetoothLE != nil)
+ {
+ _unityBluetoothLE._rssiOnly = rssiOnly;
+
+ NSMutableArray *actualUUIDs = nil;
+
+ if (serviceUUIDsStringRaw != nil)
+ {
+ NSString *serviceUUIDsString = [NSString stringWithFormat:@"%s", serviceUUIDsStringRaw];
+ NSArray *serviceUUIDs = [serviceUUIDsString componentsSeparatedByString:@"|"];
+
+ if (serviceUUIDs.count > 0)
+ {
+ actualUUIDs = [[NSMutableArray alloc] init];
+
+ for (NSString* sUUID in serviceUUIDs)
+ [actualUUIDs addObject:[CBUUID UUIDWithString:sUUID]];
+ }
+ }
+
+ NSDictionary *options = nil;
+ if (allowDuplicates)
+ options = @{ CBCentralManagerScanOptionAllowDuplicatesKey: @YES };
+
+ [_unityBluetoothLE scanForPeripheralsWithServices:actualUUIDs options:options clearPeripheralList:clearPeripheralList recordType:recordType];
+ }
+ }
+
+ void _iOSBluetoothLEStopScan () {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE stopScan];
+ }
+
+ void _iOSBluetoothLERetrieveListOfPeripheralsWithServices (char *serviceUUIDsStringRaw) {
+
+ if (_unityBluetoothLE != nil)
+ {
+ NSMutableArray *actualUUIDs = nil;
+
+ if (serviceUUIDsStringRaw != nil)
+ {
+ NSString *serviceUUIDsString = [NSString stringWithFormat:@"%s", serviceUUIDsStringRaw];
+ NSArray *serviceUUIDs = [serviceUUIDsString componentsSeparatedByString:@"|"];
+
+ if (serviceUUIDs.count > 0)
+ {
+ actualUUIDs = [[NSMutableArray alloc] init];
+
+ for (NSString* sUUID in serviceUUIDs)
+ [actualUUIDs addObject:[CBUUID UUIDWithString:sUUID]];
+ }
+ }
+
+ [_unityBluetoothLE retrieveListOfPeripheralsWithServices:actualUUIDs];
+ }
+ }
+
+ void _iOSBluetoothLEConnectToPeripheral (char *name) {
+
+ if (_unityBluetoothLE && name != nil)
+ [_unityBluetoothLE connectToPeripheral:[NSString stringWithFormat:@"%s", name]];
+ }
+
+ void _iOSBluetoothLEDisconnectPeripheral (char *name) {
+
+ if (_unityBluetoothLE && name != nil)
+ [_unityBluetoothLE disconnectPeripheral:[NSString stringWithFormat:@"%s", name]];
+ }
+
+ void _iOSBluetoothLEReadCharacteristic (char *name, char *service, char *characteristic) {
+
+ if (_unityBluetoothLE && name != nil && service != nil && characteristic != nil)
+ [_unityBluetoothLE readCharacteristic:[NSString stringWithFormat:@"%s", name] service:[NSString stringWithFormat:@"%s", service] characteristic:[NSString stringWithFormat:@"%s", characteristic]];
+ }
+
+ void _iOSBluetoothLEWriteCharacteristic (char *name, char *service, char *characteristic, unsigned char *data, int length, BOOL withResponse) {
+
+ if (_unityBluetoothLE && name != nil && service != nil && characteristic != nil && data != nil && length > 0)
+ [_unityBluetoothLE writeCharacteristic:[NSString stringWithFormat:@"%s", name] service:[NSString stringWithFormat:@"%s", service] characteristic:[NSString stringWithFormat:@"%s", characteristic] data:[NSData dataWithBytes:data length:length] withResponse:withResponse];
+ }
+
+ void _iOSBluetoothLESubscribeCharacteristic (char *name, char *service, char *characteristic) {
+
+ if (_unityBluetoothLE && name != nil && service != nil && characteristic != nil)
+ [_unityBluetoothLE subscribeCharacteristic:[NSString stringWithFormat:@"%s", name] service:[NSString stringWithFormat:@"%s", service] characteristic:[NSString stringWithFormat:@"%s", characteristic]];
+ }
+
+ void _iOSBluetoothLEUnSubscribeCharacteristic (char *name, char *service, char *characteristic) {
+
+ if (_unityBluetoothLE && name != nil && service != nil && characteristic != nil)
+ [_unityBluetoothLE unsubscribeCharacteristic:[NSString stringWithFormat:@"%s", name] service:[NSString stringWithFormat:@"%s", service] characteristic:[NSString stringWithFormat:@"%s", characteristic]];
+ }
+
+ void _iOSBluetoothLEDisconnectAll () {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE disconnectAll];
+ }
+
+#if !TARGET_OS_TV
+ void _iOSBluetoothLERequestMtu (char *name, int mtu) {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE requestMtu:[NSString stringWithFormat:@"%s", name] mtu:mtu];
+ }
+
+ void _iOSBluetoothLEScanForBeacons (char *proximityUUIDsStringRaw) {
+
+ if (_unityBluetoothLE != nil)
+ {
+ NSMutableArray *actualUUIDs = nil;
+
+ if (proximityUUIDsStringRaw != nil)
+ {
+ NSString *proximityUUIDsString = [NSString stringWithFormat:@"%s", proximityUUIDsStringRaw];
+ NSArray *proximityUUIDs = [proximityUUIDsString componentsSeparatedByString:@"|"];
+
+ if (proximityUUIDs.count > 0)
+ {
+ NSMutableArray *beaconRegions = [[NSMutableArray alloc] init];
+
+ for (NSString* sUUID in proximityUUIDs)
+ {
+ NSArray *parts = [sUUID componentsSeparatedByString:@":"];
+ if (parts.count == 2)
+ {
+ CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:parts[0]] identifier:parts[1]];
+ [beaconRegions addObject:beaconRegion];
+
+ [_unityBluetoothLE scanForBeacons:beaconRegions];
+ }
+ else
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~iBeacon Scanning missing identifiers"];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ }
+ }
+ else
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~iBeacon Scanning requires proximity UUIDs"];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ }
+ else
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~iBeacon Scanning requires proximity UUIDs"];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ }
+ }
+
+ void _iOSBluetoothLEStopBeaconScan () {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE stopBeaconScan];
+ }
+
+ void _iOSBluetoothLEPeripheralName (char *newName) {
+
+ if (_unityBluetoothLE != nil && newName != nil)
+ [_unityBluetoothLE peripheralName:[[NSString alloc] initWithUTF8String:newName]];
+ }
+
+ void _iOSBluetoothLECreateService (char *uuid, BOOL primary) {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE createService:[NSString stringWithFormat:@"%s", uuid] primary:primary];
+ }
+
+ void _iOSBluetoothLERemoveService (char *uuid) {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE removeService:[NSString stringWithFormat:@"%s", uuid]];
+ }
+
+ void _iOSBluetoothLERemoveServices () {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE removeServices];
+ }
+
+ void _iOSBluetoothLECreateCharacteristic (char *uuid, int properties, int permissions, unsigned char *data, int length) {
+
+ if (_unityBluetoothLE != nil) {
+
+ NSData *value = nil;
+ if (data != nil)
+ value = [[NSData alloc] initWithBytes:data length:length];
+
+ [_unityBluetoothLE createCharacteristic:[NSString stringWithFormat:@"%s", uuid] properties:properties permissions:permissions value:value];
+ }
+ }
+
+ void _iOSBluetoothLERemoveCharacteristic (char *uuid) {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE removeCharacteristic:[NSString stringWithFormat:@"%s", uuid]];
+ }
+
+ void _iOSBluetoothLERemoveCharacteristics () {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE removeCharacteristics];
+ }
+
+ void _iOSBluetoothLEStartAdvertising () {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE startAdvertising];
+ }
+
+ void _iOSBluetoothLEStopAdvertising () {
+
+ if (_unityBluetoothLE != nil)
+ [_unityBluetoothLE stopAdvertising];
+ }
+
+ void _iOSBluetoothLEUpdateCharacteristicValue (char *uuid, unsigned char *data, int length) {
+
+ if (_unityBluetoothLE != nil) {
+
+ NSData *value = nil;
+ if (data != nil)
+ value = [[NSData alloc] initWithBytes:data length:length];
+
+ [_unityBluetoothLE updateCharacteristicValue:[NSString stringWithFormat:@"%s", uuid] value:value];
+ }
+ }
+#endif
+}
+
+@implementation UnityBluetoothLE
+
+@synthesize _peripherals;
+@synthesize _rssiOnly;
+
+- (void)initialize:(BOOL)asCentral asPeripheral:(BOOL)asPeripheral
+{
+ _mtu = 20;
+
+ _isPaused = FALSE;
+ _isInitializing = TRUE;
+
+ _centralManager = nil;
+#if !TARGET_OS_TV
+ _peripheralManager = nil;
+ _services = nil;
+ _characteristics = nil;
+#endif
+ if (asCentral)
+ _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
+
+#if !TARGET_OS_TV
+ if (asPeripheral)
+ _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
+
+ _services = [[NSMutableDictionary alloc] init];
+ _characteristics = [[NSMutableDictionary alloc] init];
+#endif
+
+ _peripherals = [[NSMutableDictionary alloc] init];
+}
+
+- (void)deInitialize
+{
+ if (_backgroundMessages != nil)
+ {
+ for (UnityMessage *message in _backgroundMessages)
+ {
+ if (message != nil)
+ {
+ [message deInitialize];
+ [message release];
+ }
+ }
+
+ [_backgroundMessages release];
+ _backgroundMessages = nil;
+ }
+
+#if !TARGET_OS_TV
+ if (_peripheralManager != nil)
+ [self stopAdvertising];
+
+ [self removeCharacteristics];
+ [self removeServices];
+#endif
+
+ if (_centralManager != nil)
+ [self stopScan];
+
+ [_peripherals removeAllObjects];
+}
+
+- (void)pauseMessages:(BOOL)isPaused
+{
+ if (isPaused != _isPaused) {
+
+ if (_backgroundMessages == nil)
+ _backgroundMessages = [[NSMutableArray alloc] init];
+
+ _isPaused = isPaused;
+
+ // if we are not paused now since we know we changed state
+ // that means we were paused so we need to pump the saved
+ // messages to Unity
+ if (isPaused) {
+
+ if (_backgroundMessages != nil) {
+
+ for (UnityMessage *message in _backgroundMessages) {
+
+ if (message != nil) {
+
+ [message sendUnityMessage];
+ [message deInitialize];
+ [message release];
+ }
+ }
+
+ [_backgroundMessages removeAllObjects];
+ }
+ }
+ }
+}
+
+#if !TARGET_OS_TV
+- (void)createService:(NSString *)uuid primary:(BOOL)primary
+{
+ CBUUID *cbuuid = [CBUUID UUIDWithString:uuid];
+ CBMutableService *service = [[CBMutableService alloc] initWithType:cbuuid primary:primary];
+
+ NSMutableArray *characteristics = [[NSMutableArray alloc] init];
+
+ NSEnumerator *enumerator = [_characteristics keyEnumerator];
+ id key;
+ while ((key = [enumerator nextObject]))
+ [characteristics addObject:[_characteristics objectForKey:key]];
+
+ service.characteristics = characteristics;
+
+ [_services setObject:service forKey:cbuuid];
+
+ if (_peripheralManager != nil)
+ {
+ [_peripheralManager addService:service];
+ }
+}
+
+- (void)removeService:(NSString *)uuid
+{
+ if (_services != nil)
+ {
+ if (_peripheralManager != nil)
+ {
+ CBMutableService *service = [_services objectForKey:uuid];
+ if (service != nil)
+ [_peripheralManager removeService:service];
+ }
+
+ [_services removeObjectForKey:uuid];
+ }
+}
+
+- (void)removeServices
+{
+ if (_services != nil)
+ {
+ [_services removeAllObjects];
+
+ if (_peripheralManager != nil)
+ [_peripheralManager removeAllServices];
+ }
+}
+
+- (void)peripheralName:(NSString *)newName
+{
+ _peripheralName = newName;
+}
+
+- (void)createCharacteristic:(NSString *)uuid properties:(CBCharacteristicProperties)properties permissions:(CBAttributePermissions)permissions value:(NSData *)value
+{
+ CBUUID *cbuuid = [CBUUID UUIDWithString:uuid];
+ CBCharacteristic *characteristic = [[CBMutableCharacteristic alloc] initWithType:cbuuid properties:properties value:value permissions:permissions];
+
+ [_characteristics setObject:characteristic forKey:cbuuid];
+}
+
+- (void)removeCharacteristic:(NSString *)uuid
+{
+ if (_characteristics != nil)
+ [_characteristics removeObjectForKey:uuid];
+}
+
+- (void)removeCharacteristics
+{
+ if (_characteristics != nil)
+ [_characteristics removeAllObjects];
+}
+
+- (void)startAdvertising
+{
+ if (_peripheralManager != nil && _services != nil)
+ {
+ NSMutableArray *services = [[NSMutableArray alloc] init];
+
+ NSEnumerator *enumerator = [_services keyEnumerator];
+ id key;
+ while ((key = [enumerator nextObject]))
+ {
+ CBMutableService *service = [_services objectForKey:key];
+ [services addObject:service.UUID];
+ }
+
+ if (_peripheralName == nil)
+ _peripheralName = @"";
+
+ [_peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : services, CBAdvertisementDataLocalNameKey : _peripheralName }];
+ }
+}
+
+- (void)stopAdvertising
+{
+ if (_peripheralManager != nil)
+ {
+ [_peripheralManager stopAdvertising];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", "StoppedAdvertising");
+ }
+}
+
+- (void)updateCharacteristicValue:(NSString *)uuid value:(NSData *)value
+{
+ if (_characteristics != nil)
+ {
+ CBUUID *cbuuid = [CBUUID UUIDWithString:uuid];
+ CBMutableCharacteristic *characteristic = [_characteristics objectForKey:cbuuid];
+ if (characteristic != nil)
+ {
+ characteristic.value = value;
+ if (_peripheralManager != nil)
+ [_peripheralManager updateValue:value forCharacteristic:characteristic onSubscribedCentrals:nil];
+ }
+ }
+}
+
+- (void)requestMtu:(NSString *)name mtu:(int)mtu
+{
+ _mtu = mtu;
+
+ NSString *message = [NSString stringWithFormat:@"MtuChanged~%@~%d", name, _mtu];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
+}
+
+- (void)scanForBeacons:(NSArray*)beaconRegions
+{
+ if ([CLLocationManager isRangingAvailable])
+ {
+ _locationManager = [CLLocationManager new];
+ _locationManager.delegate = self;
+
+ [_locationManager requestWhenInUseAuthorization];
+
+ for (CLBeaconRegion *region in beaconRegions)
+ [_locationManager startRangingBeaconsInRegion:region];
+ }
+ else
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~iBeacon Ranging is not available"];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+}
+
+- (void) stopBeaconScan
+{
+ if (_locationManager != nil)
+ {
+ for (CLBeaconRegion *region in _locationManager.rangedRegions)
+ [_locationManager stopRangingBeaconsInRegion:region];
+
+ [_locationManager release];
+ _locationManager = nil;
+ }
+}
+
+// beacon delegate implementation
+- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region
+{
+ NSString *message;
+ for (CLBeacon *beacon in beacons)
+ {
+ message = [NSString stringWithFormat:@"DiscoveredBeacon~%@~%ld~%ld~%ld~%ld~%ld", [beacon.proximityUUID.UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""], beacon.major.longValue, beacon.minor.longValue, (long)beacon.rssi, (long)0, (long)beacon.proximity];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
+ }
+}
+#endif
+
+// central delegate implementation
+- (void)scanForPeripheralsWithServices:(NSArray *)serviceUUIDs options:(NSDictionary *)options clearPeripheralList:(BOOL)clearPeripheralList recordType:(int)recordType
+{
+ if (_centralManager != nil)
+ {
+ recordType = recordType;
+ if (clearPeripheralList && _peripherals != nil)
+ [_peripherals removeAllObjects];
+
+ [_centralManager scanForPeripheralsWithServices:serviceUUIDs options:options];
+ }
+}
+
+- (void) stopScan
+{
+ if (_centralManager != nil)
+ [_centralManager stopScan];
+}
+
+- (void)retrieveListOfPeripheralsWithServices:(NSArray *)serviceUUIDs
+{
+ if (_centralManager != nil)
+ {
+ if (_peripherals != nil)
+ [_peripherals removeAllObjects];
+
+ NSArray * list = [_centralManager retrieveConnectedPeripheralsWithServices:serviceUUIDs];
+ if (list != nil)
+ {
+ for (int i = 0; i < list.count; ++i)
+ {
+ CBPeripheral *peripheral = [list objectAtIndex:i];
+ if (peripheral != nil)
+ {
+ NSString *identifier = [[peripheral identifier] UUIDString];
+ NSString *name = [peripheral name];
+
+ NSString *message = [NSString stringWithFormat:@"RetrievedConnectedPeripheral~%@~%@", identifier, name];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
+
+ [_peripherals setObject:peripheral forKey:identifier];
+ }
+ }
+ }
+ }
+}
+
+- (void)connectToPeripheral:(NSString *)name
+{
+ if (_peripherals != nil && name != nil)
+ {
+ CBPeripheral *peripheral = [_peripherals objectForKey:name];
+ if (peripheral != nil)
+ [_centralManager connectPeripheral:peripheral options:nil];
+ }
+}
+
+- (void)disconnectAll
+{
+ if (_peripherals != nil && [_peripherals count] > 0)
+ {
+ NSArray* keys = [_peripherals allKeys];
+ for(NSString* key in keys)
+ {
+ CBPeripheral *peripheral = [_peripherals objectForKey:key];
+ if (peripheral != nil)
+ [_centralManager cancelPeripheralConnection:peripheral];
+ }
+ }
+}
+
+- (void)disconnectPeripheral:(NSString *)name
+{
+ if (_peripherals != nil && name != nil)
+ {
+ CBPeripheral *peripheral = [_peripherals objectForKey:name];
+ if (peripheral != nil)
+ {
+ [_centralManager cancelPeripheralConnection:peripheral];
+ }
+ }
+}
+
+- (CBCharacteristic *)getCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString
+{
+ CBCharacteristic *returnCharacteristic = nil;
+
+ if (name != nil && serviceString != nil && characteristicString != nil && _peripherals != nil)
+ {
+ CBPeripheral *peripheral = [_peripherals objectForKey:name];
+ if (peripheral != nil)
+ {
+ CBUUID *serviceUUID = [CBUUID UUIDWithString:serviceString];
+ CBUUID *characteristicUUID = [CBUUID UUIDWithString:characteristicString];
+
+ for (CBService *service in peripheral.services)
+ {
+ if ([service.UUID isEqual:serviceUUID])
+ {
+ for (CBCharacteristic *characteristic in service.characteristics)
+ {
+ if ([characteristic.UUID isEqual:characteristicUUID])
+ {
+ returnCharacteristic = characteristic;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return returnCharacteristic;
+}
+
+- (void)readCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString
+{
+ if (name != nil && serviceString != nil && characteristicString != nil && _peripherals != nil)
+ {
+ CBPeripheral *peripheral = [_peripherals objectForKey:name];
+ if (peripheral != nil)
+ {
+ CBCharacteristic *characteristic = [_unityBluetoothLE getCharacteristic:name service:serviceString characteristic:characteristicString];
+ if (characteristic != nil)
+ [peripheral readValueForCharacteristic:characteristic];
+ }
+ }
+}
+
+- (void)writeCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString data:(NSData *)data withResponse:(BOOL)withResponse
+{
+ if (name != nil && serviceString != nil && characteristicString != nil && _peripherals != nil && data != nil)
+ {
+ CBPeripheral *peripheral = [_peripherals objectForKey:name];
+ if (peripheral != nil)
+ {
+ CBCharacteristic *characteristic = [_unityBluetoothLE getCharacteristic:name service:serviceString characteristic:characteristicString];
+ if (characteristic != nil)
+ {
+ CBCharacteristicWriteType type = CBCharacteristicWriteWithoutResponse;
+ if (withResponse)
+ type = CBCharacteristicWriteWithResponse;
+
+ [self writeCharactersticBytes:peripheral characteristic:characteristic data:data withResponse:type];
+ }
+ }
+ }
+}
+
+- (void)subscribeCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString
+{
+ if (name != nil && serviceString != nil && characteristicString != nil && _peripherals != nil)
+ {
+ CBPeripheral *peripheral = [_peripherals objectForKey:name];
+ if (peripheral != nil)
+ {
+ CBCharacteristic *characteristic = [_unityBluetoothLE getCharacteristic:name service:serviceString characteristic:characteristicString];
+ if (characteristic != nil)
+ [peripheral setNotifyValue:YES forCharacteristic:characteristic];
+ }
+ }
+}
+
+- (void)unsubscribeCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString
+{
+ if (name != nil && serviceString != nil && characteristicString != nil && _peripherals != nil)
+ {
+ CBPeripheral *peripheral = [_peripherals objectForKey:name];
+ if (peripheral != nil)
+ {
+ CBCharacteristic *characteristic = [_unityBluetoothLE getCharacteristic:name service:serviceString characteristic:characteristicString];
+ if (characteristic != nil)
+ [peripheral setNotifyValue:NO forCharacteristic:characteristic];
+ }
+ }
+}
+
+- (void)centralManagerDidUpdateState:(CBCentralManager *)central
+{
+ switch (central.state)
+ {
+ case CBCentralManagerStateUnsupported:
+ {
+ NSLog(@"Central State: Unsupported");
+
+ NSString *message = [NSString stringWithFormat:@"Error~Bluetooth LE Not Supported"];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ } break;
+
+ case CBCentralManagerStateUnauthorized:
+ {
+ NSLog(@"Central State: Unauthorized");
+
+ NSString *message = [NSString stringWithFormat:@"Error~Bluetooth LE Not Authorized"];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ } break;
+
+ case CBCentralManagerStatePoweredOff:
+ {
+ NSLog(@"Central State: Powered Off");
+
+ NSString *message = [NSString stringWithFormat:@"Error~Bluetooth LE Powered Off"];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ } break;
+
+ case CBCentralManagerStatePoweredOn:
+ {
+ NSLog(@"Central State: Powered On");
+ if (_isInitializing)
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", "Initialized");
+ _isInitializing = FALSE;
+ } break;
+
+ case CBCentralManagerStateUnknown:
+ {
+ NSLog(@"Central State: Unknown");
+
+ NSString *message = [NSString stringWithFormat:@"Error~Bluetooth LE Unknown"];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ } break;
+
+ default:
+ {
+ }
+
+ }
+}
+
+- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
+{
+
+}
+
+- (void)centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals
+{
+
+}
+
+- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
+{
+ if (error)
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+}
+
+- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
+{
+ if (_peripherals != nil && peripheral != nil)
+ {
+ NSString *name = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
+ if (name == nil)
+ name = peripheral.name;
+ if (name == nil)
+ name = @"No Name";
+
+ if (name != nil)
+ {
+ NSString *identifier = nil;
+
+ NSString *foundPeripheral = [self findPeripheralName:peripheral];
+ if (foundPeripheral == nil)
+ identifier = [[peripheral identifier] UUIDString];
+ else
+ identifier = foundPeripheral;
+
+ NSString *message = nil;
+
+ if (advertisementData != nil && [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey] != nil)
+ {
+ NSData* bytes = [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey];
+ message = [NSString stringWithFormat:@"DiscoveredPeripheral~%@~%@~%@~%@", identifier, name, RSSI, [UnityBluetoothLE base64StringFromData:bytes length:bytes.length]];
+ }
+ else if (RSSI != 0 && _rssiOnly)
+ {
+ message = [NSString stringWithFormat:@"DiscoveredPeripheral~%@~%@~%@~", identifier, name, RSSI];
+ }
+ else
+ {
+ message = [NSString stringWithFormat:@"DiscoveredPeripheral~%@~%@", identifier, name];
+ }
+
+ if (message != nil)
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
+
+ [_peripherals setObject:peripheral forKey:identifier];
+ }
+ }
+}
+
+- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
+{
+ if (_peripherals != nil)
+ {
+ NSString *foundPeripheral = [self findPeripheralName:peripheral];
+ if (foundPeripheral != nil)
+ {
+ NSString *message = [NSString stringWithFormat:@"DisconnectedPeripheral~%@", foundPeripheral];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
+ }
+ }
+}
+
+- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
+{
+ NSString *foundPeripheral = [self findPeripheralName:peripheral];
+ if (foundPeripheral != nil)
+ {
+ NSString *message = [NSString stringWithFormat:@"ConnectedPeripheral~%@", foundPeripheral];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
+ peripheral.delegate = self;
+ [peripheral discoverServices:nil];
+ }
+}
+
+- (CBPeripheral *) findPeripheralInList:(CBPeripheral*)peripheral
+{
+ CBPeripheral *foundPeripheral = nil;
+
+ NSEnumerator *enumerator = [_peripherals keyEnumerator];
+ id key;
+ while ((key = [enumerator nextObject]))
+ {
+ CBPeripheral *tempPeripheral = [_peripherals objectForKey:key];
+ if ([tempPeripheral isEqual:peripheral])
+ {
+ foundPeripheral = tempPeripheral;
+ break;
+ }
+ }
+
+ return foundPeripheral;
+}
+
+- (NSString *) findPeripheralName:(CBPeripheral*)peripheral
+{
+ NSString *foundPeripheral = nil;
+
+ NSEnumerator *enumerator = [_peripherals keyEnumerator];
+ id key;
+ while ((key = [enumerator nextObject]))
+ {
+ CBPeripheral *tempPeripheral = [_peripherals objectForKey:key];
+ if ([tempPeripheral isEqual:peripheral])
+ {
+ foundPeripheral = key;
+ break;
+ }
+ }
+
+ return foundPeripheral;
+}
+
+// central peripheral delegate implementation
+- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
+{
+ if (error)
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ else
+ {
+ NSString *foundPeripheral = [self findPeripheralName:peripheral];
+ if (foundPeripheral != nil)
+ {
+ for (CBService *service in peripheral.services)
+ {
+ NSString *message = [NSString stringWithFormat:@"DiscoveredService~%@~%@", foundPeripheral, [service UUID]];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
+
+ [peripheral discoverCharacteristics:nil forService:service];
+ }
+ }
+ }
+}
+
+- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
+{
+ if (error)
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ else
+ {
+ NSString *foundPeripheral = [self findPeripheralName:peripheral];
+ if (foundPeripheral != nil)
+ {
+ for (CBCharacteristic *characteristic in service.characteristics)
+ {
+ NSString *message = [NSString stringWithFormat:@"DiscoveredCharacteristic~%@~%@~%@", foundPeripheral, [service UUID], [characteristic UUID]];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
+ }
+ }
+ }
+}
+
+- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
+{
+ if (error)
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ else
+ {
+ NSString *foundPeripheral = [self findPeripheralName:peripheral];
+ if (foundPeripheral != nil)
+ {
+ if (characteristic.value != nil)
+ {
+ NSString *message = [NSString stringWithFormat:@"DidUpdateValueForCharacteristic~%@~%@~%@", foundPeripheral, [characteristic UUID], [UnityBluetoothLE base64StringFromData:characteristic.value length:characteristic.value.length]];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
+ //NSString *message = [UnityBluetoothLE base64StringFromData:characteristic.value length:characteristic.value.length];
+ //UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothData", [message UTF8String] );
+ }
+ }
+ }
+}
+
+- (void)writeCharactersticBytesReset
+{
+ _writeCharacteristicBytes = nil;
+ _writeCharacteristicLength = 0;
+ _writeCharacteristicPosition = 0;
+ _writeCharacteristicBytesToWrite = 0;
+ _writeCharacteristicWithResponse = CBCharacteristicWriteWithResponse;
+ _writeCharacteristicRetries = 3;
+}
+
+- (void)writeCharactersticBytes:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic data:(NSData *)data withResponse:(CBCharacteristicWriteType)withResponse
+{
+ if (_writeCharacteristicBytes == nil && (_mtu == 0 || data.length > _mtu))
+ {
+ _writeCharacteristicLength = data.length;
+ _writeCharacteristicBytes = (unsigned char*)malloc(_writeCharacteristicLength);
+ memcpy(_writeCharacteristicBytes, [data bytes], _writeCharacteristicLength);
+ _writeCharacteristicPosition = 0;
+ _writeCharacteristicWithResponse = withResponse;
+ if (_mtu == 0)
+ _writeCharacteristicBytesToWrite = _writeCharacteristicLength;
+ else
+ _writeCharacteristicBytesToWrite = _mtu;
+ }
+
+ NSLog(@"write characteristic block");
+
+ if (_writeCharacteristicBytes != nil)
+ {
+ NSMutableData *newData = [NSMutableData dataWithCapacity:_writeCharacteristicBytesToWrite];
+ [newData appendBytes:&_writeCharacteristicBytes[_writeCharacteristicPosition] length:_writeCharacteristicBytesToWrite];
+ data = newData;
+ NSLog(@"data: %@", data);
+ }
+
+ NSLog(@"writing %ld bytes, %ld with response", data.length, withResponse);
+ [peripheral writeValue:data forCharacteristic:characteristic type:withResponse];
+
+ if (withResponse == CBCharacteristicWriteWithoutResponse)
+ {
+ double delayInSeconds = 0.01;
+ dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
+ dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
+ [self writeNextPacket:peripheral characteristic:characteristic];
+ });
+ }
+}
+
+- (void)writeNextPacket:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic
+{
+ if (_writeCharacteristicLength > _writeCharacteristicPosition + _writeCharacteristicBytesToWrite)
+ {
+ _writeCharacteristicPosition += _writeCharacteristicBytesToWrite;
+ if (_writeCharacteristicPosition + _writeCharacteristicBytesToWrite > _writeCharacteristicLength)
+ _writeCharacteristicBytesToWrite = _writeCharacteristicLength - _writeCharacteristicPosition;
+
+ NSMutableData *data = [NSMutableData dataWithCapacity:_writeCharacteristicLength];
+ [data appendBytes:_writeCharacteristicBytes length:_writeCharacteristicLength];
+ [self writeCharactersticBytes:peripheral characteristic:characteristic data:data withResponse:_writeCharacteristicWithResponse];
+ }
+ else
+ {
+ [self writeCharactersticBytesReset];
+ NSString *message = [NSString stringWithFormat:@"DidWriteCharacteristic~%@", characteristic.UUID];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+}
+
+- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
+{
+ if (error)
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ else
+ {
+ NSLog(@"%ld bytes written, %ld position, %ld length, %ld with response", _writeCharacteristicBytesToWrite, _writeCharacteristicPosition, _writeCharacteristicLength, _writeCharacteristicWithResponse);
+
+ if (_writeCharacteristicBytesToWrite > 0)
+ {
+ [self writeNextPacket:peripheral characteristic:characteristic];
+ }
+ else
+ {
+ NSString *message = [NSString stringWithFormat:@"DidWriteCharacteristic~%@", characteristic.UUID];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ }
+}
+
+- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
+{
+ if (error)
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ else
+ {
+ NSString *foundPeripheral = [self findPeripheralName:peripheral];
+ if (foundPeripheral != nil)
+ {
+ NSString *message = [NSString stringWithFormat:@"DidUpdateNotificationStateForCharacteristic~%@~%@", foundPeripheral, characteristic.UUID];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ }
+}
+
+#if !TARGET_OS_TV
+// peripheral manager delegate implementation
+- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
+{
+ _iOSBluetoothLELogString ([NSString stringWithFormat:@"Peripheral State Update: %d", (int)peripheral.state]);
+ if (_isInitializing && peripheral.state == CBPeripheralManagerStatePoweredOn)
+ {
+ _isInitializing = FALSE;
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", "Initialized");
+ }
+}
+
+- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error
+{
+ if (error)
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ else
+ {
+ NSString *message = [NSString stringWithFormat:@"ServiceAdded~%@", service.UUID];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+}
+
+- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
+{
+ if (error)
+ {
+ NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ else
+ {
+ NSString *message = [NSString stringWithFormat:@"StartedAdvertising"];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+}
+
+- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
+{
+
+}
+
+- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
+{
+
+}
+
+- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request
+{
+ BOOL success = FALSE;
+
+ if (_peripheralManager != nil)
+ {
+ CBMutableCharacteristic *characteristic = [_characteristics objectForKey:request.characteristic.UUID];
+
+ if (characteristic != nil)
+ {
+ request.value = [characteristic.value subdataWithRange:NSMakeRange(request.offset, characteristic.value.length - request.offset)];
+ [_peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
+
+ success = TRUE;
+ }
+ }
+
+ if (!success)
+ [_peripheralManager respondToRequest:request withResult:CBATTErrorAttributeNotFound];
+}
+
+- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
+{
+ BOOL success = FALSE;
+
+ if (_peripheralManager != nil)
+ {
+ for (int i = 0; i < requests.count; ++i)
+ {
+ CBATTRequest *request = [requests objectAtIndex:i];
+ if (request != nil)
+ {
+ CBMutableCharacteristic *characteristic = [_characteristics objectForKey:request.characteristic.UUID];
+
+ if (characteristic != nil)
+ {
+ characteristic.value = request.value;
+
+ NSString *message = [NSString stringWithFormat:@"PeripheralReceivedWriteData~%@~%@", [characteristic UUID], [UnityBluetoothLE base64StringFromData:characteristic.value length:characteristic.value.length]];
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
+
+ success = TRUE;
+ }
+ else
+ {
+ success = FALSE;
+ break;
+ }
+ }
+ else
+ {
+ success = FALSE;
+ break;
+ }
+ }
+ }
+
+ if (success)
+ [_peripheralManager respondToRequest:[requests objectAtIndex:0] withResult:CBATTErrorSuccess];
+ else
+ [_peripheralManager respondToRequest:[requests objectAtIndex:0] withResult:CBATTErrorAttributeNotFound];
+}
+#endif
+
+- (void)sendUnityMessage:(BOOL)isString message:(NSString *)message
+{
+ if (_isPaused) {
+
+ if (_backgroundMessages != nil) {
+
+ UnityMessage *unitymessage = [[UnityMessage alloc] init];
+ if (unitymessage != nil) {
+
+ [unitymessage initialize:isString message:message];
+ [_backgroundMessages addObject:unitymessage];
+ }
+ }
+ }
+ else {
+
+ if (isString)
+ {
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
+ }
+ else
+ {
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothData", [message UTF8String] );
+ }
+ }
+}
+
+static char base64EncodingTable[64] =
+{
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
++ (NSString *) base64StringFromData: (NSData *)data length: (int)length
+{
+ unsigned long ixtext, lentext;
+ long ctremaining;
+ unsigned char input[3], output[4];
+ short i, charsonline = 0, ctcopy;
+ const unsigned char *raw;
+ NSMutableString *result;
+
+ lentext = [data length];
+ if (lentext < 1)
+ return @"";
+ result = [NSMutableString stringWithCapacity: lentext];
+ raw = (const unsigned char *)[data bytes];
+ ixtext = 0;
+
+ while (true) {
+ ctremaining = lentext - ixtext;
+ if (ctremaining <= 0)
+ break;
+ for (i = 0; i < 3; i++) {
+ unsigned long ix = ixtext + i;
+ if (ix < lentext)
+ input[i] = raw[ix];
+ else
+ input[i] = 0;
+ }
+ output[0] = (input[0] & 0xFC) >> 2;
+ output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4);
+ output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6);
+ output[3] = input[2] & 0x3F;
+ ctcopy = 4;
+ switch (ctremaining) {
+ case 1:
+ ctcopy = 2;
+ break;
+ case 2:
+ ctcopy = 3;
+ break;
+ }
+
+ for (i = 0; i < ctcopy; i++)
+ [result appendString: [NSString stringWithFormat: @"%c", base64EncodingTable[output[i]]]];
+
+ for (i = ctcopy; i < 4; i++)
+ [result appendString: @"="];
+
+ ixtext += 3;
+ charsonline += 4;
+
+ if ((length > 0) && (charsonline >= length))
+ charsonline = 0;
+ }
+ return result;
+}
+
+#pragma mark Internal
+
+@end
+
+@implementation UnityMessage
+
+- (void)initialize:(BOOL)isString message:(NSString *)message
+{
+ _isString = isString;
+ _message = [message copy];
+}
+
+- (void)deInitialize
+{
+ if (_message != nil)
+ [_message release];
+ _message = nil;
+}
+
+- (void)sendUnityMessage
+{
+ if (_message != nil) {
+
+ if (_isString)
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [_message UTF8String] );
+ else
+ UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothData", [_message UTF8String] );
+ }
+}
+
+@end
diff --git a/Assets/Plugins/iOS/UnityBluetoothLE.mm.meta b/Assets/Plugins/iOS/UnityBluetoothLE.mm.meta
new file mode 100644
index 00000000..33ce6211
--- /dev/null
+++ b/Assets/Plugins/iOS/UnityBluetoothLE.mm.meta
@@ -0,0 +1,124 @@
+fileFormatVersion: 2
+guid: 6a40ca1fe2b7a48e5b257178dfdca41e
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ : Any
+ second:
+ enabled: 0
+ settings:
+ Exclude Android: 1
+ Exclude Editor: 1
+ Exclude Linux: 1
+ Exclude Linux64: 1
+ Exclude LinuxUniversal: 1
+ Exclude OSXUniversal: 1
+ Exclude Win: 1
+ Exclude Win64: 1
+ Exclude iOS: 0
+ - first:
+ : Linux
+ second:
+ enabled: 0
+ settings:
+ CPU: x86
+ - first:
+ : OSXIntel
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ : OSXIntel64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Android: Android
+ second:
+ enabled: 0
+ settings:
+ CPU: ARMv7
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ DefaultValueInitialized: true
+ OS: AnyOS
+ - first:
+ Facebook: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Facebook: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Linux
+ second:
+ enabled: 0
+ settings:
+ CPU: x86
+ - first:
+ Standalone: Linux64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: OSXUniversal
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ Standalone: Win64
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ - first:
+ iPhone: iOS
+ second:
+ enabled: 1
+ settings:
+ AddToEmbeddedBinaries: false
+ CompileFlags: -fno-objc-arc
+ FrameworkDependencies: CoreBluetooth;
+ - first:
+ tvOS: tvOS
+ second:
+ enabled: 1
+ settings:
+ CompileFlags: -fno-objc-arc
+ FrameworkDependencies: CoreBluetooth;
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/App.cs b/Assets/Scripts/App.cs
index f649e2d5..956369e4 100644
--- a/Assets/Scripts/App.cs
+++ b/Assets/Scripts/App.cs
@@ -11,7 +11,7 @@ using Assets.Scripts.Devices;
public static class App
{
- public static string Host = "http://192.168.0.101:5084/";
+ public static string Host = "http://192.168.0.101:5083/";
public static string AppVersion = Application.version;
diff --git a/Assets/Scripts/Devices/Ble/BleDevice.cs b/Assets/Scripts/Devices/Ble/BleDevice.cs
index 6b634c20..beadb367 100644
--- a/Assets/Scripts/Devices/Ble/BleDevice.cs
+++ b/Assets/Scripts/Devices/Ble/BleDevice.cs
@@ -17,7 +17,7 @@ namespace Assets.Scripts.Devices.Ble
public abstract class BleDevice : AbstractDevice
{
- protected BleWinHwInterface hwInterface;
+ protected IBleWinHwInterface hwInterface;
protected BlePeripheralInfo peripheralInfo;
private readonly HashSet services = new HashSet();
@@ -32,7 +32,7 @@ namespace Assets.Scripts.Devices.Ble
}
public List Characteristics { get; protected set; } = new List();
- public BleDevice(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface, SensorType sensor) : base(peripheralInfo.Address, NetworkType.BLE)
+ public BleDevice(BlePeripheralInfo peripheralInfo, IBleWinHwInterface bleWinHwInterface, SensorType sensor) : base(peripheralInfo.Address, NetworkType.BLE)
{
this.hwInterface = bleWinHwInterface;
this.hwInterface.BluetoothStateChangedEvent += BluetoothStateChangedEvent;
@@ -50,7 +50,7 @@ namespace Assets.Scripts.Devices.Ble
Characteristics.Add(new ModelNumberCharacteristic());
}
- private void HwInterface_PeripheralDisconnectedEvent(BleWinHwInterface hwInterface, BlePeripheralInfo peripheral, BleResponse response, bool manualDisconnect)
+ private void HwInterface_PeripheralDisconnectedEvent(IBleWinHwInterface hwInterface, BlePeripheralInfo peripheral, BleResponse response, bool manualDisconnect)
{
if (!peripheral.MatchAddress(this.peripheralInfo.Address))
{
@@ -93,7 +93,7 @@ namespace Assets.Scripts.Devices.Ble
}
}
- private void PeripheralConnectedAction(BleWinHwInterface hwInterface, BlePeripheralInfo sender, BleResponse response)
+ private void PeripheralConnectedAction(IBleWinHwInterface hwInterface, BlePeripheralInfo sender, BleResponse response)
{
Debug.Log($"连接{ this.Name }"+response.IsSuccess);
if (response.IsSuccess)
@@ -123,7 +123,7 @@ namespace Assets.Scripts.Devices.Ble
Debug.Log("断开设备" + this.Name);
//App.MainDeviceAdapter.PrintStatus();
-
+ this.State = DeviceState.Disconnected;
this.hwInterface.DisconnectPeripheral(this.peripheralInfo, () => {
//App.MainDeviceAdapter.PrintStatus();
@@ -136,7 +136,7 @@ namespace Assets.Scripts.Devices.Ble
- private void ServicesDiscoveredAction(BleWinHwInterface hwInterface, BlePeripheralInfo sender, BleResponse> response)
+ private void ServicesDiscoveredAction(IBleWinHwInterface hwInterface, BlePeripheralInfo sender, BleResponse> response)
{
//Debug.Log("搜索service");
if(!response.IsSuccess || !response.Data.Any())
@@ -211,7 +211,7 @@ namespace Assets.Scripts.Devices.Ble
{
}
- private void BluetoothStateChangedEvent(BleWinHwInterface hwInterface, BleState state)
+ private void BluetoothStateChangedEvent(IBleWinHwInterface hwInterface, BleState state)
{
switch (state)
{
diff --git a/Assets/Scripts/Devices/Ble/BleDeviceAdapter.cs b/Assets/Scripts/Devices/Ble/BleDeviceAdapter.cs
index 823b439b..b32faaae 100644
--- a/Assets/Scripts/Devices/Ble/BleDeviceAdapter.cs
+++ b/Assets/Scripts/Devices/Ble/BleDeviceAdapter.cs
@@ -1,6 +1,7 @@
using Assets.Scripts.Ble;
using Assets.Scripts.Ble.Service;
using Assets.Scripts.Devices.Ble.Devices;
+using Assets.Scripts.Devices.Ble.Interfaces;
using Assets.Scripts.UI.Prefab.Device;
using System;
using System.Collections.Generic;
@@ -17,15 +18,16 @@ namespace Assets.Scripts.Devices.Ble
private IDictionary discoveredDevices = new Dictionary();
- private BleWinHwInterface hwInterface;
- public BleDeviceAdapter()
+ private IBleWinHwInterface hwInterface { get; set; }
+ public BleDeviceAdapter(IBleWinHwInterface bleWinHwInterface)
{
- hwInterface = BleWinHwInterface.GetInterface();
+
+ hwInterface = bleWinHwInterface;// BleWinHwInterface.GetInterface();
hwInterface.BluetoothStateChangedEvent += HwInterface_BluetoothStateChangedEvent;
}
- private void HwInterface_BluetoothStateChangedEvent(BleWinHwInterface hwInterface, BleState bleState)
+ private void HwInterface_BluetoothStateChangedEvent(IBleWinHwInterface hwInterface, BleState bleState)
{
//Debug.Log("22222222222222" + bleState);
if(bleState == BleState.Off)
diff --git a/Assets/Scripts/Devices/Ble/BleResponse.cs b/Assets/Scripts/Devices/Ble/BleResponse.cs
index 0c15559d..707278a9 100644
--- a/Assets/Scripts/Devices/Ble/BleResponse.cs
+++ b/Assets/Scripts/Devices/Ble/BleResponse.cs
@@ -37,5 +37,10 @@ namespace Assets.Scripts.Devices.Ble
{
return base.ToString() + "\n" + this.Data;
}
- }
+
+ public static implicit operator BleResponse(BleResponse> v)
+ {
+ throw new NotImplementedException();
+ }
+ }
}
diff --git a/Assets/Scripts/Devices/Ble/BluetoothStateChangedCallback.cs b/Assets/Scripts/Devices/Ble/BluetoothStateChangedCallback.cs
index c8fd1484..7a038776 100644
--- a/Assets/Scripts/Devices/Ble/BluetoothStateChangedCallback.cs
+++ b/Assets/Scripts/Devices/Ble/BluetoothStateChangedCallback.cs
@@ -1,4 +1,5 @@
-using System;
+using Assets.Scripts.Devices.Ble.Interfaces;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,6 +7,6 @@ using System.Threading.Tasks;
namespace Assets.Scripts.Ble
{
- public delegate void BluetoothStateChangedCallback(BleWinHwInterface hwInterface, BleState bleState);
+ public delegate void BluetoothStateChangedCallback(IBleWinHwInterface hwInterface, BleState bleState);
}
diff --git a/Assets/Scripts/Devices/Ble/CharacteristicReadCallback.cs b/Assets/Scripts/Devices/Ble/CharacteristicReadCallback.cs
index 9328c12a..b81a34fe 100644
--- a/Assets/Scripts/Devices/Ble/CharacteristicReadCallback.cs
+++ b/Assets/Scripts/Devices/Ble/CharacteristicReadCallback.cs
@@ -1,4 +1,5 @@
using Assets.Scripts.Devices.Ble;
+using Assets.Scripts.Devices.Ble.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -7,5 +8,5 @@ using System.Threading.Tasks;
namespace Assets.Scripts.Ble
{
- public delegate void CharacteristicReadCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response);
+ public delegate void CharacteristicReadCallback(IBleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response);
}
diff --git a/Assets/Scripts/Devices/Ble/CharacteristicsDiscoveredCallback.cs b/Assets/Scripts/Devices/Ble/CharacteristicsDiscoveredCallback.cs
index d3fab0e7..d32563d2 100644
--- a/Assets/Scripts/Devices/Ble/CharacteristicsDiscoveredCallback.cs
+++ b/Assets/Scripts/Devices/Ble/CharacteristicsDiscoveredCallback.cs
@@ -1,4 +1,5 @@
using Assets.Scripts.Devices.Ble;
+using Assets.Scripts.Devices.Ble.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -7,5 +8,5 @@ using System.Threading.Tasks;
namespace Assets.Scripts.Ble
{
- public delegate void CharacteristicsDiscoveredCallback(BleWinHwInterface hwInterface, BleServiceInfo service, BleResponse> response);
+ public delegate void CharacteristicsDiscoveredCallback(IBleWinHwInterface hwInterface, BleServiceInfo service, BleResponse> response);
}
diff --git a/Assets/Scripts/Devices/Ble/Devices/CyclingPower.cs b/Assets/Scripts/Devices/Ble/Devices/CyclingPower.cs
index 23bbca0b..097080b8 100644
--- a/Assets/Scripts/Devices/Ble/Devices/CyclingPower.cs
+++ b/Assets/Scripts/Devices/Ble/Devices/CyclingPower.cs
@@ -1,6 +1,7 @@
using Assets.Scripts.Ble;
using Assets.Scripts.Devices.Ant.Interfaces;
using Assets.Scripts.Devices.Ble.Characteristic;
+using Assets.Scripts.Devices.Ble.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -14,7 +15,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
{
private List Services;
private CyclingPowerMeasurement cyclingPowerMeasurement;
- public CyclingPower(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Power)
+ public CyclingPower(BlePeripheralInfo peripheralInfo, IBleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Power)
{
Priority = 2;
cyclingPowerMeasurement = new CyclingPowerMeasurement(1920);
@@ -49,7 +50,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
}
- private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
+ private void CharacteristicReadMainCallback(IBleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
{
//Debug.Log("power main call" + string.Join(",", response.Data));
diff --git a/Assets/Scripts/Devices/Ble/Devices/Ftms.cs b/Assets/Scripts/Devices/Ble/Devices/Ftms.cs
index 5cc33535..1fb5db56 100644
--- a/Assets/Scripts/Devices/Ble/Devices/Ftms.cs
+++ b/Assets/Scripts/Devices/Ble/Devices/Ftms.cs
@@ -1,6 +1,7 @@
using Assets.Scripts.Ble;
using Assets.Scripts.Devices.Ant.Interfaces;
using Assets.Scripts.Devices.Ble.Characteristic;
+using Assets.Scripts.Devices.Ble.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -21,7 +22,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
private List Services;
private BleCharacteristicInfo controlPointCharacteristic;
- public Ftms(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) :base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Trainer)
+ public Ftms(BlePeripheralInfo peripheralInfo, IBleWinHwInterface bleWinHwInterface) :base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Trainer)
{
this._ftmsIndoorBikeData = new FtmsIndoorBikeData();
base.Characteristics.Add(this._ftmsIndoorBikeData);
@@ -60,7 +61,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
}
}
- private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
+ private void CharacteristicReadMainCallback(IBleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
{
foreach (var item in base.Characteristics)
{
diff --git a/Assets/Scripts/Devices/Ble/Devices/HeartRate.cs b/Assets/Scripts/Devices/Ble/Devices/HeartRate.cs
index c84781d1..5ce8abf3 100644
--- a/Assets/Scripts/Devices/Ble/Devices/HeartRate.cs
+++ b/Assets/Scripts/Devices/Ble/Devices/HeartRate.cs
@@ -1,6 +1,7 @@
using Assets.Scripts.Ble;
using Assets.Scripts.Devices.Ant.Interfaces;
using Assets.Scripts.Devices.Ble.Characteristic;
+using Assets.Scripts.Devices.Ble.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -16,7 +17,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
private List Services;
private HeartRateMeasurement heartRateMeasurement;
- public HeartRate(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.HeartRate)
+ public HeartRate(BlePeripheralInfo peripheralInfo, IBleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.HeartRate)
{
Priority = 2;
heartRateMeasurement = new HeartRateMeasurement();
@@ -73,7 +74,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
});
}
- private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
+ private void CharacteristicReadMainCallback(IBleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
{
//Debug.Log("heart rate main call" + string.Join(",", response.Data));
diff --git a/Assets/Scripts/Devices/Ble/Devices/SpeedCadence.cs b/Assets/Scripts/Devices/Ble/Devices/SpeedCadence.cs
index 504a4fd0..281d4546 100644
--- a/Assets/Scripts/Devices/Ble/Devices/SpeedCadence.cs
+++ b/Assets/Scripts/Devices/Ble/Devices/SpeedCadence.cs
@@ -1,6 +1,7 @@
using Assets.Scripts.Ble;
using Assets.Scripts.Devices.Ant.Interfaces;
using Assets.Scripts.Devices.Ble.Characteristic;
+using Assets.Scripts.Devices.Ble.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -18,7 +19,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
private double _wheelCircumference;
private List Services;
- public SpeedCadence(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.SpeedCadence)
+ public SpeedCadence(BlePeripheralInfo peripheralInfo, IBleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.SpeedCadence)
{
Debug.Log("创建速度踏频设备");
Priority = 1;
@@ -81,7 +82,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
}
- private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
+ private void CharacteristicReadMainCallback(IBleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
{
//Debug.Log("power main call" + string.Join(",", response.Data));
diff --git a/Assets/Scripts/Devices/Ble/Devices/Tacx.cs b/Assets/Scripts/Devices/Ble/Devices/Tacx.cs
index 39333b15..5c6c1e94 100644
--- a/Assets/Scripts/Devices/Ble/Devices/Tacx.cs
+++ b/Assets/Scripts/Devices/Ble/Devices/Tacx.cs
@@ -2,6 +2,7 @@
using Assets.Scripts.Devices.Ant;
using Assets.Scripts.Devices.Ant.Interfaces;
using Assets.Scripts.Devices.Ble.Characteristic;
+using Assets.Scripts.Devices.Ble.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -30,7 +31,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
///
private double _grade = 0;
- public Tacx(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Trainer)
+ public Tacx(BlePeripheralInfo peripheralInfo, IBleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Trainer)
{
tacxFecNotify = new TacxFecNotify();
base.Characteristics.Add(tacxFecNotify);
@@ -75,7 +76,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
}
}
- private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
+ private void CharacteristicReadMainCallback(IBleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
{
foreach (var item in base.Characteristics)
{
diff --git a/Assets/Scripts/Devices/Ble/HeartRate/HeartRateService.cs b/Assets/Scripts/Devices/Ble/HeartRate/HeartRateService.cs
index dc9f5fef..00bb791b 100644
--- a/Assets/Scripts/Devices/Ble/HeartRate/HeartRateService.cs
+++ b/Assets/Scripts/Devices/Ble/HeartRate/HeartRateService.cs
@@ -2,6 +2,7 @@
using Assets.Scripts.Ble.Service;
using Assets.Scripts.Commands;
using Assets.Scripts.Devices.Ble;
+using Assets.Scripts.Devices.Ble.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -36,12 +37,12 @@ namespace Assets.Scripts.Ble.HeartRate
}
}
- private void HrmCharacteristicSubscribed(BleWinHwInterface winHwInterface, BleCharacteristicInfo characteristic, BleResponse response)
+ private void HrmCharacteristicSubscribed(IBleWinHwInterface winHwInterface, BleCharacteristicInfo characteristic, BleResponse response)
{
}
- private void HrmCharacteristicRead(BleWinHwInterface winHwInterface, BleCharacteristicInfo characteristic, BleResponse response)
+ private void HrmCharacteristicRead(IBleWinHwInterface winHwInterface, BleCharacteristicInfo characteristic, BleResponse response)
{
HeartRateMeasurementValue heartRateMeasurementValue;
if(base.CheckCharacteristicResponse(characteristic, response, (BleCharacteristicInfo info, BleResponse bleResponse) => new HeartRateMeasurementValue(bleResponse.Data), out heartRateMeasurementValue) != CommandResponseCode.Success)
diff --git a/Assets/Scripts/Devices/Ble/Interfaces/IBleWinHwInterface.cs b/Assets/Scripts/Devices/Ble/Interfaces/IBleWinHwInterface.cs
new file mode 100644
index 00000000..dc500079
--- /dev/null
+++ b/Assets/Scripts/Devices/Ble/Interfaces/IBleWinHwInterface.cs
@@ -0,0 +1,28 @@
+using Assets.Scripts.Ble;
+using Assets.Scripts.Ble.Scan;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Assets.Scripts.Devices.Ble.Interfaces
+{
+ public interface IBleWinHwInterface
+ {
+ void StartScan(Action discoveredCallBack);
+ void ConnectPeripheral(BlePeripheralInfo info, Action callback);
+ void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback);
+ void DiscoverServices(BlePeripheralInfo peripheral, Action>> callback);
+ void DiscoverCharacteristic(BleServiceInfo service, CharacteristicsDiscoveredCallback callback);
+ void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action callback);
+ void WriteCharacteristic(BleCharacteristicInfo characteristic, byte[] data);
+ void ReadCharacteristic(BleCharacteristicInfo characteristic, CharacteristicReadCallback callback);
+ void Dispose();
+ BleState BleState { get; set; }
+ Dictionary pCache { get; set; }
+ event BluetoothStateChangedCallback BluetoothStateChangedEvent;
+ event CharacteristicReadCallback CharacteristicReadEvent;
+ event PeripheralDisconnectedCallback PeripheralDisconnectedEvent;
+ }
+}
diff --git a/Assets/Scripts/Devices/Ble/Interfaces/IBleWinHwInterface.cs.meta b/Assets/Scripts/Devices/Ble/Interfaces/IBleWinHwInterface.cs.meta
new file mode 100644
index 00000000..77926020
--- /dev/null
+++ b/Assets/Scripts/Devices/Ble/Interfaces/IBleWinHwInterface.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 86216427171ac784296ca577b921b2e7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Devices/Ble/PeripheralDisconnectedCallback.cs b/Assets/Scripts/Devices/Ble/PeripheralDisconnectedCallback.cs
index 3b24a05b..e6211017 100644
--- a/Assets/Scripts/Devices/Ble/PeripheralDisconnectedCallback.cs
+++ b/Assets/Scripts/Devices/Ble/PeripheralDisconnectedCallback.cs
@@ -1,4 +1,5 @@
using Assets.Scripts.Ble;
+using Assets.Scripts.Devices.Ble.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -7,5 +8,5 @@ using System.Threading.Tasks;
namespace Assets.Scripts.Devices.Ble
{
- public delegate void PeripheralDisconnectedCallback(BleWinHwInterface hwInterface, BlePeripheralInfo peripheral, BleResponse response, bool manualDisconnect);
+ public delegate void PeripheralDisconnectedCallback(IBleWinHwInterface hwInterface, BlePeripheralInfo peripheral, BleResponse response, bool manualDisconnect);
}
diff --git a/Assets/Scripts/Devices/Ble/Service/BleService.cs b/Assets/Scripts/Devices/Ble/Service/BleService.cs
index 40a0f123..b8679d82 100644
--- a/Assets/Scripts/Devices/Ble/Service/BleService.cs
+++ b/Assets/Scripts/Devices/Ble/Service/BleService.cs
@@ -8,6 +8,7 @@ using Assets.Scripts.Ble.Commands;
using Assets.Scripts.Commands;
using Assets.Scripts.Devices.Ble;
using Assets.Scripts.Devices.Ble.Extension;
+using Assets.Scripts.Devices.Ble.Interfaces;
using UnityEngine;
namespace Assets.Scripts.Ble.Service
@@ -18,7 +19,7 @@ namespace Assets.Scripts.Ble.Service
private BleServiceInfo serviceInfo;
private List characteristics;
- private readonly Dictionary>> registeredCharacteristicReadEvents = new Dictionary>>();
+ private readonly Dictionary>> registeredCharacteristicReadEvents = new Dictionary>>();
public IReadOnlyList Characteristics
{
@@ -58,7 +59,7 @@ namespace Assets.Scripts.Ble.Service
this.hwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
}
- private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
+ private void CharacteristicReadMainCallback(IBleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse response)
{
//Debug.Log("read main callback");
if (this.registeredCharacteristicReadEvents.ContainsKey(characteristic.Id) && characteristic.Service.Equals(this.serviceInfo))
@@ -79,7 +80,7 @@ namespace Assets.Scripts.Ble.Service
this.CheckCharacteristicDiscoveredResponse(this.hwInterface, this.serviceInfo, scanCharacteristicsResponse);
}
- private void CheckCharacteristicDiscoveredResponse(BleWinHwInterface hwInterface, BleServiceInfo service, BleResponse> response)
+ private void CheckCharacteristicDiscoveredResponse(IBleWinHwInterface hwInterface, BleServiceInfo service, BleResponse> response)
{
if (!service.Equals(this.serviceInfo))
{
@@ -98,8 +99,8 @@ namespace Assets.Scripts.Ble.Service
protected abstract void CharacteristicsDiscovered(BleResponse> response);
- protected void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action notificationCallback,
- Action> readCallback)
+ protected void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action notificationCallback,
+ Action> readCallback)
{
this.hwInterface.SubscribeCharacteristic(characteristic, (hw, info, response) =>
{
diff --git a/Assets/Scripts/Devices/Ble/Win/BleWinHwInterface.cs b/Assets/Scripts/Devices/Ble/Win/BleWinHwInterface.cs
index 96576511..794db60f 100644
--- a/Assets/Scripts/Devices/Ble/Win/BleWinHwInterface.cs
+++ b/Assets/Scripts/Devices/Ble/Win/BleWinHwInterface.cs
@@ -2,6 +2,7 @@
using Assets.Scripts.Ble.Win;
using Assets.Scripts.Devices.Ant;
using Assets.Scripts.Devices.Ble;
+using Assets.Scripts.Devices.Ble.Interfaces;
using Assets.Scripts.Devices.Ble.Win;
using System;
using System.Collections.Generic;
@@ -12,13 +13,24 @@ using UnityEngine;
namespace Assets.Scripts.Ble
{
- public sealed class BleWinHwInterface
+ public sealed class BleWinHwInterface: IBleWinHwInterface
{
private static BleWinHwInterface hwInterface;
private WclBleMainThread wclBleMainThread;
- public readonly Dictionary pCache = new Dictionary();
-
+ private Dictionary _pCache;
+ public Dictionary pCache
+ {
+ get
+ {
+ if (_pCache == null)
+ {
+ _pCache = new Dictionary();
+ }
+ return _pCache;
+ }
+ set { _pCache = value; }
+ }
private Action _discoveredCallback;
private Dictionary> callbacks = new Dictionary>();
@@ -43,6 +55,7 @@ namespace Assets.Scripts.Ble
}
}
+
private BluetoothStateChangedCallback bluetoothStateChanged;
public event BluetoothStateChangedCallback BluetoothStateChangedEvent
{
@@ -55,7 +68,7 @@ namespace Assets.Scripts.Ble
this.bluetoothStateChanged -= value;
}
}
-
+
private BleState nativeState;
public BleState BleState
{
@@ -63,7 +76,7 @@ namespace Assets.Scripts.Ble
{
return this.nativeState;
}
- private set
+ set
{
if(this.nativeState != value)
{
@@ -201,7 +214,7 @@ namespace Assets.Scripts.Ble
return wclBleGattThread;
}
- internal void ConnectPeripheral(BlePeripheralInfo info, Action callback)
+ public void ConnectPeripheral(BlePeripheralInfo info, Action callback)
{
this.callbacks.Add(info, callback);
WclBleGattThread wclBleGattThread = this.wclBleMainThread.GetGattThread(info);
@@ -229,8 +242,8 @@ namespace Assets.Scripts.Ble
//});
}
-
- internal void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback)
+
+ public void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback)
{
var gattThread = this.wclBleMainThread.GetGattThread(peripheral);
if(gattThread != null && gattThread.CanLoadWork)
@@ -372,7 +385,7 @@ namespace Assets.Scripts.Ble
}
}
- public void DiscoverServices(BlePeripheralInfo peripheral, Action>> callback)
+ public void DiscoverServices(BlePeripheralInfo peripheral, Action>> callback)
{
WclBleGattThread gattThread = this.wclBleMainThread.GetGattThread(peripheral);
if(gattThread == null)
@@ -420,7 +433,7 @@ namespace Assets.Scripts.Ble
this.GattCharacteristicsDiscovered(gattThread, service, response);
}
- public void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action callback)
+ public void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action callback)
{
WclBleGattThread gattThread = this.wclBleMainThread.GetGattThread(characteristic.Peripheral);
diff --git a/Assets/Scripts/Devices/Ble/mobile.meta b/Assets/Scripts/Devices/Ble/mobile.meta
new file mode 100644
index 00000000..95152633
--- /dev/null
+++ b/Assets/Scripts/Devices/Ble/mobile.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9fa2f8906f5360c47b807eaef8d42263
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Devices/Ble/mobile/BleMobileInterface.cs b/Assets/Scripts/Devices/Ble/mobile/BleMobileInterface.cs
new file mode 100644
index 00000000..b18fa19f
--- /dev/null
+++ b/Assets/Scripts/Devices/Ble/mobile/BleMobileInterface.cs
@@ -0,0 +1,399 @@
+using Assets.Scripts.Ble.Scan;
+using Assets.Scripts.Ble.Win;
+using Assets.Scripts.Devices.Ant;
+using Assets.Scripts.Devices.Ble;
+using Assets.Scripts.Devices.Ble.Interfaces;
+using Assets.Scripts.Devices.Ble.Win;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+
+namespace Assets.Scripts.Ble
+{
+ public sealed class BleMobileInterface : IBleWinHwInterface
+ {
+ private static BleMobileInterface hwInterface;
+ private BleMobileThread bleMobileThread;
+
+ private Dictionary _pCache;
+ public Dictionary pCache
+ {
+ get
+ {
+ if (_pCache == null)
+ {
+ _pCache = new Dictionary();
+ }
+ return _pCache;
+ }
+ set { _pCache = value; }
+ }
+ private Action _discoveredCallback;
+
+ private Dictionary> callbacks = new Dictionary>();
+ private Dictionary>>> servicesCallbacks = new Dictionary>>>();
+ //private Dictionary>>> characteristicsCallbacks = new Dictionary>>>();
+ private Dictionary> characteristicNotificationCallbacks = new Dictionary>();
+ private Dictionary characteristicReadCallbacks = new Dictionary();
+ private Dictionary characteristicsDiscoveredCallbacks = new Dictionary();
+
+ private Dictionary disconnectedCallback = new Dictionary();
+
+ private CharacteristicReadCallback characteristicReadEvent;
+ public event CharacteristicReadCallback CharacteristicReadEvent
+ {
+ add
+ {
+ this.characteristicReadEvent += value;
+ }
+ remove
+ {
+ this.characteristicReadEvent -= value;
+ }
+ }
+
+
+ private BluetoothStateChangedCallback bluetoothStateChanged;
+ public event BluetoothStateChangedCallback BluetoothStateChangedEvent
+ {
+ add
+ {
+ this.bluetoothStateChanged += value;
+ }
+ remove
+ {
+ this.bluetoothStateChanged -= value;
+ }
+ }
+
+ private BleState nativeState;
+ public BleState BleState
+ {
+ get
+ {
+ return this.nativeState;
+ }
+ set
+ {
+ if (this.nativeState != value)
+ {
+ this.nativeState = value;
+ this.bluetoothStateChanged?.Invoke(this, this.nativeState);
+ }
+ }
+ }
+
+ private PeripheralDisconnectedCallback peripheralDisconnectedEvent;
+ public event PeripheralDisconnectedCallback PeripheralDisconnectedEvent
+ {
+ add
+ {
+ this.peripheralDisconnectedEvent += value;
+ }
+ remove
+ {
+ this.peripheralDisconnectedEvent -= value;
+ }
+ }
+
+ private BleMobileInterface()
+ {
+ bleMobileThread = new BleMobileThread();
+ bleMobileThread.ManagerInitialized += BleMobileThread_ManagerInitialized;
+ bleMobileThread.ManagerStatusChanged += ManagerStatusChanged;
+ bleMobileThread.ScanInfoReceived += WatcherScanInfoReceived;
+ }
+
+ private void BleMobileThread_ManagerInitialized(BleMobileThread thread)
+ {
+ this.BleState = BleState.On;
+ }
+
+ private void ManagerStatusChanged(BleMobileThread sender, WclBleManagerStatus status)
+ {
+ this.BleState = BleMobileInterface.StateFromNativeState(status);
+ }
+
+ private void WatcherScanInfoReceived(BleMobileThread sender, string address, string name, int rssi,string[] uuids)
+ {
+ SensorType sensor = SensorType.None;
+ List services = new List();
+
+ if (uuids != null && uuids.Length > 0)
+ {
+ foreach (var item in uuids)
+ {
+ services.Add(new Guid(item));
+ }
+ foreach (var item in ServiceUuids.Services)
+ {
+ if (!uuids.Contains(item.IdGuid.ToString()))
+ {
+ continue;
+ }
+ if (item.IdByteArray == ServiceUuids.Ftms)
+ {
+ sensor = SensorType.Trainer;
+ }
+ else if (item.IdByteArray == ServiceUuids.HeartRate)
+ {
+ sensor = SensorType.HeartRate;
+ }
+ else if (item.IdByteArray == ServiceUuids.CyclingPower)
+ {
+ sensor = SensorType.Power;
+ //sensor = SensorType.Trainer;
+ }
+ else if (item.IdByteArray == ServiceUuids.CyclingSpeedCadence)
+ {
+ sensor = SensorType.SpeedCadence;
+ }
+ else if (item.IdByteArray == ServiceUuids.TacxBle)
+ {
+ sensor = SensorType.Trainer;
+ }
+ }
+ };
+
+ var addressStr = address;
+ if (!pCache.ContainsKey(addressStr))
+ {
+ var device = new BleAdvertisementInfo(new WinBlePeripheralInfo(addressStr, name), rssi, true, services, null, sensor);
+ pCache.Add(addressStr, device);
+ }
+ if (!string.IsNullOrWhiteSpace(name))
+ {
+ (pCache[addressStr].Peripheral as WinBlePeripheralInfo).SetName(name);
+ }
+ if (sensor == SensorType.None)
+ {
+ return;
+ }
+ pCache[addressStr].SensorType = sensor;
+ pCache[addressStr].Rssi = rssi;
+ //Debug.Log(sensor);
+ //pCache[address.ToString()].SensorType = sensor;
+
+ foreach (var item in uuids)
+ {
+ pCache[addressStr].TryAddService(new Guid(item));
+ }
+
+ pCache[addressStr].Index++;
+ if (pCache[addressStr].SensorType == SensorType.Power && pCache[addressStr].Services.Any(s => s.Equals(ServiceUuids.Get(ServiceUuids.TacxBle).IdGuid)))
+ {
+ pCache[addressStr].SensorType = SensorType.Trainer;
+ //Debug.Log("纠正为trainer, "+ pCache[address.ToString()].Index);
+ }
+
+
+ if (pCache[addressStr].SensorType == SensorType.Power)
+ {
+ if (pCache[addressStr].Index > 4)
+ {
+ _discoveredCallback?.Invoke(pCache[addressStr]);
+ }
+ }
+ else if (pCache[addressStr].SensorType != SensorType.None)
+ {
+ _discoveredCallback?.Invoke(pCache[addressStr]);
+ }
+ }
+
+ //private WclBleGattThread SetUpGattClient(BlePeripheralInfo peripheral)
+ //{
+ // WclBleGattThread wclBleGattThread = this.wclBleMainThread.CreateGattThread(peripheral);
+ // wclBleGattThread.GattConnected += this.GattConnected;
+ // wclBleGattThread.GattDisconnected += this.GattDisconnected;
+ // wclBleGattThread.GattServicesDiscovered += this.GattServicesDiscovered;
+ // wclBleGattThread.GattCharacteristicsDiscovered += this.GattCharacteristicsDiscovered;
+ // wclBleGattThread.GattCharacteristicSubscribed += this.GattCharacteristicSubscribed;
+ // wclBleGattThread.GattCharacteristicRead += this.GattCharacteristicRead;
+ // wclBleGattThread.GattCharacteristicWrote += this.GattCharacteristicWrote;
+ // wclBleGattThread.GattCharacteristicChanged += this.GattCharacteristicChanged;
+ // wclBleGattThread.Start();
+ // return wclBleGattThread;
+ //}
+
+ List servicelist = new List();
+ List characteristilist = new List();
+ public void ConnectPeripheral(BlePeripheralInfo info, Action callback)
+ {
+ BleResponse s = new BleResponse();
+ s.IsSuccess = true;
+ s.Error = null;
+ var self = this;
+ BluetoothLEHardwareInterface.ConnectToPeripheral(info.Address, (address) =>
+ {
+ callback?.Invoke(self, info, s);
+ }, (address, service) => {
+ if (servicesCallbacks.Where(c => c.Key.Address == address).Any())
+ {
+
+ var serviceCallback = servicesCallbacks.Where(c => c.Key.Address == address).FirstOrDefault();
+ List servicelist = new List();
+ servicelist.Add(new WinBleServiceInfo(serviceCallback.Key,new Guid(service)));
+ BleResponse> response = new BleResponse>
+ {
+ IsSuccess = true,
+ Error = null,
+ Data = servicelist,
+ };
+ serviceCallback.Value?.Invoke(this, serviceCallback.Key, response);
+ }
+
+ }, (address, service, characteristic) =>
+ {
+ if (characteristicsDiscoveredCallbacks.Where(c => c.Key.Peripheral.Address == address).Any())
+ {
+ var characteristicCallback = characteristicsDiscoveredCallbacks.Where(c => c.Key.Peripheral.Address == address).FirstOrDefault();
+ List characteristiclist = new List();
+ characteristiclist.Add(new WinBleCharacteristicInfo(new Guid(characteristic), new WinBleServiceInfo(characteristicCallback.Key.Peripheral, new Guid(service)),0));
+ BleResponse> response = new BleResponse>
+ {
+ IsSuccess = true,
+ Error = null,
+ Data = characteristiclist,
+ };
+ characteristicCallback.Value?.Invoke(this, characteristicCallback.Key, response);
+ }
+ }, null);
+ }
+
+ //设备断开连接
+ public void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback)
+ {
+ BluetoothLEHardwareInterface.DisconnectPeripheral(peripheral.Address, (address) =>
+ {
+ //peripheralDisconnectedEvent(this, peripheral, null, true);
+ callback?.Invoke();
+ });
+ }
+
+ public static BleMobileInterface GetInterface()
+ {
+ if(hwInterface == null)
+ {
+ hwInterface = new BleMobileInterface();
+ }
+
+ return hwInterface;
+ }
+ //扫描设备
+ public void StartScan(Action discoveredCallBack)
+ {
+ pCache.Clear();
+ _discoveredCallback = discoveredCallBack;
+ bleMobileThread.StartWatcher();
+ }
+ //发现服务列表
+ public void DiscoverServices(BlePeripheralInfo peripheral, Action>> callback)
+ {
+ this.servicesCallbacks.Add(peripheral, callback);
+ }
+ //发现特征值
+ public void DiscoverCharacteristic(BleServiceInfo service, CharacteristicsDiscoveredCallback callback)
+ {
+ this.characteristicsDiscoveredCallbacks.Add(service, callback);
+ }
+ //订阅特征值
+ public void SubscribeCharacteristic(BleCharacteristicInfo characteristic, Action callback)
+ {
+ this.characteristicNotificationCallbacks.Add(characteristic.Peripheral, callback);
+ BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress(characteristic.Peripheral.Address, characteristic.Service.ToString(), characteristic.Id.ToString(), null, (deviceAddress, characteristric, bytes) =>
+ {
+ if (characteristicReadEvent != null)
+ {
+ BleResponse response = new BleResponse
+ {
+ IsSuccess = true,
+ Error = null,
+ Data = bytes,
+ };
+ characteristicReadEvent.Invoke(this, characteristic, response);
+ }
+ });
+ }
+ //写入特征值
+ public void WriteCharacteristic(BleCharacteristicInfo characteristic, byte[] data)
+ {
+ BluetoothLEHardwareInterface.WriteCharacteristic(characteristic.Peripheral.Address, characteristic.Service.Id.ToString(), characteristic.Id.ToString(), data, data.Length, false, (characteristicUUID) => {
+
+ BluetoothLEHardwareInterface.Log("Write Succeeded");
+ });
+ }
+
+
+ public void Dispose()
+ {
+ bleMobileThread.ManagerInitialized -= BleMobileThread_ManagerInitialized;
+ bleMobileThread.ManagerStatusChanged -= ManagerStatusChanged;
+ bleMobileThread.ScanInfoReceived -= WatcherScanInfoReceived;
+ bleMobileThread.Stop();
+ bleMobileThread = null;
+ hwInterface = null;
+ pCache.Clear();
+ }
+
+ public void ReadCharacteristic(BleCharacteristicInfo characteristic, CharacteristicReadCallback callback)
+ {
+ BluetoothLEHardwareInterface.ReadCharacteristic(characteristic.Peripheral.Address, characteristic.Service.Id.ToString(), characteristic.Id.ToString(), (c, bytes) => {
+ BleResponse response = new BleResponse
+ {
+ IsSuccess = true,
+ Error = null,
+ Data = bytes,
+ };
+ callback?.Invoke(this, characteristic, response);
+ });
+ }
+
+ private static BleState StateFromNativeState(WclBleManagerStatus status)
+ {
+ switch (status)
+ {
+ case WclBleManagerStatus.RadioOff:
+ return BleState.Off;
+ case WclBleManagerStatus.RadioOn:
+ return BleState.On;
+ case WclBleManagerStatus.Unknown:
+ return BleState.Unknown;
+ default:
+ return BleState.Unavailable;
+ }
+ }
+
+ private class WinBlePeripheralInfo : BlePeripheralInfo
+ {
+ // Token: 0x06003F35 RID: 16181 RVA: 0x000E9FBF File Offset: 0x000E81BF
+ public WinBlePeripheralInfo(string address, string name) : base(address, name)
+ {
+ }
+
+ // Token: 0x06003F36 RID: 16182 RVA: 0x000E9FC9 File Offset: 0x000E81C9
+ public void SetName(string name)
+ {
+ base.Name = name;
+ }
+ }
+
+ private class WinBleServiceInfo : BleServiceInfo
+ {
+ // Token: 0x06003F86 RID: 16262 RVA: 0x000EA27F File Offset: 0x000E847F
+ public WinBleServiceInfo(BlePeripheralInfo peripheral, Guid id) : base(id, peripheral)
+ {
+ }
+ }
+ private class WinBleCharacteristicInfo : BleCharacteristicInfo
+ {
+ // Token: 0x06003F86 RID: 16262 RVA: 0x000EA27F File Offset: 0x000E847F
+ public WinBleCharacteristicInfo(Guid id, BleServiceInfo service, BleCharacteristicProperties properties) : base(id,service, properties)
+ {
+
+ }
+ }
+ }
+}
diff --git a/Assets/Scripts/Devices/Ble/mobile/BleMobileInterface.cs.meta b/Assets/Scripts/Devices/Ble/mobile/BleMobileInterface.cs.meta
new file mode 100644
index 00000000..f9174596
--- /dev/null
+++ b/Assets/Scripts/Devices/Ble/mobile/BleMobileInterface.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2e5257ea169e69a498a3e4d935a51306
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Devices/Ble/mobile/BleMobileThread.cs b/Assets/Scripts/Devices/Ble/mobile/BleMobileThread.cs
new file mode 100644
index 00000000..a9db13d0
--- /dev/null
+++ b/Assets/Scripts/Devices/Ble/mobile/BleMobileThread.cs
@@ -0,0 +1,80 @@
+using Assets.Scripts.Ble;
+using System.Timers;
+
+namespace Assets.Scripts.Devices.Ble
+{
+ internal class BleMobileThread
+ {
+ public delegate void WclInitializedDelegate(BleMobileThread sender);
+ private BleMobileThread.WclInitializedDelegate managerInitialized;
+ public event BleMobileThread.WclInitializedDelegate ManagerInitialized
+ {
+ add
+ {
+ this.managerInitialized += value;
+ }
+ remove
+ {
+ this.managerInitialized -= value;
+ }
+ }
+
+ public delegate void WclAdvertisementPacketDelegate(BleMobileThread sender, string address, string name, int rssi, string[] uuids);
+ public BleMobileThread.WclAdvertisementPacketDelegate ScanInfoReceived;
+
+ internal delegate void ManagerStatusChangedCallback(BleMobileThread thread, WclBleManagerStatus status);
+ private BleMobileThread.ManagerStatusChangedCallback managerStatusChanged;
+ public event BleMobileThread.ManagerStatusChangedCallback ManagerStatusChanged
+ {
+ add
+ {
+ this.managerStatusChanged += value;
+ }
+ remove
+ {
+ this.managerStatusChanged -= value;
+ }
+ }
+
+ internal BleMobileThread() {
+ var self = this;
+ //初始蓝牙
+ BluetoothLEHardwareInterface.Initialize(true, false, () => {
+ managerInitialized?.Invoke(self);
+ },
+ (error) => {
+ BluetoothLEHardwareInterface.Log("Error: " + error);
+ if (error.Contains("Bluetooth LE Not Enabled"))
+ BluetoothLEHardwareInterface.BluetoothEnable(true);
+ }, (status) => {
+
+ var statusEnum = WclBleManagerStatus.RadioOn;
+ switch (status)
+ {
+ case 13:
+ statusEnum = WclBleManagerStatus.RadioOff;
+ break;
+ case 11:
+ statusEnum = WclBleManagerStatus.RadioOn;
+ break;
+ }
+ if (managerStatusChanged != null)
+ {
+ managerStatusChanged.Invoke(self, statusEnum);
+ }
+ });
+ }
+
+ public void StartWatcher() {
+ BluetoothLEHardwareInterface.ScanForPeripheralsWithServices(null, null, (address, name, rssi, bytes) =>
+ {
+ ScanInfoReceived?.Invoke(this, address, name, rssi, bytes);
+ }, true);
+ }
+
+ public void Stop()
+ {
+ BluetoothLEHardwareInterface.StopScan();
+ }
+ }
+}
diff --git a/Assets/Scripts/Devices/Ble/mobile/BleMobileThread.cs.meta b/Assets/Scripts/Devices/Ble/mobile/BleMobileThread.cs.meta
new file mode 100644
index 00000000..aaa1a572
--- /dev/null
+++ b/Assets/Scripts/Devices/Ble/mobile/BleMobileThread.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cec5e50ac67fde54196ea58f5b1b790b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/Devices/MainDeviceAdapter.cs b/Assets/Scripts/Devices/MainDeviceAdapter.cs
index 3e50f026..a5f84d70 100644
--- a/Assets/Scripts/Devices/MainDeviceAdapter.cs
+++ b/Assets/Scripts/Devices/MainDeviceAdapter.cs
@@ -1,4 +1,5 @@
-using Assets.Scripts.Devices.Ant;
+using Assets.Scripts.Ble;
+using Assets.Scripts.Devices.Ant;
using Assets.Scripts.Devices.Ble;
using System;
using System.Collections.Generic;
@@ -14,10 +15,12 @@ namespace Assets.Scripts.Devices
private List adapters = new List();
public MainDeviceAdapter()
{
- #if !(UNITY_IOS || UNITY_ANDROID)
- this.CreateAntAdapter();
+#if UNITY_IOS || UNITY_TVOS || UNITY_ANDROID
this.CreateBleAdapter();
- #endif
+#else
+ this.CreateBleAdapter();
+ this.CreateAntAdapter();
+#endif
}
private void CreateAntAdapter()
@@ -27,7 +30,11 @@ namespace Assets.Scripts.Devices
private void CreateBleAdapter()
{
- adapters.Add(new BleDeviceAdapter());
+#if UNITY_IOS || UNITY_TVOS || UNITY_ANDROID
+ adapters.Add(new BleDeviceAdapter(BleMobileInterface.GetInterface()));
+#else
+ adapters.Add(new BleDeviceAdapter(BleWinHwInterface.GetInterface()));
+#endif
}
public void StartScan()
diff --git a/Assets/Scripts/Scenes/LoginController.cs b/Assets/Scripts/Scenes/LoginController.cs
index 6b7db09d..1294ceb8 100644
--- a/Assets/Scripts/Scenes/LoginController.cs
+++ b/Assets/Scripts/Scenes/LoginController.cs
@@ -330,6 +330,7 @@ public class LoginController : MonoBehaviour
{
wxReturnLogin();
});
+ #if !(UNITY_IOS || UNITY_ANDROID)
wxBrowser = wxLogin1.Find("Browser (GUI)").GetComponent();
if (wxBrowser != null)
{
@@ -941,7 +942,9 @@ public class LoginController : MonoBehaviour
void wxReturnLogin()
{
wxLock = true;
+#if !(UNITY_IOS || UNITY_ANDROID)
wxBrowser.LoadHTML("");
+#endif
//wxBrowser.Url = "chrome://version/";
wxLogin1.DOLocalMoveY(-573, 0.3f).onComplete = () =>
{
diff --git a/Assets/Scripts/Scenes/Ride/Scripts/PlayerController.cs b/Assets/Scripts/Scenes/Ride/Scripts/PlayerController.cs
index 94388d22..d342a727 100644
--- a/Assets/Scripts/Scenes/Ride/Scripts/PlayerController.cs
+++ b/Assets/Scripts/Scenes/Ride/Scripts/PlayerController.cs
@@ -56,7 +56,7 @@ namespace Assets.Scenes.Ride.Scripts
weight = App.CurrentUser.Weight;
bicycleWeight = App.CurrentUser.BicycleWeight;
//#if UNITY_EDITOR
- power = 500;
+ //power = 500;
//#endif
mainController.TrackResistance(currentSlope * App.RideSetting.Sensitivity / 100);
}
diff --git a/Assets/Shatalmic.meta b/Assets/Shatalmic.meta
new file mode 100644
index 00000000..22b01e25
--- /dev/null
+++ b/Assets/Shatalmic.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: fcef0f33b95c6fd4d9b2f5a0dcd0d564
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Shatalmic/Demo.unity b/Assets/Shatalmic/Demo.unity
new file mode 100644
index 00000000..87ccf60d
--- /dev/null
+++ b/Assets/Shatalmic/Demo.unity
@@ -0,0 +1,439 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_OcclusionBakeSettings:
+ smallestOccluder: 5
+ smallestHole: 0.25
+ backfaceThreshold: 100
+ m_SceneGUID: 00000000000000000000000000000000
+ m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 9
+ m_Fog: 0
+ m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+ m_FogMode: 3
+ m_FogDensity: 0.01
+ m_LinearFogStart: 0
+ m_LinearFogEnd: 300
+ m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+ m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+ m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+ m_AmbientIntensity: 1
+ m_AmbientMode: 3
+ m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+ m_SkyboxMaterial: {fileID: 0}
+ m_HaloStrength: 0.5
+ m_FlareStrength: 1
+ m_FlareFadeSpeed: 3
+ m_HaloTexture: {fileID: 0}
+ m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+ m_DefaultReflectionMode: 0
+ m_DefaultReflectionResolution: 128
+ m_ReflectionBounces: 1
+ m_ReflectionIntensity: 1
+ m_CustomReflection: {fileID: 0}
+ m_Sun: {fileID: 0}
+ m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
+ m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 11
+ m_GIWorkflowMode: 1
+ m_GISettings:
+ serializedVersion: 2
+ m_BounceScale: 1
+ m_IndirectOutputScale: 1
+ m_AlbedoBoost: 1
+ m_EnvironmentLightingMode: 0
+ m_EnableBakedLightmaps: 0
+ m_EnableRealtimeLightmaps: 0
+ m_LightmapEditorSettings:
+ serializedVersion: 10
+ m_Resolution: 2
+ m_BakeResolution: 40
+ m_AtlasSize: 1024
+ m_AO: 0
+ m_AOMaxDistance: 1
+ m_CompAOExponent: 1
+ m_CompAOExponentDirect: 0
+ m_Padding: 2
+ m_LightmapParameters: {fileID: 0}
+ m_LightmapsBakeMode: 1
+ m_TextureCompression: 1
+ m_FinalGather: 0
+ m_FinalGatherFiltering: 1
+ m_FinalGatherRayCount: 256
+ m_ReflectionCompression: 2
+ m_MixedBakeMode: 2
+ m_BakeBackend: 1
+ m_PVRSampling: 1
+ m_PVRDirectSampleCount: 32
+ m_PVRSampleCount: 500
+ m_PVRBounces: 2
+ m_PVRFilterTypeDirect: 0
+ m_PVRFilterTypeIndirect: 0
+ m_PVRFilterTypeAO: 0
+ m_PVRFilteringMode: 1
+ m_PVRCulling: 1
+ m_PVRFilteringGaussRadiusDirect: 1
+ m_PVRFilteringGaussRadiusIndirect: 5
+ m_PVRFilteringGaussRadiusAO: 2
+ m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+ m_PVRFilteringAtrousPositionSigmaIndirect: 2
+ m_PVRFilteringAtrousPositionSigmaAO: 1
+ m_ShowResolutionOverlay: 1
+ m_LightingDataAsset: {fileID: 0}
+ m_UseShadowmask: 1
+--- !u!196 &4
+NavMeshSettings:
+ serializedVersion: 2
+ m_ObjectHideFlags: 0
+ m_BuildSettings:
+ serializedVersion: 2
+ agentTypeID: 0
+ agentRadius: 0.5
+ agentHeight: 2
+ agentSlope: 45
+ agentClimb: 0.4
+ ledgeDropHeight: 0
+ maxJumpAcrossDistance: 0
+ minRegionArea: 2
+ manualCellSize: 0
+ cellSize: 0.16666667
+ manualTileSize: 0
+ tileSize: 256
+ accuratePlacement: 0
+ debug:
+ m_Flags: 0
+ m_NavMeshData: {fileID: 0}
+--- !u!1 &53270293
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 53270296}
+ - component: {fileID: 53270295}
+ - component: {fileID: 53270294}
+ m_Layer: 0
+ m_Name: EventSystem
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &53270294
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 53270293}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_HorizontalAxis: Horizontal
+ m_VerticalAxis: Vertical
+ m_SubmitButton: Submit
+ m_CancelButton: Cancel
+ m_InputActionsPerSecond: 10
+ m_RepeatDelay: 0.5
+ m_ForceModuleActive: 0
+--- !u!114 &53270295
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 53270293}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_FirstSelected: {fileID: 0}
+ m_sendNavigationEvents: 1
+ m_DragThreshold: 10
+--- !u!4 &53270296
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 53270293}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_RootOrder: 1
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &344612123
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 344612127}
+ - component: {fileID: 344612126}
+ - component: {fileID: 344612125}
+ - component: {fileID: 344612124}
+ m_Layer: 5
+ m_Name: Canvas
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &344612124
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 344612123}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 1301386320, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_IgnoreReversedGraphics: 1
+ m_BlockingObjects: 0
+ m_BlockingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+--- !u!114 &344612125
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 344612123}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 1980459831, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_UiScaleMode: 1
+ m_ReferencePixelsPerUnit: 100
+ m_ScaleFactor: 1
+ m_ReferenceResolution: {x: 800, y: 600}
+ m_ScreenMatchMode: 0
+ m_MatchWidthOrHeight: 0
+ m_PhysicalUnit: 3
+ m_FallbackScreenDPI: 96
+ m_DefaultSpriteDPI: 96
+ m_DynamicPixelsPerUnit: 1
+--- !u!223 &344612126
+Canvas:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 344612123}
+ m_Enabled: 1
+ serializedVersion: 3
+ m_RenderMode: 0
+ m_Camera: {fileID: 0}
+ m_PlaneDistance: 100
+ m_PixelPerfect: 0
+ m_ReceivesEvents: 1
+ m_OverrideSorting: 0
+ m_OverridePixelPerfect: 0
+ m_SortingBucketNormalizedSize: 0
+ m_AdditionalShaderChannelsFlag: 0
+ m_SortingLayerID: 0
+ m_SortingOrder: 0
+ m_TargetDisplay: 0
+--- !u!224 &344612127
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 344612123}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 0, y: 0, z: 0}
+ m_Children:
+ - {fileID: 601672577}
+ m_Father: {fileID: 0}
+ m_RootOrder: 2
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 0, y: 0}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0, y: 0}
+--- !u!1 &601672576
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 601672577}
+ - component: {fileID: 601672579}
+ - component: {fileID: 601672578}
+ m_Layer: 5
+ m_Name: Text
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &601672577
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 601672576}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 344612127}
+ m_RootOrder: 0
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0, y: 0}
+ m_AnchorMax: {x: 1, y: 1}
+ m_AnchoredPosition: {x: 0, y: 0}
+ m_SizeDelta: {x: 0, y: 0}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &601672578
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 601672576}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Material: {fileID: 0}
+ m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
+ m_RaycastTarget: 1
+ m_OnCullStateChanged:
+ m_PersistentCalls:
+ m_Calls: []
+ m_FontData:
+ m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
+ m_FontSize: 72
+ m_FontStyle: 0
+ m_BestFit: 0
+ m_MinSize: 7
+ m_MaxSize: 72
+ m_Alignment: 4
+ m_AlignByGeometry: 0
+ m_RichText: 1
+ m_HorizontalOverflow: 0
+ m_VerticalOverflow: 0
+ m_LineSpacing: 1
+ m_Text: Due to the new Unity asset publishing requirements you must follow the instructions
+ in the README file to unpack this plugin.
+--- !u!222 &601672579
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 601672576}
+ m_CullTransparentMesh: 0
+--- !u!1 &1655223073
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1655223076}
+ - component: {fileID: 1655223075}
+ - component: {fileID: 1655223074}
+ m_Layer: 0
+ m_Name: Main Camera
+ m_TagString: MainCamera
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!81 &1655223074
+AudioListener:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1655223073}
+ m_Enabled: 1
+--- !u!20 &1655223075
+Camera:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1655223073}
+ m_Enabled: 1
+ serializedVersion: 2
+ m_ClearFlags: 1
+ m_BackGroundColor: {r: 1, g: 1, b: 1, a: 0}
+ m_projectionMatrixMode: 1
+ m_SensorSize: {x: 36, y: 24}
+ m_LensShift: {x: 0, y: 0}
+ m_GateFitMode: 2
+ m_FocalLength: 50
+ m_NormalizedViewPortRect:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 1
+ height: 1
+ near clip plane: 0.3
+ far clip plane: 1000
+ field of view: 60
+ orthographic: 1
+ orthographic size: 5
+ m_Depth: -1
+ m_CullingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_RenderingPath: -1
+ m_TargetTexture: {fileID: 0}
+ m_TargetDisplay: 0
+ m_TargetEye: 3
+ m_HDR: 1
+ m_AllowMSAA: 1
+ m_AllowDynamicResolution: 0
+ m_ForceIntoRT: 0
+ m_OcclusionCulling: 1
+ m_StereoConvergence: 10
+ m_StereoSeparation: 0.022
+--- !u!4 &1655223076
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1655223073}
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: -10}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_RootOrder: 0
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
diff --git a/Assets/Shatalmic/Demo.unity.meta b/Assets/Shatalmic/Demo.unity.meta
new file mode 100644
index 00000000..4f135db5
--- /dev/null
+++ b/Assets/Shatalmic/Demo.unity.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 0149d806ed996492787b9cb44993fd5b
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Shatalmic/Editor.meta b/Assets/Shatalmic/Editor.meta
new file mode 100644
index 00000000..6b9cdfe0
--- /dev/null
+++ b/Assets/Shatalmic/Editor.meta
@@ -0,0 +1,5 @@
+fileFormatVersion: 2
+guid: 87247c18c42564aceaf454206a3ef873
+folderAsset: yes
+DefaultImporter:
+ userData:
diff --git a/Assets/Shatalmic/Editor/BluetoothPostProcessBuild.cs b/Assets/Shatalmic/Editor/BluetoothPostProcessBuild.cs
new file mode 100644
index 00000000..847ca187
--- /dev/null
+++ b/Assets/Shatalmic/Editor/BluetoothPostProcessBuild.cs
@@ -0,0 +1,30 @@
+#if UNITY_IOS
+using UnityEditor.Callbacks;
+using UnityEditor;
+using UnityEditor.iOS.Xcode;
+using System.IO;
+
+public class BluetoothPostProcessBuild
+{
+ [PostProcessBuild]
+ public static void ChangeXcodePlist(BuildTarget buildTarget, string pathToBuiltProject)
+ {
+ if (buildTarget == BuildTarget.iOS)
+ {
+ // Get plist
+ string plistPath = pathToBuiltProject + "/Info.plist";
+ PlistDocument plist = new PlistDocument();
+ plist.ReadFromString(File.ReadAllText(plistPath));
+
+ // Get root
+ PlistElementDict rootDict = plist.root;
+
+ rootDict.SetString("NSBluetoothPeripheralUsageDescription", "Uses BLE to communicate with devices.");
+ rootDict.SetString("NSBluetoothAlwaysUsageDescription", "Uses BLE to communicate with devices.");
+
+ // Write to file
+ File.WriteAllText(plistPath, plist.WriteToString());
+ }
+ }
+}
+#endif
diff --git a/Assets/Shatalmic/Editor/BluetoothPostProcessBuild.cs.meta b/Assets/Shatalmic/Editor/BluetoothPostProcessBuild.cs.meta
new file mode 100644
index 00000000..99d5856a
--- /dev/null
+++ b/Assets/Shatalmic/Editor/BluetoothPostProcessBuild.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 1695b640ed1354053a8cdd9e0186f57f
+timeCreated: 1493664761
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Shatalmic/Editor/PostprocessBuildPlayer b/Assets/Shatalmic/Editor/PostprocessBuildPlayer
new file mode 100644
index 00000000..3c2e8ece
--- /dev/null
+++ b/Assets/Shatalmic/Editor/PostprocessBuildPlayer
@@ -0,0 +1,93 @@
+#!/usr/bin/perl
+use File::Copy;
+
+print ("\n*** Starting PostprocessBuildPlayer ***\n");
+
+my $installPath = $ARGV[0];
+
+#values to watch for already existing
+my $requiredDeviceCapsString = "UIRequiredDeviceCapabilities";
+my $backgroundModesString = "UIBackgroundModes";
+my $bluetoothLEString = "bluetooth-le";
+
+#go through the info.plist file line by line until you find this one:
+my $endOfPlist = "";
+
+# The type of player built:
+# "dashboard", "standaloneWin32", "standaloneOSXIntel", "standaloneOSXPPC", "standaloneOSXUniversal", "webplayer", "iPhone"
+my $target = $ARGV[1];
+
+print ("\n*** PostprocessBuildPlayer - Building at '$installPath' with target: $target ***\n");
+
+################################################################
+# This modifies info.plist to add the external accessory #
+# entries #
+################################################################
+
+#open this file
+
+$oplistPath = $installPath."/Info.plist";
+$nplistPath = $installPath."/Info.plist.tmp";
+
+open OLDPLIST, "<", $oplistPath or die("Cannot open Info.plist");
+open NEWPLIST, ">", $nplistPath or die("Cannot create new Info.plist");
+
+my $nextLine = 0;
+my $requiredDeviceCapsFound = 0;
+my $backgroundModesFound = 0;
+
+while()
+{
+ if ($nextLine == 1)
+ {
+ if ($_ =~ m/$bluetoothLEString/)
+ {
+ }
+ else
+ {
+ $_ =~ s||\n\tbluetooth-le|
+ }
+
+ $nextLine = 0;
+ }
+
+ ################################################################
+ # Check for required device caps string already exists #
+ ################################################################
+ if ($_ =~ m/$requiredDeviceCapsString/ )
+ {
+ $nextLine = 1;
+ }
+
+ ################################################################
+ # Check for background modes string already exists #
+ ################################################################
+ if ($_ =~ m/$backgroundModesString/ )
+ {
+ $backgroundModesFound = 1;
+ }
+
+ ################################################################
+ # Add any key/value pairs you want at the end of Info.plist #
+ ################################################################
+
+ if ($_ =~ m/$endOfPlist/ && $backgrounModesFound == 0)
+ {
+ my $keys = "";
+
+ $keys .= " UIBackgroundModes\n";
+ $keys .= " \n";
+ $keys .= " bluetooth-central\n";
+ $keys .= " bluetooth-peripheral\n";
+ $keys .= " \n";
+
+ $_ = $keys . $_;
+ }
+
+ print NEWPLIST $_;
+}
+
+close OLDPLIST;
+close NEWPLIST;
+
+`mv \'$nplistPath\' \'$oplistPath\'`;
diff --git a/Assets/Shatalmic/Editor/PostprocessBuildPlayer.meta b/Assets/Shatalmic/Editor/PostprocessBuildPlayer.meta
new file mode 100644
index 00000000..7fceff06
--- /dev/null
+++ b/Assets/Shatalmic/Editor/PostprocessBuildPlayer.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 3c726eecf85fe4a88a7e7d57812ff455
+timeCreated: 1515198229
+licenseType: Pro
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Shatalmic/README.txt b/Assets/Shatalmic/README.txt
new file mode 100644
index 00000000..ea8d3e7b
--- /dev/null
+++ b/Assets/Shatalmic/README.txt
@@ -0,0 +1 @@
+You must double click on the unity package file called Plugin.unitypackage in order to unpack the plugin files.
\ No newline at end of file
diff --git a/Assets/Shatalmic/README.txt.meta b/Assets/Shatalmic/README.txt.meta
new file mode 100644
index 00000000..56fc2dbd
--- /dev/null
+++ b/Assets/Shatalmic/README.txt.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 3465e0116537642f78e4b288b23c461c
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Shatalmic/plugin.unitypackage.meta b/Assets/Shatalmic/plugin.unitypackage.meta
new file mode 100644
index 00000000..c11cbc4e
--- /dev/null
+++ b/Assets/Shatalmic/plugin.unitypackage.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 1a70f37e2f13e4df0ac477f3c3eb451b
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant: