65.9K
CodeProject 正在变化。 阅读更多。
Home

Zune 检测和网络感知

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (17投票s)

2010年10月26日

Ms-PL

13分钟阅读

viewsIcon

54342

downloadIcon

861

如何在 WP7 应用程序中检测 Zune 连接和网络状态

NetworkAwarenessTest.jpg

目录

前言

  • 为了所有的测试,我使用了有线同步,因为不知何故我无法通过 WiFi 同步。如果我成功了,这篇文章会进行更新。
  • 我与微软的工程师们之间有很多邮件往来,因为他们无法重现网络功能的大部分奇怪行为,尽管我曾发送过一些问题的视频给他们。但我不得不说,我对此相当满意,因为这可能意味着最终版本的手机比我正在使用的开发设备(固件为 7003 的 LG GW910)要好得多。我迫不及待想拿到设备的最终版本。:)

引言

检测网络状态是一项重要任务。利用网络功能的应用程序应该了解手机是否有互联网连接,以及连接的确切类型。在“System.Net.NetworkInformation”和“Microsoft.Phone.Net.NetworkInformation”这两个命名空间中,有一些方法和事件专门用于此。这两个命名空间很相似,但功能有所不同。

背景

System.Net.NetworkInformation 命名空间

  • bool System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable(): 指示是否有任何网络连接可用。
  • event System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged: 当网络状态改变时(也称为 Changed Event)会引发一个事件。

用法和示例: http://msdn.microsoft.com/en-us/library/system.net.networkinformation.networkinterface.getisnetworkavailable%28v=VS.95%29.aspx

Microsoft.Phone.Net.NetworkInformation 命名空间

bool Microsoft.Phone.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable(): 指示是否有任何网络连接可用。这与System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()完全相同。

枚举 Microsoft.Phone.Net.NetworkInformation.NetworkInterfaceType:

互联网连接的类型。

  • None 没有可用于访问互联网的网络。
  • AsymmetricDsl
  • Atm
  • BasicIsdn
  • Ethernet 网络接口使用以太网连接。以太网在 IEEE 标准 802.3 中定义。
  • Ethernet3Megabit
  • FastEthernetFx
  • FastEthernetT
  • Fddi
  • GenericModem
  • GigabitEthernet
  • HighPerformanceSerialBus
  • IPOverAtm
  • Isdn
  • Loopback
  • MultiRateSymmetricDsl
  • Ppp
  • PrimaryIsdn
  • RateAdaptDsl
  • Slip
  • SymmetricDsl
  • TokenRing
  • Tunnel
  • 未知
  • VeryHighSpeedDsl
  • Wireless80211 网络接口使用无线局域网连接(IEEE 802.11 标准)。
  • MobileBroadbandGsm 网络接口使用 GSM 蜂窝网络。
  • MobileBroadbandCdma 网络接口使用 CDMA 蜂窝网络。

来源: http://msdn.microsoft.com/en-us/library/microsoft.phone.net.networkinformation.networkinterfacetype%28v=VS.92%29.aspx

属性 Microsoft.Phone.Net.NetworkInformation.NetworkInterface.NetworkInterfaceType

用法: http://msdn.microsoft.com/en-us/library/microsoft.phone.net.networkinformation.networkinterface.networkinterfacetype%28v=VS.92%29.aspx

在模拟器上,如果计算机连接到互联网,NetworkInterfaceType 大多为 Wireless8011;如果断开连接,则为 None。但是,如果您有机会像我一样在设备上进行测试,您可以获得有效的结果,而这正是我将用来检测设备是否连接到计算机的方法。在下一节中,我将解释这些函数在具有最终 7003 RTM 固件发布的 LG 测试设备上如何工作。

网络行为和优先级

网络接口的优先级如下:

如果在 PC 上运行 Zune 或 WPDTConnect 并且手机正在同步,则设备通过 PC 连接到互联网(NetworkInterfaceType=="Ethernet")。如果 PC 没有互联网连接,设备将卡住而无法连接互联网,NetworkInterfaceType 将为 "None"。如果没有同步连接,手机将在 WiFi 和宽带连接之间进行选择。WiFi 的优先级高于宽带。如果两者都不可用,或者连接的 WiFi 没有互联网访问权限,NetworkInterfaceType 将为 "None"。在丢失更高优先级的连接后,设备会自动尝试连接到下一个可用的连接类型。注意! 如果在没有互联网的情况下与 Zune/WPDT 同步,手机将不会切换到可用或预定义的 WiFi/宽带。

