Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2017 Google
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#import <Foundation/Foundation.h>
16
 
17
#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h"
18
 
19
#import "GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h"
20
#import "GoogleUtilities/Reachability/GULReachabilityMessageCode.h"
21
 
22
#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h"
23
 
24
static GULLoggerService kGULLoggerReachability = @"[GULReachability]";
25
#if !TARGET_OS_WATCH
26
static void ReachabilityCallback(SCNetworkReachabilityRef reachability,
27
                                 SCNetworkReachabilityFlags flags,
28
                                 void *info);
29
 
30
static const struct GULReachabilityApi kGULDefaultReachabilityApi = {
31
    SCNetworkReachabilityCreateWithName,
32
    SCNetworkReachabilitySetCallback,
33
    SCNetworkReachabilityScheduleWithRunLoop,
34
    SCNetworkReachabilityUnscheduleFromRunLoop,
35
    CFRelease,
36
};
37
 
38
static NSString *const kGULReachabilityUnknownStatus = @"Unknown";
39
static NSString *const kGULReachabilityConnectedStatus = @"Connected";
40
static NSString *const kGULReachabilityDisconnectedStatus = @"Disconnected";
41
#endif
42
@interface GULReachabilityChecker ()
43
 
44
@property(nonatomic, assign) const struct GULReachabilityApi *reachabilityApi;
45
@property(nonatomic, assign) GULReachabilityStatus reachabilityStatus;
46
@property(nonatomic, copy) NSString *host;
47
#if !TARGET_OS_WATCH
48
@property(nonatomic, assign) SCNetworkReachabilityRef reachability;
49
#endif
50
 
51
@end
52
 
53
@implementation GULReachabilityChecker
54
 
55
@synthesize reachabilityApi = reachabilityApi_;
56
#if !TARGET_OS_WATCH
57
@synthesize reachability = reachability_;
58
#endif
59
 
60
- (const struct GULReachabilityApi *)reachabilityApi {
61
  return reachabilityApi_;
62
}
63
 
64
- (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi {
65
#if !TARGET_OS_WATCH
66
  if (reachability_) {
67
    GULLogError(kGULLoggerReachability, NO,
68
                [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode000],
69
                @"Cannot change reachability API while reachability is running. "
70
                @"Call stop first.");
71
    return;
72
  }
73
  reachabilityApi_ = reachabilityApi;
74
#endif
75
}
76
 
77
@synthesize reachabilityStatus = reachabilityStatus_;
78
@synthesize host = host_;
79
@synthesize reachabilityDelegate = reachabilityDelegate_;
80
 
81
- (BOOL)isActive {
82
#if !TARGET_OS_WATCH
83
  return reachability_ != nil;
84
#else
85
  return NO;
86
#endif
87
}
88
 
89
- (void)setReachabilityDelegate:(id<GULReachabilityDelegate>)reachabilityDelegate {
90
  if (reachabilityDelegate &&
91
      (![(NSObject *)reachabilityDelegate conformsToProtocol:@protocol(GULReachabilityDelegate)])) {
92
    GULLogError(kGULLoggerReachability, NO,
93
                [NSString stringWithFormat:@"I-NET%06ld", (long)kGULReachabilityMessageCode005],
94
                @"Reachability delegate doesn't conform to Reachability protocol.");
95
    return;
96
  }
97
  reachabilityDelegate_ = reachabilityDelegate;
98
}
99
 
100
- (instancetype)initWithReachabilityDelegate:(id<GULReachabilityDelegate>)reachabilityDelegate
101
                                    withHost:(NSString *)host {
102
  self = [super init];
103
 
104
  if (!host || !host.length) {
105
    GULLogError(kGULLoggerReachability, NO,
106
                [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode001],
107
                @"Invalid host specified");
108
    return nil;
109
  }
110
  if (self) {
111
#if !TARGET_OS_WATCH
112
    [self setReachabilityDelegate:reachabilityDelegate];
113
    reachabilityApi_ = &kGULDefaultReachabilityApi;
114
    reachabilityStatus_ = kGULReachabilityUnknown;
115
    host_ = [host copy];
116
    reachability_ = nil;
117
#endif
118
  }
119
  return self;
120
}
121
 
122
- (void)dealloc {
123
  reachabilityDelegate_ = nil;
124
  [self stop];
125
}
126
 
127
- (BOOL)start {
128
#if TARGET_OS_WATCH
129
  return NO;
130
#else
131
 
132
  if (!reachability_) {
133
    reachability_ = reachabilityApi_->createWithNameFn(kCFAllocatorDefault, [host_ UTF8String]);
134
    if (!reachability_) {
135
      return NO;
136
    }
137
    SCNetworkReachabilityContext context = {
138
        0,                       /* version */
139
        (__bridge void *)(self), /* info (passed as last parameter to reachability callback) */
140
        NULL,                    /* retain */
141
        NULL,                    /* release */
142
        NULL                     /* copyDescription */
143
    };
144
    if (!reachabilityApi_->setCallbackFn(reachability_, ReachabilityCallback, &context) ||
145
        !reachabilityApi_->scheduleWithRunLoopFn(reachability_, CFRunLoopGetMain(),
146
                                                 kCFRunLoopCommonModes)) {
147
      reachabilityApi_->releaseFn(reachability_);
148
      reachability_ = nil;
149
 
150
      GULLogError(kGULLoggerReachability, NO,
151
                  [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode002],
152
                  @"Failed to start reachability handle");
153
      return NO;
154
    }
155
  }
156
  GULLogDebug(kGULLoggerReachability, NO,
157
              [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode003],
158
              @"Monitoring the network status");
159
  return YES;
160
#endif
161
}
162
 
163
- (void)stop {
164
#if !TARGET_OS_WATCH
165
  if (reachability_) {
166
    reachabilityStatus_ = kGULReachabilityUnknown;
167
    reachabilityApi_->unscheduleFromRunLoopFn(reachability_, CFRunLoopGetMain(),
168
                                              kCFRunLoopCommonModes);
169
    reachabilityApi_->releaseFn(reachability_);
170
    reachability_ = nil;
171
  }
172
#endif
173
}
174
 
175
#if !TARGET_OS_WATCH
176
- (GULReachabilityStatus)statusForFlags:(SCNetworkReachabilityFlags)flags {
177
  GULReachabilityStatus status = kGULReachabilityNotReachable;
178
  // If the Reachable flag is not set, we definitely don't have connectivity.
179
  if (flags & kSCNetworkReachabilityFlagsReachable) {
180
    // Reachable flag is set. Check further flags.
181
    if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired)) {
182
// Connection required flag is not set, so we have connectivity.
183
#if TARGET_OS_IOS || TARGET_OS_TV
184
      status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular
185
                                                           : kGULReachabilityViaWifi;
186
#elif TARGET_OS_OSX
187
      status = kGULReachabilityViaWifi;
188
#endif
189
    } else if ((flags & (kSCNetworkReachabilityFlagsConnectionOnDemand |
190
                         kSCNetworkReachabilityFlagsConnectionOnTraffic)) &&
191
               !(flags & kSCNetworkReachabilityFlagsInterventionRequired)) {
192
// If the connection on demand or connection on traffic flag is set, and user intervention
193
// is not required, we have connectivity.
194
#if TARGET_OS_IOS || TARGET_OS_TV
195
      status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular
196
                                                           : kGULReachabilityViaWifi;
197
#elif TARGET_OS_OSX
198
      status = kGULReachabilityViaWifi;
199
#endif
200
    }
201
  }
