Add iOS specific implementation for the networkreachabilitymonitor
This commit is contained in:
parent
2633bc4e40
commit
dee1aa4e04
@ -9,6 +9,10 @@ NetworkReachabilityMonitor::NetworkReachabilityMonitor(QObject *parent)
|
|||||||
: QObject{parent}
|
: QObject{parent}
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if defined(Q_OS_IOS)
|
||||||
|
setupIOS();
|
||||||
|
#endif
|
||||||
|
|
||||||
m_networkConfigManager = new QNetworkConfigurationManager(this);
|
m_networkConfigManager = new QNetworkConfigurationManager(this);
|
||||||
|
|
||||||
QObject::connect(m_networkConfigManager, &QNetworkConfigurationManager::configurationAdded, this, [this](const QNetworkConfiguration &config){
|
QObject::connect(m_networkConfigManager, &QNetworkConfigurationManager::configurationAdded, this, [this](const QNetworkConfiguration &config){
|
||||||
@ -40,18 +44,16 @@ NymeaConnection::BearerTypes NetworkReachabilityMonitor::availableBearerTypes()
|
|||||||
|
|
||||||
void NetworkReachabilityMonitor::updateActiveBearers()
|
void NetworkReachabilityMonitor::updateActiveBearers()
|
||||||
{
|
{
|
||||||
|
// NOTE: The Qt API is not working at all on iOS, we're using the iOS reachability API instead.
|
||||||
|
#if defined(Q_OS_IOS)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
NymeaConnection::BearerTypes availableBearerTypes;
|
NymeaConnection::BearerTypes availableBearerTypes;
|
||||||
QList<QNetworkConfiguration> configs = m_networkConfigManager->allConfigurations(QNetworkConfiguration::Active);
|
QList<QNetworkConfiguration> configs = m_networkConfigManager->allConfigurations(QNetworkConfiguration::Active);
|
||||||
qCDebug(dcNymeaConnection()) << "Network configuations:" << configs.count();
|
qCDebug(dcNymeaConnection()) << "Network configuations:" << configs.count();
|
||||||
foreach (const QNetworkConfiguration &config, configs) {
|
foreach (const QNetworkConfiguration &config, configs) {
|
||||||
qCDebug(dcNymeaConnection()) << "Active network config:" << config.name() << config.bearerTypeFamily() << config.bearerTypeName();
|
qCDebug(dcNymeaConnection()) << "Active network config:" << config.name() << config.bearerTypeFamily() << config.bearerTypeName();
|
||||||
|
|
||||||
// NOTE: iOS doesn't correctly report bearer types. It'll be Unknown all the time. Let's hardcode it to WiFi for that...
|
|
||||||
#if defined(Q_OS_IOS)
|
|
||||||
availableBearerTypes.setFlag(NymeaConnection::BearerTypeWiFi);
|
|
||||||
#else
|
|
||||||
availableBearerTypes.setFlag(qBearerTypeToNymeaBearerType(config.bearerType()));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (availableBearerTypes == NymeaConnection::BearerTypeNone) {
|
if (availableBearerTypes == NymeaConnection::BearerTypeNone) {
|
||||||
// This is just debug info... On some platform bearer management seems a bit broken, so let's get some infos right away...
|
// This is just debug info... On some platform bearer management seems a bit broken, so let's get some infos right away...
|
||||||
@ -76,7 +78,7 @@ void NetworkReachabilityMonitor::updateActiveBearers()
|
|||||||
emit availableBearerTypesUpdated();
|
emit availableBearerTypesUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
NymeaConnection::BearerType NetworkReachabilityMonitor::qBearerTypeToNymeaBearerType(QNetworkConfiguration::BearerType type) const
|
NymeaConnection::BearerType NetworkReachabilityMonitor::qBearerTypeToNymeaBearerType(QNetworkConfiguration::BearerType type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case QNetworkConfiguration::BearerUnknown:
|
case QNetworkConfiguration::BearerUnknown:
|
||||||
|
|||||||
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
#include "nymeaconnection.h"
|
#include "nymeaconnection.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
#import <SystemConfiguration/SystemConfiguration.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
class NetworkReachabilityMonitor : public QObject
|
class NetworkReachabilityMonitor : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -22,13 +26,18 @@ signals:
|
|||||||
private slots:
|
private slots:
|
||||||
void updateActiveBearers();
|
void updateActiveBearers();
|
||||||
|
|
||||||
private:
|
|
||||||
NymeaConnection::BearerType qBearerTypeToNymeaBearerType(QNetworkConfiguration::BearerType type) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QNetworkConfigurationManager *m_networkConfigManager = nullptr;
|
QNetworkConfigurationManager *m_networkConfigManager = nullptr;
|
||||||
NymeaConnection::BearerTypes m_availableBearerTypes = NymeaConnection::BearerTypeNone;
|
NymeaConnection::BearerTypes m_availableBearerTypes = NymeaConnection::BearerTypeNone;
|
||||||
|
|
||||||
|
static NymeaConnection::BearerType qBearerTypeToNymeaBearerType(QNetworkConfiguration::BearerType type);
|
||||||
|
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
void setupIOS();
|
||||||
|
SCNetworkReachabilityRef _reachabilityRef;
|
||||||
|
static NymeaConnection::BearerType flagsToBearerType(SCNetworkReachabilityFlags flags);
|
||||||
|
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NETWORKREACHABILITYMONITOR_H
|
#endif // NETWORKREACHABILITYMONITOR_H
|
||||||
|
|||||||
103
libnymea-app/connection/networkreachabilitymonitorios.mm
Normal file
103
libnymea-app/connection/networkreachabilitymonitorios.mm
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#include "networkreachabilitymonitor.h"
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <SystemConfiguration/SystemConfiguration.h>
|
||||||
|
#import <netinet/in.h>
|
||||||
|
#import <arpa/inet.h>
|
||||||
|
#import <ifaddrs.h>
|
||||||
|
#import <netdb.h>
|
||||||
|
#import <sys/socket.h>
|
||||||
|
#import <netinet/in.h>
|
||||||
|
#import <CoreFoundation/CoreFoundation.h>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
void NetworkReachabilityMonitor::ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
|
||||||
|
{
|
||||||
|
#pragma unused (target, flags)
|
||||||
|
NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
|
||||||
|
|
||||||
|
NetworkReachabilityMonitor* thiz = (__bridge NetworkReachabilityMonitor *)info;
|
||||||
|
// Post a notification to notify the client that the network reachability changed.
|
||||||
|
qCritical() << "******* network reachability changed";
|
||||||
|
NymeaConnection::BearerTypes old = thiz->m_availableBearerTypes;
|
||||||
|
thiz->m_availableBearerTypes = flagsToBearerType(flags);
|
||||||
|
if (thiz->m_availableBearerTypes != old) {
|
||||||
|
emit thiz->availableBearerTypesChanged();
|
||||||
|
}
|
||||||
|
emit thiz->availableBearerTypesUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkReachabilityMonitor::setupIOS()
|
||||||
|
{
|
||||||
|
struct sockaddr_in zeroAddress;
|
||||||
|
bzero(&zeroAddress, sizeof(zeroAddress));
|
||||||
|
zeroAddress.sin_len = sizeof(zeroAddress);
|
||||||
|
zeroAddress.sin_family = AF_INET;
|
||||||
|
|
||||||
|
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress);
|
||||||
|
if (reachability != NULL) {
|
||||||
|
_reachabilityRef = reachability;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCNetworkReachabilityContext context = {0, (__bridge void *)(this), NULL, NULL, NULL};
|
||||||
|
qCritical() << "Registering callback";
|
||||||
|
if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context)) {
|
||||||
|
qCritical() << "Callback registered";
|
||||||
|
if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
|
||||||
|
qCritical() << "******* reachability callback set up";
|
||||||
|
} else {
|
||||||
|
qCritical() << "******** Error setting up reachability callback";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SCNetworkReachabilityFlags flags;
|
||||||
|
|
||||||
|
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) {
|
||||||
|
m_availableBearerTypes = flagsToBearerType(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: unregister
|
||||||
|
// SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NymeaConnection::BearerType NetworkReachabilityMonitor::flagsToBearerType(SCNetworkReachabilityFlags flags)
|
||||||
|
{
|
||||||
|
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) {
|
||||||
|
return NymeaConnection::BearerTypeNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) {
|
||||||
|
/*
|
||||||
|
If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
|
||||||
|
*/
|
||||||
|
return NymeaConnection::BearerTypeWiFi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
|
||||||
|
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) {
|
||||||
|
/*
|
||||||
|
... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
... and no [user] intervention is needed...
|
||||||
|
*/
|
||||||
|
return NymeaConnection::BearerTypeWiFi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
|
||||||
|
*/
|
||||||
|
return NymeaConnection::BearerTypeMobileData;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NymeaConnection::BearerTypeNone;
|
||||||
|
}
|
||||||
@ -55,6 +55,14 @@ NymeaConnection::NymeaConnection(QObject *parent) : QObject(parent)
|
|||||||
connect(m_networkReachabilityMonitor, &NetworkReachabilityMonitor::availableBearerTypesChanged, this, &NymeaConnection::availableBearerTypesChanged);
|
connect(m_networkReachabilityMonitor, &NetworkReachabilityMonitor::availableBearerTypesChanged, this, &NymeaConnection::availableBearerTypesChanged);
|
||||||
connect(m_networkReachabilityMonitor, &NetworkReachabilityMonitor::availableBearerTypesUpdated, this, &NymeaConnection::onAvailableBearerTypesUpdated);
|
connect(m_networkReachabilityMonitor, &NetworkReachabilityMonitor::availableBearerTypesUpdated, this, &NymeaConnection::onAvailableBearerTypesUpdated);
|
||||||
|
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
connect(m_networkReachabilityMonitor, &NetworkReachabilityMonitor::availableBearerTypesChanged, this, [this](){
|
||||||
|
if (m_currentTransport) {
|
||||||
|
m_currentTransport->disconnect();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
QGuiApplication *app = static_cast<QGuiApplication*>(QGuiApplication::instance());
|
QGuiApplication *app = static_cast<QGuiApplication*>(QGuiApplication::instance());
|
||||||
QObject::connect(app, &QGuiApplication::applicationStateChanged, this, [app, this](Qt::ApplicationState state) {
|
QObject::connect(app, &QGuiApplication::applicationStateChanged, this, [app, this](Qt::ApplicationState state) {
|
||||||
qCDebug(dcNymeaConnection()) << "Application state changed to:" << state;
|
qCDebug(dcNymeaConnection()) << "Application state changed to:" << state;
|
||||||
|
|||||||
@ -358,3 +358,7 @@ ubports: {
|
|||||||
android: {
|
android: {
|
||||||
DESTDIR = $${ANDROID_TARGET_ARCH}
|
DESTDIR = $${ANDROID_TARGET_ARCH}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ios: {
|
||||||
|
OBJECTIVE_SOURCES += $${PWD}/connection/networkreachabilitymonitorios.mm
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user