NetworkAddressChanged 事件详解

此事件自 Silverlight 3 起存在,并在 Windows Phone 7 上受支持。基本上,当手机的 IP 地址更改时,该事件会发生,通常在以下情况之一:

  • Zune/WPDT 启动(连接同步线缆或已连接)
  • Zune/WPDT 停止
  • 同步时断开同步线缆
  • WiFi/宽带连接/断开(进入/离开区域)

同步期间,手机从 PC 获取 IP 地址,由于我们无法(到目前为止)从代码中获取此 IP 地址,因此我们必须依赖此事件和 NetworkInterfaceType 属性。如果设备已建立更高优先级的连接,则不会发生此事件。

检测 Zune/WPDT 连接状态的更改并引发事件相对较快(2-5 秒),但如果 WiFi/宽带连接丢失,有时需要 20-30 秒才能引发事件。断开 Zune 连接后,事件引发几乎是瞬时的(0-3 秒),但如果系统正在切换到 WiFi/宽带,这段时间可能不足以正确建立 WiFi 连接,因此请小心基于事件的 UI/代码刷新。当可用性更高的网络出现时,手机会自动尝试连接到它,如果成功,将引发此更改事件(优先级:Zune、WiFi、宽带)。在网络更改期间,Changed 事件可能会连续发生几次。有些情况下,我启动应用程序时使用的是宽带,然后打开了一个我之前连接了手机的路由器,大约 45-60 秒后,引发了 3-4 次连接更改事件。NetworkInterfaceType 的顺序如下(我在事件处理程序中进行了检查):

MobileBroadbandGsm, Wireless8011, Wireless8011, Wireless8011。所以第一个是宽带,这是初始连接,然后是 3 个 WiFi 连接,这可能是某些无法解释的 IP 更改的结果。这种情况可能发生在任何网络类型切换时,所以最好做好准备。

Microsoft.Phone.Net.NetworkInformation.NetworkInterface.NetworkInterfaceType 属性详解

首先,读取此属性会阻塞 UI 线程。阻塞时间主要取决于从/到 NetworkType

  • 拔出同步线缆,同时 Zune 已连接 -> WiFi 连接:NetworkType 阻塞约 1 秒(再次强调,这并不总是足够让手机正确连接 WiFi)
  • 已同步,Zune 已连接,PC 通过 WiFi 连接到互联网 -> PC WiFi 关闭 -> NetworkType 会使 UI 阻塞 20-30 秒!!!!结果将是 "None" NetworkType,但如果在 20 秒冻结期间再次打开 WiFi,结果的 NetType 将是 Ethernet 而不是 None,就像什么都没发生一样。

解决方案:将其放入 BackgroundWorker 中,继续阅读了解详细信息。

连接/同步问题

在我们的开发手机上,有几次我同步手机后没有引发 Network Changed 事件。在这种情况下,NetworkType 包含 WiFi 类型而不是 Ethernet。我的意思是,根据我们的开发设备,这些功能不能 100% 信任。我希望在最终版本上,它们是可靠的。

Zune 检测

到目前为止,WP7 在 Zune 软件连接时无法在设备上播放视频。有一个捷径是使用 WPDTPTConnect64/32 程序,它可以连接手机到 PC 而不阻止媒体,但这仅由开发人员使用。我认为能够检测 Zune 是否连接应该是基本功能。在 WP7 SDK 中,我找不到任何专门针对这种情况的功能。但有一个变通方法,可以利用上述功能。

也许您已经注意到,当您尝试在 MediaElementSmoothStreamingMediaElement 中打开 MediaFile 时,如果在 Zune 连接时,您会收到一个包含 AG_E_NETWORK_ERROR ErrorMessageMediaFailed 事件。检测到这一点必须是 Windows Phone 7 上 Zune 检测的最后一道防线。

如果可能,我们需要避免走到这一步,并且必须在尝试播放 MediaFile 之前检测连接状态。通过使用 Changed 事件和 NetworkType 属性,我们可以在连接后立即通知用户,或者至少在点击播放按钮时通知。

关于 None NetworkType

