Я знаю, что вы специально спрашивали о записи данных на устройство Bluetooth, но это просто расширение чтения данных, а также общее использование API внешних аксессуаров для Xamarin.iOS, потому что там не так много документации или примеров Xamarin. Это свободное преобразование из Образец Apple, выполненный с помощью Objective-C. Моим аксессуаром был сертифицированный MFi считыватель микрочипов. Я добавил только функцию «чтения», так как мне это нужно было только для моего приложения.
Создайте класс SessionController, наследуемый от NSStreamDelegate, и это сделает большую часть работы. Открывает, закрывает сеансы, обрабатывает события с устройства и считывает данные. Я думаю, вы бы добавили сюда и свои методы записи.
public class EASessionController : NSStreamDelegate
{
NSString SessionDataReceivedNotification = (NSString)"SessionDataReceivedNotification";
public static EAAccessory _accessory;
public static string _protocolString;
EASession _session;
NSMutableData _readData;
public static EASessionController SharedController()
{
EASessionController sessionController = null;
if (sessionController == null)
{
sessionController = new EASessionController();
}
return sessionController;
}
public void SetupController(EAAccessory accessory, string protocolString)
{
_accessory = accessory;
_protocolString = protocolString;
}
public bool OpenSession()
{
Console.WriteLine("opening new session");
_accessory.WeakDelegate = this;
if (_session == null)
_session = new EASession(_accessory, _protocolString);
// Open both input and output streams even if the device only makes use of one of them
_session.InputStream.Delegate = this;
_session.InputStream.Schedule(NSRunLoop.Current, NSRunLoopMode.Default);
_session.InputStream.Open();
_session.OutputStream.Delegate = this;
_session.OutputStream.Schedule(NSRunLoop.Current, NSRunLoopMode.Default);
_session.OutputStream.Open();
return (_session != null);
}
public void CloseSession()
{
_session.InputStream.Unschedule(NSRunLoop.Current, NSRunLoopMode.Default);
_session.InputStream.Delegate = null;
_session.InputStream.Close();
_session.OutputStream.Unschedule(NSRunLoop.Current, NSRunLoopMode.Default);
_session.OutputStream.Delegate = null;
_session.OutputStream.Close();
_session = null;
}
/// <summary>
/// Get Number of bytes to read into local buffer
/// </summary>
/// <returns></returns>
public nuint ReadBytesAvailable()
{
return _readData.Length;
}
/// <summary>
/// High level read method
/// </summary>
/// <param name="bytesToRead"></param>
/// <returns></returns>
public NSData ReadData(nuint bytesToRead)
{
NSData data = null;
if (_readData.Length >= bytesToRead)
{
NSRange range = new NSRange(0, (nint)bytesToRead);
data = _readData.Subdata(range);
_readData.ReplaceBytes(range, IntPtr.Zero, 0);
}
return data;
}
/// <summary>
/// Low level read method - read data while there is data and space in input buffer, then post notification to observer
/// </summary>
void ReadData()
{
nuint bufferSize = 128;
byte[] buffer = new byte[bufferSize];
while (_session.InputStream.HasBytesAvailable())
{
nint bytesRead = _session.InputStream.Read(buffer, bufferSize);
if (_readData == null)
{
_readData = new NSMutableData();
}
_readData.AppendBytes(buffer, 0, bytesRead);
Console.WriteLine(buffer);
}
// We now have our data from the device (stored in _readData), so post the notification for an observer to do something with the data
NSNotificationCenter.DefaultCenter.PostNotificationName(SessionDataReceivedNotification, this);
}
/// <summary>
/// Handle the events occurring with the external accessory
/// </summary>
/// <param name="theStream"></param>
/// <param name="streamEvent"></param>
public override void HandleEvent(NSStream theStream, NSStreamEvent streamEvent)
{
switch (streamEvent)
{
case NSStreamEvent.None:
Console.WriteLine("StreamEventNone");
break;
case NSStreamEvent.HasBytesAvailable:
Console.WriteLine("StreamEventHasBytesAvailable");
ReadData();
break;
case NSStreamEvent.HasSpaceAvailable:
Console.WriteLine("StreamEventHasSpaceAvailable");
// Do write operations to the device here
break;
case NSStreamEvent.OpenCompleted:
Console.WriteLine("StreamEventOpenCompleted");
break;
case NSStreamEvent.ErrorOccurred:
Console.WriteLine("StreamEventErroOccurred");
break;
case NSStreamEvent.EndEncountered:
Console.WriteLine("StreamEventEndEncountered");
break;
default:
Console.WriteLine("Stream present but no event");
break;
}
}
}
В моем ViewController, который будет отображать данные, которые я только что прочитал из внешнего аксессуара, мы все это подключаем. В ViewDidLoad создайте наблюдателей, чтобы представление знало, когда событие было запущено устройством. Также убедитесь, что мы подключены к правильному аксессуару, и откройте сеанс.
public EASessionController _EASessionController;
EAAccessory[] _accessoryList;
EAAccessory _selectedAccessory;
NSString SessionDataReceivedNotification = (NSString)"SessionDataReceivedNotification";
string myDeviceProtocol = "com.my-microchip-reader.1234";
public override void ViewDidLoad()
{
base.ViewDidLoad();
NSNotificationCenter.DefaultCenter.AddObserver(EAAccessoryManager.DidConnectNotification, EADidConnect);
NSNotificationCenter.DefaultCenter.AddObserver(EAAccessoryManager.DidDisconnectNotification, EADidDisconnect);
NSNotificationCenter.DefaultCenter.AddObserver(SessionDataReceivedNotification, SessionDataReceived);
EAAccessoryManager.SharedAccessoryManager.RegisterForLocalNotifications();
_EASessionController = EASessionController.SharedController();
_accessoryList = EAAccessoryManager.SharedAccessoryManager.ConnectedAccessories;
foreach (EAAccessory acc in _accessoryList)
{
if (acc.ProtocolStrings.Contains(myDeviceProtocol))
{
// Connected to the correct accessory
_selectedAccessory = acc;
_EASessionController.SetupController(acc, myDeviceProtocol);
_EASessionController.OpenSession();
lblEAConnectionStatus.Text = acc.Name;
Console.WriteLine("Already connected via bluetooth");
}
else
{
// Not connected
}
}
}
Создайте методы DidConnect, DidDisconnect и SessionDataReceived. Имя устройства просто обновляется на некоторых ярлыках при подключении/отключении, и я отображаю данные в текстовом поле.
void EADidConnect(NSNotification notification)
{
EAAccessory connectedAccessory = (EAAccessory)notification.UserInfo.ObjectForKey((NSString)"EAAccessoryKey");
Console.WriteLine("I did connect!!");
_accessoryList = EAAccessoryManager.SharedAccessoryManager.ConnectedAccessories;
// Reconnect and open the session in case the device was disconnected
foreach (EAAccessory acc in _accessoryList)
{
if (acc.ProtocolStrings.Contains(myDeviceProtocol))
{
// Connected to the correct accessory
_selectedAccessory = acc;
Console.WriteLine(_selectedAccessory.ProtocolStrings);
_EASessionController.SetupController(acc, myDeviceProtocol);
_EASessionController.OpenSession();
}
else
{
// Not connected
}
}
Console.WriteLine(connectedAccessory.Name);
// Update a label to show it's connected
lblEAConnectionStatus.Text = connectedAccessory.Name;
}
void EADidDisconnect(NSNotification notification)
{
Console.WriteLine("Accessory disconnected");
_EASessionController.CloseSession();
lblEAConnectionStatus.Text = string.Empty;
}
/// <summary>
/// Data receieved from accessory
/// </summary>
/// <param name="notification"></param>
void SessionDataReceived(NSNotification notification)
{
EASessionController sessionController = (EASessionController)notification.Object;
nuint bytesAvailable = 0;
while ((bytesAvailable = sessionController.ReadBytesAvailable()) > 0)
{
// read the data as a string
NSData data = sessionController.ReadData(bytesAvailable);
NSString chipNumber = new NSString(data, NSStringEncoding.UTF8);
// Displaying the data
txtMircochipNumber.Text = chipNumber;
}
}
person
Tahari
schedule
13.07.2017