diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index 43204345f55a80669312c9aed48dbb708b50b84a..bbfb5aa45f36229ce75c3c04b0ff1b465cee8171 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -375,20 +375,6 @@ static NSMutableDictionary *callFlags;
     _state = GRXWriterStateStarted;
   }
 
-  // Create a retain cycle so that this instance lives until the RPC finishes (or is cancelled).
-  // This makes RPCs in which the call isn't externally retained possible (as long as it is started
-  // before being autoreleased).
-  // Care is taken not to retain self strongly in any of the blocks used in this implementation, so
-  // that the life of the instance is determined by this retain cycle.
-  _retainSelf = self;
-
-  _responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
-
-  _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path];
-  NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?");
-
-  [self sendHeaders:_requestHeaders];
-  [self invokeCall];
   // TODO(jcanizales): Extract this logic somewhere common.
   NSString *host = [NSURL URLWithString:[@"https://" stringByAppendingString:_host]].host;
   if (!host) {
@@ -397,15 +383,35 @@ static NSMutableDictionary *callFlags;
   }
   __weak typeof(self) weakSelf = self;
   _connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host];
-  [_connectivityMonitor handleLossWithHandler:^{
+  void (^handler)() = ^{
     typeof(self) strongSelf = weakSelf;
     if (strongSelf) {
       [strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
                                                       code:GRPCErrorCodeUnavailable
                                                   userInfo:@{NSLocalizedDescriptionKey: @"Connectivity lost."}]];
-      [[GRPCHost hostWithAddress:strongSelf->_host] disconnect];
     }
-  }];
+  };
+  [_connectivityMonitor handleLossWithHandler:handler
+                      wifiStatusChangeHandler:handler];
+
+  // Create a retain cycle so that this instance lives until the RPC finishes
+  // (or is cancelled).
+  // This makes RPCs in which the call isn't externally retained possible (as
+  // long as it is started
+  // before being autoreleased).
+  // Care is taken not to retain self strongly in any of the blocks used in this
+  // implementation, so
+  // that the life of the instance is determined by this retain cycle.
+  _retainSelf = self;
+
+  _responseWriteable =
+      [[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
+
+  _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path];
+  NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?");
+
+  [self sendHeaders:_requestHeaders];
+  [self invokeCall];
 }
 
 - (void)setState:(GRXWriterState)newState {
diff --git a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
index 2fae410331517e9739964683402706fd6f1e1e65..8d5c1b3e68aff30cba90aa374ab5d3c13705e39a 100644
--- a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
+++ b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
@@ -73,5 +73,6 @@
  * Only one handler is active at a time, so if this method is called again before the previous
  * handler has been called, it might never be called at all (or yes, if it has already been queued).
  */
-- (void)handleLossWithHandler:(nonnull void (^)())handler;
+- (void)handleLossWithHandler:(void (^)())handler
+      wifiStatusChangeHandler:(void (^)())wifiStatusChangeHandler;
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
index b4061bd5ef52e5100c75c00b15d948cadda1bbc3..d736c5e6b037e1582b64263f6bbd920c49967ef4 100644
--- a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
+++ b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
@@ -120,6 +120,7 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
 
 @implementation GRPCConnectivityMonitor {
   SCNetworkReachabilityRef _reachabilityRef;
+  GRPCReachabilityFlags *_previousReachabilityFlags;
 }
 
 - (nullable instancetype)initWithReachability:(nullable SCNetworkReachabilityRef)reachability {
@@ -129,6 +130,13 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
   if ((self = [super init])) {
     _reachabilityRef = CFRetain(reachability);
     _queue = dispatch_get_main_queue();
+    SCNetworkReachabilityFlags flags;
+    if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) {
+      _previousReachabilityFlags =
+          [[GRPCReachabilityFlags alloc] initWithFlags:flags];
+    } else {
+      _previousReachabilityFlags = 0;
+    }
   }
   return self;
 }
@@ -149,11 +157,16 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
   return returnValue;
 }
 
-- (void)handleLossWithHandler:(void (^)())handler {
+- (void)handleLossWithHandler:(void (^)())handler
+      wifiStatusChangeHandler:(nonnull void (^)())wifiStatusChangeHandler {
   [self startListeningWithHandler:^(GRPCReachabilityFlags *flags) {
-    if (!flags.isHostReachable) {
+    if (!flags.reachable && handler) {
       handler();
+    } else if (flags.isWWAN ^ _previousReachabilityFlags.isWWAN &&
+               wifiStatusChangeHandler) {
+      wifiStatusChangeHandler();
     }
+    _previousReachabilityFlags = flags;
   }];
 }
 
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index f8634b448e9d9ada50c4bb37fde26a90d16489ad..ee6045653e9433b57f41c544b563679f6aca3a4c 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -43,6 +43,7 @@
 
 #import "GRPCChannel.h"
 #import "GRPCCompletionQueue.h"
+#import "GRPCConnectivityMonitor.h"
 #import "NSDictionary+GRPC.h"
 
 NS_ASSUME_NONNULL_BEGIN
@@ -52,6 +53,7 @@ NS_ASSUME_NONNULL_BEGIN
 #define GRPC_OBJC_VERSION_STRING @"1.0.0"
 
 static NSMutableDictionary *kHostCache;
+static GRPCConnectivityMonitor *connectivityMonitor = nil;
 
 @implementation GRPCHost {
   // TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
@@ -98,6 +100,16 @@ static NSMutableDictionary *kHostCache;
       _address = address;
       _secure = YES;
       kHostCache[address] = self;
+
+      if (!connectivityMonitor) {
+        connectivityMonitor =
+            [GRPCConnectivityMonitor monitorWithHost:hostURL.host];
+        void (^handler)() = ^{
+          [GRPCHost flushChannelCache];
+        };
+        [connectivityMonitor handleLossWithHandler:handler
+                           wifiStatusChangeHandler:handler];
+      }
     }
   }
   return self;
@@ -110,6 +122,7 @@ static NSMutableDictionary *kHostCache;
                                                     BOOL * _Nonnull stop) {
       [host disconnect];
     }];
+    connectivityMonitor = nil;
   }
 }
 
diff --git a/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h b/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
index 4b92504b555378e1d1ac2d7fa5c403ab7036a838..1c907877a0e03d8eadf4a0a8dfe8047a5f3312af 100644
--- a/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
+++ b/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
@@ -65,3 +65,4 @@ GRPC_XMACRO_ITEM(interventionRequired, InterventionRequired)
 GRPC_XMACRO_ITEM(connectionOnDemand, ConnectionOnDemand)
 GRPC_XMACRO_ITEM(isLocalAddress, IsLocalAddress)
 GRPC_XMACRO_ITEM(isDirect, IsDirect)
+GRPC_XMACRO_ITEM(isWWAN, IsWWAN)
diff --git a/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj b/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj
index 2a9466c03f11e8183720c6520d4919b174c51a66..3f26c98564863c193938fafb91cd5f59d81c6e34 100644
--- a/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj
@@ -156,7 +156,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n    cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n    exit 1\nfi\n";
+			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n";
 			showEnvVarsInLog = 0;
 		};
 		5347BF6C41E7888C1C05CD88 /* [CP] Copy Pods Resources */ = {