Delphi和C++Builder获取手机网络连接状态(Android & IOS)
介绍
对FireMonkey开发人员来说,检查互联网连接是一项常见的任务。通知用户他将要使用移动连接下载大量数据或者在用户界面上显示联机/脱机状态,这是很有用的。
Rad studio类中缺少此功能,因此许多开发人员都为他们的需求制定了解决方案,尽管大多数开发人员解决了他们在开发中的问题,但这可能无法满足您的需求。
为了填补这个空白,作者提出了一个遵循以下准则的解决方案:
完整的解决方案称为“firemonkey-network-state”
如何整合
- 下载源码,并将其添加到你的项目中
- 构建Android项目,要启用ACCESS_NETWORK_STATE权限(在项目的 Project Options——Application——Uses permissions中,勾选ACCESS_NETWORK_STATE)
- 对于Delphi构建的iOS项目,将 libReachability.a 和 libReachability64.a放到根目录中;对于C++构建的iOS项目,添加libReachability64.a到项目中(“Project”—— “Add to project”)。这些文件源码文件夹中已提供。注:在C++项目中,你可以使用libReachability64.a来构建32位和64。
- 您可能需要在RAD Studio SDK Manager中为iOS平台添加“SystemConfiguration”系统配置框架。有关如何操作的说明,请阅读这篇文章。
如何使用
唯一需要的步骤是使用Factory工厂类方法初始化TNetworkState类的实例:
Factory(AOwner: TComponent; AOnChange: TNetworkStateChangeEvent): TNetworkState;
第二个参数为网络状态改变事件,如果不需要,则为nil。
TNetworkState实例的数量没有限制,如果需要,程序的不同部位都可以安全地分配实例。
然后,访问TNetworkState.CurrentValue属性以检索当前网络状态。返回值类型为TNetworkStateValue它是已定义网络状态的枚举类型:
TNetworkStateValue = ( nsUnknown = 0, nsConnectedWifi = 1, nsConnectedMobileData = 2, nsDisconnected = 3 );
如果要通过一个事件来处理Factory方法,那么每次连接改变时都会调用它。请注意:事件处理是在主线程的上下文中调用的,因此您可以操作UI而不需要任何额外的Synchronize同步。更新连接状态通过事件处理参数传递:
procedure TSampleForm.DoOnChange(Sender: TObject; Value: TNetworkStateValue); begin // 响应网络状态变化 end;
局限性
- 在C++中,需要将libReachability64.a文件添加到项目中。如果您有一个既适用于iOS又适用于Android的项目,则需要在构建Android之前从构建中排除.a文件,并在构建iOS之前启用。请注意,如果您忘记在iOS平台启用它,项目将编译良好,但在分配TNetworkStateValue实例时会发生异常。
- 该库不能再iOS simulator模拟器中工作。这背后的原因是:TNetworkStateValue的iOS实现使用Objective-C静态库(libReachability64.a),而Delphi链接器在构建iOS simulator平台时会忽略静态库。为了方便起见,作者在iOS simulator平台上实例化了虚拟的TNetworkStateValue,这样项目就可以编译和运行,但是CurrentValue总是返回nsUnknown ,并且永远不会调用“on change”事件。
在Android中启用详情
就像在Dave(作者博客:https://www.delphiworlds.com/download/network-state-demo/)的解决方案中一样,TNetworkState使用Android SDK中的ConnectivityManager 类检索当前网络状态
尽管如此,这个类不能检测连接状态何时改变。Android使用另一种机制来报告它——Intent Messages。每次连接发生变化时,Android都会向所有正在运行的应用程序广播特定的Intent Messages。为了接收它,我们需要一个BroadcastReceiver实例
首先,我们需要实例化接收器并订阅特定的消息,对于这个任务,我们只需要在android.net.conn.CONNECTIVITY_CHANGE更改。为每个入站消息触发OnReceive回调。注意,回调在Java线程的上下文中触发。
BroadcastReceiver 可以用于许多目的,例如监听其他系统范围内的事件或在进程间通信。
在iOS中启用详情
同样,Dave的解决方案完成了互联网连接检索的工作。不幸的是,iOS SDK中没有方便的API来管理Internet连接,因此许多iOS开发者使用developer.apple.com中的reachability类。
在源码文件夹中已经包含了libReachability.a这个静态库类,你需要链接到FireMonkey应用程序二进制文件中。然后,我们可以创建Reachability 类的头,并用Delphi或C++实例化。
Reachability 类本身不报告连接的改变。通过研究它的源代码,连接事件将通过iOS SDK发布到NSNotificationCenter类。
为了使用此事件,我们需要定义委托接口:
INetworkChangeDelegate = interface(IObjectiveC) ['{BC4EABBE-F21F-4592-93B0-0C40415E4A91}'] procedure handleNetworkChange(notice: NSNotification); cdecl; end;
然后,使用从TOCLocal基类派生的Delphi类执行此接口:
TNetworkChangeDelegate = class (TOCLocal, INetworkChangeDelegate) public // (void) handleNetworkChange:(NSNotification *)notice procedure handleNetworkChange(notice: NSNotification); cdecl; end;
完成此操作后,我们可以添加监听observer到连接改变事件::
TNSNotificationCenter.Wrap(TNSNotificationCenter.OCClass.defaultCenter).addObserver( FDelegate.GetObjectID, sel_getUid('handleNetworkChange:'), StringToID('kReachabilityChangedNotification'), nil );
其中,FDelegate.GetObjectID是对Objective-C委托对象的引用,sel_getUid('handleNetworkChange:“)是Objective-C方法选择器,“kReachabilityChangedNotification”是我们要监听的通知名称。
注意,我们需要保持对FDelegate对象的引用,否则它将被自动引用计数(ARC)机制销毁。
调用AddObserver后,每次连接更改都将调用TNetworkChangeDelegate.handleNetworkChange。