我知道您特别询问了有关将数据写入蓝牙设备的问题,但这只是扩展了读取数据以及 Xamarin.iOS 外部附件 API 的一般用途,因为那里没有太多文档或 Xamarin 示例。这是使用 Objective-C 完成的Apple 示例的松散转换。我的配件是 MFi 认证的微芯片阅读器。我只添加了“读取”功能,因为我的应用程序只需要它。
创建一个继承自 NSStreamDelegate 的 SessionController 类,这会做很多工作。打开、关闭会话、处理来自设备的事件并读取数据。我想你也会在这里添加你的写方法。
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;
           }
        }