202
  return status;
203
}
204
 
205
- (void)reachabilityFlagsChanged:(SCNetworkReachabilityFlags)flags {
206
  GULReachabilityStatus status = [self statusForFlags:flags];
207
  if (reachabilityStatus_ != status) {
208
    NSString *reachabilityStatusString;
209
    if (status == kGULReachabilityUnknown) {
210
      reachabilityStatusString = kGULReachabilityUnknownStatus;
211
    } else {
212
      reachabilityStatusString = (status == kGULReachabilityNotReachable)
213
                                     ? kGULReachabilityDisconnectedStatus
214
                                     : kGULReachabilityConnectedStatus;
215
    }
216
 
217
    GULLogDebug(kGULLoggerReachability, NO,
218
                [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode004],
219
                @"Network status has changed. Code:%@, status:%@", @(status),
220
                reachabilityStatusString);
221
    reachabilityStatus_ = status;
222
    [reachabilityDelegate_ reachability:self statusChanged:reachabilityStatus_];
223
  }
224
}
225
 
226
#endif
227
@end
228
 
229
#if !TARGET_OS_WATCH
230
static void ReachabilityCallback(SCNetworkReachabilityRef reachability,
231
                                 SCNetworkReachabilityFlags flags,
232
                                 void *info) {
233
  GULReachabilityChecker *checker = (__bridge GULReachabilityChecker *)info;
234
  [checker reachabilityFlagsChanged:flags];
235
}
236
#endif
237
 
238
// This function used to be at the top of the file, but it was moved here
239
// as a workaround for a suspected compiler bug. When compiled in Release mode
240
// and run on an iOS device with WiFi disabled, the reachability code crashed
241
// when calling SCNetworkReachabilityScheduleWithRunLoop, or shortly thereafter.
242
// After unsuccessfully trying to diagnose the cause of the crash, it was
243
// discovered that moving this function to the end of the file magically fixed
244
// the crash. If you are going to edit this file, exercise caution and make sure
245
// to test thoroughly with an iOS device under various network conditions.
246
const NSString *GULReachabilityStatusString(GULReachabilityStatus status) {
247
  switch (status) {
248
    case kGULReachabilityUnknown:
249
      return @"Reachability Unknown";
250
 
251
    case kGULReachabilityNotReachable:
252
      return @"Not reachable";
253
 
254
    case kGULReachabilityViaWifi:
255
      return @"Reachable via Wifi";
256
 
257
    case kGULReachabilityViaCellular:
258
      return @"Reachable via Cellular Data";
259
 
260
    default:
261
      return [NSString stringWithFormat:@"Invalid reachability status %d", (int)status];
262
  }
263
}