NetworkType 表示手机没有互联网访问权限的状态。切换到此状态或处于此状态时,NetType 请求几乎总是很慢(10-60 秒,尤其是在切换到此状态时)。此状态的一个大问题是,我们不一定知道我们是如何到达这里的。例如:

  1. 应用程序刚刚启动,GetIsNetworkAvailable() 函数返回 TRUE,这意味着我们连接到了一个 Network,而 NetTypeNone!!在这种情况下,正确的连接可能是通过 PC 与手机同步但没有互联网,或者 WiFi 路由器连接到手机但没有互联网。
  2. 应用程序刚刚启动,GetIsNetworkAvailable() 函数返回 FALSE,这意味着我们没有连接到任何 Network,而 NetType 显然是 None!!然后手机与没有互联网连接的 PC 同步,或者手机连接到一个没有互联网连接的路由器。

如果是与 PC 的情况,那么 Zune 就已连接,但我们无法确定,因为它也可能是 WiFi。我知道这些情况发生的可能性极小,但仍然可能发生。在代码中,我没有处理这些情况,但如果您有更好的解决方案,请告诉我。您可以留下评论,或发送电子邮件至 dolhaig at gmail 地址。

关于此 NetworkType 的另一个重要事项是:当手机有另一个网络连接时,框架不会在切换到此状态时触发 Changed 事件。让我再解释一下:

  • 您将收到一个更改事件:手机没有预先配置的 WiFi 或宽带,并且当前通过 Zune 同步连接到 PC。断开连接,您将收到一个更改事件,因为手机丢失了 IP 并且没有可用的连接。NetType 将是 None,我代码中的 "online" 变量将是 FalseOnNetworkOFF 事件也会触发)。
  • 没有更改事件:手机处于 WiFi/Ethernet (Zune) 状态,并且路由器/PC 丢失了互联网连接。NetworkType=Noneonline=True(手机仍有 IP 地址)。此状态只能通过轮询检测。

让我们看看代码

我创建了一个 Singleton 类,该类使用这些函数来简化网络接口的使用。对于 Zune 检测,我只需检查返回的 NetworkType 是否为 "Ethernet",如果是,则 Zune 必定已连接。通过我的类,您可以在以下情况下收到通知:

  • 不同的连接类型被激活/停用
  • 所有网络丢失/部分找到
  • Zune 已连接/断开

尽管该类隐藏了框架函数在您的其他代码中的实际工作方式,但如果您将 DetailedMode 布尔值设置为 True,则可以获取框架的所有事件和 Networktype 更改。还可以以用户提供的间隔时间轮询 NetworkType

关于事件

  • public NetworkAvailableEventArgs(bool isOnline):仅包含 NetworkAvailability 状态 true/false,当为 false 时,手机绝对未连接到网络
  • public NetworkDetectorEventArgs(bool isOnline, Microsoft.Phone.Net.NetworkInformation.NetworkInterfaceType netType)NetworkAvailability 和网络类型
public event EventHandler OnNetworkON;
public event EventHandler OnNetworkOFF;
public event EventHandler OnNetworkChanged;

public event EventHandler OnZuneConnected;
public event EventHandler OnZuneDisconnected;
public event EventHandler OnConnectedEthernet;
public event EventHandler OnConnectedWifi;
public event EventHandler OnConnectedNone;
public event EventHandler OnConnectedBroadbandGsm;
public event EventHandler OnConnectedBroadbandCdma;
public event EventHandler OnConnectedOther;
public event EventHandler OnLostNetworkType;

public event EventHandler OnAsyncGetNetworkTypeCompleted;
  • OnNetworkONOnNetworkOFF:当手机从无网络状态连接到任何网络或失去所有网络连接时触发
  • OnNetworkChanged:仅在 DetailedMode=True 时触发,当框架引发 System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged 时发生
  • OnZuneConnectedOnZuneDisconnected:不言而喻,仅在连接/断开 Ethernet 网络类型开始时触发
  • OnLostNetworkType:当 NetworkType 更改时触发。此事件的 NetType 属性包含之前的 NetworkType,与其它事件不同,在其它事件中,它包含实际的 Type(当存在时)
  • OnAsyncGetNetworkTypeCompleted:调用 AsyncGetNetworkType public 函数后返回的事件
  • OnConnectedXXX:当框架引发 NetworkAddressChanged 事件并且 NetworkType 与之前的 NetworkType 相比发生变化时,会引发这些事件。当 DetailedModeTrue 时,每次框架的 NetworkAddressChanged 事件发生或轮询运行 Tick 事件时,它们都会触发

公共属性和函数

public void AsyncGetNetworkType()
{
    //requestQueue.Enqueue(System.DateTime.Now.Ticks);
    IsInstantRequestPresent = true;
    if (!networkWorker.IsBusy)
    {
        requestStatus = NetworkTypeRequestStatus.Started;
        networkWorker.RunWorkerAsync();
    }
    if (!updateTimer.IsEnabled) updateTimer.Start();
}

