mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Use NSPathMonitor instead of Reachability to monitor network connectivity
This commit is contained in:
parent
c6270f78f1
commit
fb05647d97
@ -1,20 +1,14 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
objc_library(
|
swift_library(
|
||||||
name = "Reachability",
|
name = "Reachability",
|
||||||
enable_modules = True,
|
|
||||||
module_name = "Reachability",
|
module_name = "Reachability",
|
||||||
srcs = glob([
|
srcs = glob([
|
||||||
"Sources/*.m",
|
"Sources/**/*.swift",
|
||||||
]),
|
]),
|
||||||
hdrs = glob([
|
deps = [
|
||||||
"PublicHeaders/**/*.h",
|
"//submodules/Reachability/LegacyReachability:LegacyReachability",
|
||||||
]),
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||||
includes = [
|
|
||||||
"PublicHeaders",
|
|
||||||
],
|
|
||||||
sdk_frameworks = [
|
|
||||||
"Foundation",
|
|
||||||
"SystemConfiguration",
|
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
22
submodules/Reachability/LegacyReachability/BUILD
Normal file
22
submodules/Reachability/LegacyReachability/BUILD
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
objc_library(
|
||||||
|
name = "LegacyReachability",
|
||||||
|
enable_modules = True,
|
||||||
|
module_name = "LegacyReachability",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/*.m",
|
||||||
|
]),
|
||||||
|
hdrs = glob([
|
||||||
|
"PublicHeaders/**/*.h",
|
||||||
|
]),
|
||||||
|
includes = [
|
||||||
|
"PublicHeaders",
|
||||||
|
],
|
||||||
|
sdk_frameworks = [
|
||||||
|
"Foundation",
|
||||||
|
"SystemConfiguration",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
@ -24,7 +24,7 @@ typedef enum : NSInteger {
|
|||||||
extern NSString *kReachabilityChangedNotification;
|
extern NSString *kReachabilityChangedNotification;
|
||||||
|
|
||||||
|
|
||||||
@interface Reachability : NSObject
|
@interface LegacyReachability : NSObject
|
||||||
|
|
||||||
@property (nonatomic, copy) void (^reachabilityChanged)(NetworkStatus status);
|
@property (nonatomic, copy) void (^reachabilityChanged)(NetworkStatus status);
|
||||||
|
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#import <CoreFoundation/CoreFoundation.h>
|
#import <CoreFoundation/CoreFoundation.h>
|
||||||
|
|
||||||
#import <Reachability/Reachability.h>
|
#import <LegacyReachability/LegacyReachability.h>
|
||||||
|
|
||||||
#import <pthread.h>
|
#import <pthread.h>
|
||||||
#import <libkern/OSAtomic.h>
|
#import <libkern/OSAtomic.h>
|
||||||
@ -126,14 +126,14 @@ static ReachabilityAtomic *contexts() {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void withContext(int32_t key, void (^f)(Reachability *)) {
|
static void withContext(int32_t key, void (^f)(LegacyReachability *)) {
|
||||||
Reachability *reachability = [contexts() with:^id(NSDictionary *dict) {
|
LegacyReachability *reachability = [contexts() with:^id(NSDictionary *dict) {
|
||||||
return dict[@(key)];
|
return dict[@(key)];
|
||||||
}];
|
}];
|
||||||
f(reachability);
|
f(reachability);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t addContext(Reachability *context) {
|
static int32_t addContext(LegacyReachability *context) {
|
||||||
int32_t key = OSAtomicIncrement32(&nextKey);
|
int32_t key = OSAtomicIncrement32(&nextKey);
|
||||||
[contexts() modify:^id(NSMutableDictionary *dict) {
|
[contexts() modify:^id(NSMutableDictionary *dict) {
|
||||||
NSMutableDictionary *updatedDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
|
NSMutableDictionary *updatedDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
|
||||||
@ -155,19 +155,19 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
|||||||
{
|
{
|
||||||
#pragma unused (target, flags)
|
#pragma unused (target, flags)
|
||||||
//NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
|
//NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
|
||||||
//NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
|
//NSCAssert([(__bridge NSObject*) info isKindOfClass: [LegacyReachability class]], @"info was wrong class in ReachabilityCallback");
|
||||||
|
|
||||||
int32_t key = (int32_t)((intptr_t)info);
|
int32_t key = (int32_t)((intptr_t)info);
|
||||||
withContext(key, ^(Reachability *context) {
|
withContext(key, ^(LegacyReachability *context) {
|
||||||
if ([context isKindOfClass:[Reachability class]] && context.reachabilityChanged != nil)
|
if ([context isKindOfClass:[LegacyReachability class]] && context.reachabilityChanged != nil)
|
||||||
context.reachabilityChanged(context.currentReachabilityStatus);
|
context.reachabilityChanged(context.currentReachabilityStatus);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Reachability implementation
|
#pragma mark - LegacyReachability implementation
|
||||||
|
|
||||||
@implementation Reachability
|
@implementation LegacyReachability
|
||||||
{
|
{
|
||||||
int32_t _key;
|
int32_t _key;
|
||||||
SCNetworkReachabilityRef _reachabilityRef;
|
SCNetworkReachabilityRef _reachabilityRef;
|
||||||
@ -175,7 +175,7 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
|||||||
|
|
||||||
+ (instancetype)reachabilityWithHostName:(NSString *)hostName
|
+ (instancetype)reachabilityWithHostName:(NSString *)hostName
|
||||||
{
|
{
|
||||||
Reachability* returnValue = NULL;
|
LegacyReachability* returnValue = NULL;
|
||||||
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
|
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
|
||||||
if (reachability != NULL)
|
if (reachability != NULL)
|
||||||
{
|
{
|
||||||
@ -199,7 +199,7 @@ static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReach
|
|||||||
{
|
{
|
||||||
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
|
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
|
||||||
|
|
||||||
Reachability* returnValue = NULL;
|
LegacyReachability* returnValue = NULL;
|
||||||
|
|
||||||
if (reachability != NULL)
|
if (reachability != NULL)
|
||||||
{
|
{
|
180
submodules/Reachability/Sources/Reachability.swift
Normal file
180
submodules/Reachability/Sources/Reachability.swift
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftSignalKit
|
||||||
|
|
||||||
|
import LegacyReachability
|
||||||
|
import Network
|
||||||
|
|
||||||
|
private final class WrappedLegacyReachability: NSObject {
|
||||||
|
@objc private static func threadImpl() {
|
||||||
|
while true {
|
||||||
|
RunLoop.current.run(until: .distantFuture)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static let thread: Thread = {
|
||||||
|
let thread = Thread(target: Reachability.self, selector: #selector(WrappedLegacyReachability.threadImpl), object: nil)
|
||||||
|
thread.start()
|
||||||
|
return thread
|
||||||
|
}()
|
||||||
|
|
||||||
|
@objc private static func dispatchOnThreadImpl(_ f: @escaping () -> Void) {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func dispatchOnThread(_ f: @escaping @convention(block) () -> Void) {
|
||||||
|
WrappedLegacyReachability.perform(#selector(WrappedLegacyReachability.dispatchOnThreadImpl(_:)), on: WrappedLegacyReachability.thread, with: f, waitUntilDone: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private let reachability: LegacyReachability
|
||||||
|
|
||||||
|
let value: ValuePromise<Reachability.NetworkType>
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
assert(Thread.current === WrappedLegacyReachability.thread)
|
||||||
|
self.reachability = LegacyReachability.forInternetConnection()
|
||||||
|
let type: Reachability.NetworkType
|
||||||
|
switch self.reachability.currentReachabilityStatus() {
|
||||||
|
case NotReachable:
|
||||||
|
type = .none
|
||||||
|
case ReachableViaWiFi:
|
||||||
|
type = .wifi
|
||||||
|
case ReachableViaWWAN:
|
||||||
|
type = .cellular
|
||||||
|
default:
|
||||||
|
type = .none
|
||||||
|
}
|
||||||
|
self.value = ValuePromise<Reachability.NetworkType>(type)
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.reachability.reachabilityChanged = { [weak self] status in
|
||||||
|
WrappedLegacyReachability.dispatchOnThread {
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let internalNetworkType: Reachability.NetworkType
|
||||||
|
switch status {
|
||||||
|
case NotReachable:
|
||||||
|
internalNetworkType = .none
|
||||||
|
case ReachableViaWiFi:
|
||||||
|
internalNetworkType = .wifi
|
||||||
|
case ReachableViaWWAN:
|
||||||
|
internalNetworkType = .cellular
|
||||||
|
default:
|
||||||
|
internalNetworkType = .none
|
||||||
|
}
|
||||||
|
strongSelf.value.set(internalNetworkType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.reachability.startNotifier()
|
||||||
|
}
|
||||||
|
|
||||||
|
private static var valueRef: Unmanaged<WrappedLegacyReachability>?
|
||||||
|
|
||||||
|
static func withInstance(_ f: @escaping (WrappedLegacyReachability) -> Void) {
|
||||||
|
WrappedLegacyReachability.dispatchOnThread {
|
||||||
|
if self.valueRef == nil {
|
||||||
|
self.valueRef = Unmanaged.passRetained(WrappedLegacyReachability())
|
||||||
|
}
|
||||||
|
if let valueRef = self.valueRef {
|
||||||
|
let value = valueRef.takeUnretainedValue()
|
||||||
|
f(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOSApplicationExtension 12.0, iOS 12.0, *)
|
||||||
|
private final class PathMonitor {
|
||||||
|
private let queue: Queue
|
||||||
|
private let monitor: NWPathMonitor
|
||||||
|
|
||||||
|
let networkType = Promise<Reachability.NetworkType>()
|
||||||
|
|
||||||
|
init(queue: Queue) {
|
||||||
|
self.queue = queue
|
||||||
|
self.monitor = NWPathMonitor()
|
||||||
|
|
||||||
|
self.monitor.pathUpdateHandler = { [weak self] path in
|
||||||
|
queue.async {
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let networkType: Reachability.NetworkType
|
||||||
|
if path.status == .satisfied {
|
||||||
|
if path.usesInterfaceType(.cellular) {
|
||||||
|
networkType = .cellular
|
||||||
|
} else {
|
||||||
|
networkType = .wifi
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
networkType = .none
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.networkType.set(.single(networkType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.monitor.start(queue: self.queue.queue)
|
||||||
|
|
||||||
|
let networkType: Reachability.NetworkType
|
||||||
|
let path = self.monitor.currentPath
|
||||||
|
if path.status == .satisfied {
|
||||||
|
if path.usesInterfaceType(.cellular) {
|
||||||
|
networkType = .cellular
|
||||||
|
} else {
|
||||||
|
networkType = .wifi
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
networkType = .none
|
||||||
|
}
|
||||||
|
|
||||||
|
self.networkType.set(.single(networkType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOSApplicationExtension 12.0, iOS 12.0, *)
|
||||||
|
private final class SharedPathMonitor {
|
||||||
|
static let queue = Queue()
|
||||||
|
static let impl = QueueLocalObject<PathMonitor>(queue: queue, generate: {
|
||||||
|
return PathMonitor(queue: queue)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Reachability {
|
||||||
|
public enum NetworkType: Equatable {
|
||||||
|
case none
|
||||||
|
case wifi
|
||||||
|
case cellular
|
||||||
|
}
|
||||||
|
|
||||||
|
public static var networkType: Signal<NetworkType, NoError> {
|
||||||
|
if #available(iOSApplicationExtension 12.0, iOS 12.0, *) {
|
||||||
|
return Signal { subscriber in
|
||||||
|
let disposable = MetaDisposable()
|
||||||
|
|
||||||
|
SharedPathMonitor.impl.with { impl in
|
||||||
|
disposable.set(impl.networkType.get().start(next: { value in
|
||||||
|
subscriber.putNext(value)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
return disposable
|
||||||
|
}
|
||||||
|
|> distinctUntilChanged
|
||||||
|
} else {
|
||||||
|
return Signal { subscriber in
|
||||||
|
let disposable = MetaDisposable()
|
||||||
|
|
||||||
|
WrappedLegacyReachability.withInstance({ impl in
|
||||||
|
disposable.set(impl.value.get().start(next: { next in
|
||||||
|
subscriber.putNext(next)
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
return disposable
|
||||||
|
}
|
||||||
|
|> distinctUntilChanged
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -34,12 +34,6 @@ extension CellularNetworkType {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum InternalNetworkType: Equatable {
|
|
||||||
case none
|
|
||||||
case wifi
|
|
||||||
case cellular
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum NetworkType: Equatable {
|
public enum NetworkType: Equatable {
|
||||||
case none
|
case none
|
||||||
case wifi
|
case wifi
|
||||||
@ -50,7 +44,7 @@ public enum NetworkType: Equatable {
|
|||||||
|
|
||||||
extension NetworkType {
|
extension NetworkType {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
init(internalType: InternalNetworkType, cellularType: CellularNetworkType) {
|
init(internalType: Reachability.NetworkType, cellularType: CellularNetworkType) {
|
||||||
switch internalType {
|
switch internalType {
|
||||||
case .none:
|
case .none:
|
||||||
self = .none
|
self = .none
|
||||||
@ -61,7 +55,7 @@ extension NetworkType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
init(internalType: InternalNetworkType) {
|
init(internalType: Reachability.NetworkType) {
|
||||||
switch internalType {
|
switch internalType {
|
||||||
case .none:
|
case .none:
|
||||||
self = .none
|
self = .none
|
||||||
@ -72,91 +66,11 @@ extension NetworkType {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class WrappedReachability: NSObject {
|
|
||||||
@objc private static func threadImpl() {
|
|
||||||
while true {
|
|
||||||
RunLoop.current.run(until: .distantFuture)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static let thread: Thread = {
|
|
||||||
let thread = Thread(target: WrappedReachability.self, selector: #selector(WrappedReachability.threadImpl), object: nil)
|
|
||||||
thread.start()
|
|
||||||
return thread
|
|
||||||
}()
|
|
||||||
|
|
||||||
@objc private static func dispatchOnThreadImpl(_ f: @escaping () -> Void) {
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func dispatchOnThread(_ f: @escaping @convention(block) () -> Void) {
|
|
||||||
WrappedReachability.perform(#selector(WrappedReachability.dispatchOnThreadImpl(_:)), on: WrappedReachability.thread, with: f, waitUntilDone: false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private let reachability: Reachability
|
|
||||||
|
|
||||||
let value: ValuePromise<InternalNetworkType>
|
|
||||||
|
|
||||||
override init() {
|
|
||||||
assert(Thread.current === WrappedReachability.thread)
|
|
||||||
self.reachability = Reachability.forInternetConnection()
|
|
||||||
let type: InternalNetworkType
|
|
||||||
switch self.reachability.currentReachabilityStatus() {
|
|
||||||
case NotReachable:
|
|
||||||
type = .none
|
|
||||||
case ReachableViaWiFi:
|
|
||||||
type = .wifi
|
|
||||||
case ReachableViaWWAN:
|
|
||||||
type = .cellular
|
|
||||||
default:
|
|
||||||
type = .none
|
|
||||||
}
|
|
||||||
self.value = ValuePromise<InternalNetworkType>(type)
|
|
||||||
|
|
||||||
super.init()
|
|
||||||
|
|
||||||
self.reachability.reachabilityChanged = { [weak self] status in
|
|
||||||
WrappedReachability.dispatchOnThread {
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let internalNetworkType: InternalNetworkType
|
|
||||||
switch status {
|
|
||||||
case NotReachable:
|
|
||||||
internalNetworkType = .none
|
|
||||||
case ReachableViaWiFi:
|
|
||||||
internalNetworkType = .wifi
|
|
||||||
case ReachableViaWWAN:
|
|
||||||
internalNetworkType = .cellular
|
|
||||||
default:
|
|
||||||
internalNetworkType = .none
|
|
||||||
}
|
|
||||||
strongSelf.value.set(internalNetworkType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.reachability.startNotifier()
|
|
||||||
}
|
|
||||||
|
|
||||||
static var valueRef: Unmanaged<WrappedReachability>?
|
|
||||||
|
|
||||||
static func withInstance(_ f: @escaping (WrappedReachability) -> Void) {
|
|
||||||
WrappedReachability.dispatchOnThread {
|
|
||||||
if self.valueRef == nil {
|
|
||||||
self.valueRef = Unmanaged.passRetained(WrappedReachability())
|
|
||||||
}
|
|
||||||
if let valueRef = self.valueRef {
|
|
||||||
let value = valueRef.takeUnretainedValue()
|
|
||||||
f(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class NetworkTypeManagerImpl {
|
private final class NetworkTypeManagerImpl {
|
||||||
let queue: Queue
|
let queue: Queue
|
||||||
let updated: (NetworkType) -> Void
|
let updated: (NetworkType) -> Void
|
||||||
var networkTypeDisposable: Disposable?
|
var networkTypeDisposable: Disposable?
|
||||||
var currentNetworkType: InternalNetworkType?
|
var currentNetworkType: Reachability.NetworkType?
|
||||||
var networkType: NetworkType?
|
var networkType: NetworkType?
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
var currentCellularType: CellularNetworkType
|
var currentCellularType: CellularNetworkType
|
||||||
@ -197,9 +111,8 @@ private final class NetworkTypeManagerImpl {
|
|||||||
let networkTypeDisposable = MetaDisposable()
|
let networkTypeDisposable = MetaDisposable()
|
||||||
self.networkTypeDisposable = networkTypeDisposable
|
self.networkTypeDisposable = networkTypeDisposable
|
||||||
|
|
||||||
WrappedReachability.withInstance({ [weak self] impl in
|
networkTypeDisposable.set((Reachability.networkType
|
||||||
networkTypeDisposable.set((impl.value.get()
|
|> deliverOn(queue)).start(next: { [weak self] networkStatus in
|
||||||
|> deliverOn(queue)).start(next: { networkStatus in
|
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -218,7 +131,6 @@ private final class NetworkTypeManagerImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func stop() {
|
func stop() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user