原文地址:thecodewash.blogspot.com/2017/05/com…
原文作者:thecodewash.blogspot.com/
发布时间:2017年5月24日
通过USB与您的iOS应用程序进行通信(C#和/或Xamarin)。
所以,你正在编写一个需要与桌面客户端通信的iOS应用。在google上快速搜索一下就会发现,唯一的方法就是在桌面客户端上创建一个小型的socket服务器,在给定的端口上进行监听,然后让iOS应用通过你的本地网络连接到桌面客户端。这绝对是可行的,而且很多时候已经很好了。如果你熟悉socket编程,这绝对是直接的。然而,肯定有一些缺点。应用程序必须与客户端在同一个网络上(在企业环境中,你的计算机在一些私有的有线网络上,这并不总是可能的)。客户端为你的电脑打开了一个端口,网络上的任何人都可以访问,这可能是一个安全问题。初始设置也比较繁琐,因为应用用户必须在应用中输入IP地址和端口才能连接。如果能够通过USB线实现 "iOS应用到桌面 "的通信,就可以解决所有这些问题,并使(在我看来)应用更加方便。
这个方法的问题只是关于如何实现这个功能的文档太少了。一些论坛的帖子说这是不可能的。其他人会说,你需要注册苹果的MFi计划(一个漫长而乏味的过程)。好吧, 在花了上周在互联网上搜索, 我在这里告诉你,它绝对是可能的,没有MFi. 而且,一旦你明白发生了什么,它甚至不是那么困难。所以,这就是我学到的一切。
几个快速说明
我主要是一个C#/.NET的开发人员,所以我写这篇文章是假设你也是。这些概念是非常通用的,但例子将使用C#。我正在使用Xamarin.iOS来构建iOS应用,所以即使是iOS代码也将使用C#。
另外,我认为有必要指出,对于编写Swift/Objective-C代码的开发者来说,有一个非常棒的平台工具,叫做Peertalk,它可以完成我将要讲到的所有内容。不幸的是,没有Xamarin的绑定。我几乎决定关掉Xamarin来使用这个,最后才知道如何非常快速、轻松地完成Peertalk的工作。
苹果是怎么做的呢?
当你把你的iOS设备插到电脑上时,你就可以通过USB线来同步你的数据。苹果实现这个功能的方式是通过一个非常方便的程序usbmuxd。这是一个在电脑上运行的程序,等待iOS设备的连接。如果你的机器上安装了iTunes,你也安装了这个程序。在Windows上,承载这个程序的服务名为 "Apple Mobile Device Service",可以在services.msc中看到。那么,usbmuxd是做什么的呢?
usbmuxd
usbmuxd是USB多路复用守护进程的缩写。如果你和我一样,"USB "是这个名字中唯一真正熟悉的术语。但这个程序所做的事情其实很简单(而且对我们来说非常有用)。它是一个后台进程(守护进程),可以告诉你的iOS设备将所有从USB电缆接收到的数据映射(复用)到iOS设备上的网络端口,并返回一个套接字连接到该端口。
那么,实际上,这对我们意味着什么呢?这意味着,如果你在iOS设备上做了这样的事情
var socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Loopback, 5050));
socket.Listen(100);
socket.BeginAccept((ar) =>
{
var connectionAttempt = (Socket) ar.AsyncState;
var connectedSocket = connectionAttempt.EndAccept(ar);
// Do something with "connectedSocket"
}, socket);
上面的代码(正在你的iOS设备上运行)现在正在监听5050端口(我完全随意选择的)的传入连接。我知道你可能在想什么。"我以为我们不会使用网络连接。什么情况!?"
这就是usbmuxd的神奇之处。从你的桌面应用程序,你可以发送一个消息到usbmuxd,通知连接的iOS设备接收网络端口上的所有USB数据。在我们的例子中,我们想让usbmuxd告诉我们的iOS设备在5050端口接收USB数据。usbmuxd会答应,并给你一个套接字句柄发送数据和接收数据。这时,你的iOS应用将调用 "BeginAccept "回调,你将有一个网络套接字,但不是真正的 "网络 "套接字。即使你的电脑和iOS设备在不同的网络上,或者根本就没有网络,这也可以工作。所有的数据都是通过你的USB线进行的!
那么......我到底该如何与usbmuxd通信呢?
幸运的是,有一个nuget包可以解决这个问题! iMobileDevice.Net的nuget页面可以在这里找到。它并不是最完善的文档工具,但它非常好用。它假定usbmuxd服务在你的机器上运行。最简单的方法是确保你已经安装了iTunes. 如果你不想依赖iTunes,你可以像Duet Display的人一样,从iTunes安装程序中解压出相应的msi,并将其作为应用程序的先决条件。
AppleApplicationSupport64.msi AppleMobileDeviceSupport6464.msi安装程序将安装你需要的服务。
一旦你知道usbmuxd确实在你的机器上,你就可以开始使用nuget包了。这个包实际上只是一个C库的包装器,它显示了。有很多IntPtr's和out参数,所以它不是很好看。但它可以工作。
这是我正在做的一个项目中的一个片段。下面的代码监听一个iOS设备事件(usbmuxd为我们调用)。当该事件是 "DeviceAdd "事件时,我尝试连接到它。
public void BeginListening()
{
_iDeviceApi.idevice_event_subscribe(_eventCallback, new IntPtr());
}
private iDeviceEventCallBack EventCallback()
{
return (ref iDeviceEvent devEvent, IntPtr data) =>
{
switch (devEvent.@event)
{
case iDeviceEventType.DeviceAdd:
Connect(devEvent.udidString);
break;
case iDeviceEventType.DeviceRemove:
break;
default:
return;
}
};
}
Connect方法使用所连接的设备的udid获取一个 "DeviceHandle "引用。一旦得到这个句柄,它就会调用 "ReceiveDataFromDevice "方法。
private void Connect(string newUdid)
{
_iDeviceApi.idevice_new(out iDeviceHandle deviceHandle, newUdid).ThrowOnError();
var error =_iDeviceApi.idevice_connect(deviceHandle, 5050, out iDeviceConnectionHandle connection);
if (error != iDeviceError.Success) return;
ReceiveDataFromDevice(connection);
}
private void ReceiveDataFromDevice(iDeviceConnectionHandle connection)
{
Task.Run(() =>
{
while (true)
{
uint receivedBytes = 0;
_iDeviceApi.idevice_connection_receive(connection, _inboxBuffer, (uint)_inboxBuffer.Length,
ref receivedBytes);
if (receivedBytes <= 0) continue;
// Do something with your received bytes
}
});
}
最后,下面一行将数据发送到iOS设备。
_iDeviceApi.idevice_connection_send(connection, bytesPending, (uint)bytesPending.Length, ref sentBytes);
还有很多其他的函数可供你使用,但这些是一些重要的函数。使用这些功能,你可以开始通过USB向你的iOS设备发送数据。你的iOS应用甚至不会知道这是一个USB连接。对应用程序来说,它只是另一个TCP网络连接。希望这能为你节省一些时间,如果你有任何问题,可以随时评论或给我留言。
祝你编码快乐!