public void SetNetworkPolling(int Minutes, int Seconds, int Milliseconds)
{
    pollTimer.Interval = new TimeSpan(0, 0, Minutes, Seconds, Milliseconds);
    if (!pollTimer.IsEnabled) pollTimer.Start();
}

public void DisableNetworkPolling()
{
    if (pollTimer.IsEnabled) pollTimer.Stop();
}

public Microsoft.Phone.Net.NetworkInformation.NetworkInterfaceType 
	GetCurrentNetworkType()
{
    return net;
}

public NetworkTypeRequestStatus GetRequestStatus()
{
    //NetworkTypeRequestStatus temp = requestStatus;
    //if (requestStatus == NetworkTypeRequestStatus.Ended) 
    //requestStatus = NetworkTypeRequestStatus.Default;
    //return temp;
    return requestStatus;
}

public bool DetailedMode
{
    get
    {
        return detailedMode;
    }
    set
    {
        detailedMode = value;
    }
}

public bool GetZuneStatus()
{
    return isZuneConnected;
}
  • 函数 AsyncGetNetworkType:启动一个即时且单一的请求来确定当前的 NetworkType。完成后,会引发 OnAsyncGetNetworkTypeCompleted 事件,并附带当前的 NetType
  • Function SetNetworkPolling(int Minutes, int Seconds, int Milliseconds):以用户提供的时时间隔启动 NetworkType 轮询
  • 函数 DisableNetworkPolling:停止 NetworkType 轮询
  • 函数 GetCurrentNetworkType:返回当前存储的 NetworkType
  • 函数 GetRequestStatus:返回 BackgroundWorker 的状态,确定 NetType 请求是否存在(NetworkTypeRequestStatus.Started)或不存在(NetworkTypeRequestStatus.Ended)。
  • 函数 GetZuneStatus:Zune 已连接(true)或未连接(false
  • 属性 DetailedMode:这是一个 get/set 布尔属性,用于确定事件是每次框架引发时(包括 NetworkPolling)都触发(true),还是仅在 NetworkType 真正改变时触发(false)。False 是默认设置,以隐藏框架的故障。

Using the Code

首先,在App.xaml.cs 中,引用 Singleton

NetworkDetector nd;
// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
    nd = NetworkDetector.Instance;
}

// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
    nd = NetworkDetector.Instance;
}

通过这种方式,您甚至可以在代码从 tombstone 返回时,从一开始就为更改做好准备。

然后,根据您的应用程序速度和对框架的信任程度,选择您想要使用代码的方式:

  • 不时进行单次请求或用户轮询:您可以随时调用 AsyncGetNetworkType 函数,它将在 OnAsyncGetNetworkTypeCompleted 事件中返回当前状态。
  • 如果您完全信任框架,认为它会在正确的时间引发 NetworkAddressChanged 事件,那么您可以订阅正确的事件,它将及时引发。
  • 您不信任框架(因为它很糟糕 :) )或者您只是想一直知道网络状态:使用 SetNetworkPolling 函数设置一个合适的轮询间隔,并订阅正确的事件。多亏了 BackgroundWorker,即使在繁重的轮询中,UI 也可以完全响应。在我进行的测试中,我注意到即使将轮询间隔设置为 100 毫秒,框架也只能提供每秒大约 3 个请求。

监控特定的 NetworkType

例如,假设您是一位非常细心的开发者,您不希望用户将他们的全部薪水都花在移动运营商上,因此您想监控连接类型,当系统使用宽带连接时限制使用的数据量,然后当有更好的连接可用时再发送大量数据。

您只需订阅宽带事件和 OnLostNetworkType 事件。在 OnLostNetworkType 中,您将获得之前的网络是什么,然后您可以使用 GetCurrentNetworkType 获取当前网络,或者手动使用 AsyncGetNetworkType 函数进行轮询,以确定当前连接是否适合发送大量数据。

重要!此库与框架一样好。我相信最终版本的手机将比我们的开发设备好得多,开发设备已经足够好,可以为大多数问题创建变通方法。

我的代码可以在 MS-PL 许可下自由使用。Singleton 类可以在NetworkDetector.cs 中找到。

如果您发现这篇文章有用,请投票

了解一下

本文也可以在我的 WP7 博客上找到:

© . All rights reserved.