
一. 引言
在每个新的iOS APP 开发中可能会遇到一个令人困扰的小问题:
用户首次进入到需要请求网络的页面,会弹出网络授权弹窗,但是授权之后当前页面却仍然是空白。
当然了也不是每个人都会遇到,有些APP集成的三方SDK会把这些问题自动处理掉了,现象就是当你刚刚一启动APP的时候就出现了网络请求弹窗,你点击同意之后才进入APP得首页或者登录页,这时候已经获取到了网络权限,当然就不需要处理。但是如果是一款很干净,流程很清晰的APP通常会遇到上面的问题。
今天我们就来详细聊一聊这个问题的原因,并给出一个更优雅的可落地的解决方案,而不是启动APP假装先发起一个没用的请求。
二. 为什么会发生?
原理很简单:
1. iOS 没有"网络权限回调"
系统弹窗只是控制蜂窝网络访问权限,App 无法直接获知用户点击了允许还是拒绝。
2.请求失败原因
当弹窗存在时,首次网络请求被阻塞或失败。
总结来说就是:
当我们首次进行网络请求的时候才会弹出弹窗,而弹窗弹出时就表示该次请求已经失败了。
不管是在UIKit中还是SwiftUI中都避免不了的会遇到这个问题。
三. 解决办法
系统并没有给我们直接的授权弹窗点击回调,那么该如何解决呢?
我们可以直接通过监听网络状态,也就是说 我们可以通过监听网络变化,在用户允许网络请求后再开始重新触发请求。但需要注意,当我们已经监听到APP获取到网络权限后,一般需要停止监听,以避免反复请求。当然了也有很多其它方案,只要可以避免重复请求就可以。
监听网络状态常用的有三种方式:
- 原生 NWPathMonitor(iOS 12+)
- Alamofire 的 NetworkReachabilityManager
- AFNetworking 的 Reachability
我们就以 NWPathMonitor 和 NetworkReachabilityManager为例。
3.1 原生 NWPathMonitor
使用起来非常简单,导入Network,在需要的页面直接监听网络状态,代码实现如下:
Swift
import Network
let monitor = NWPathMonitor()
let queue = DispatchQueue(label: "NetworkMonitor")
monitor.pathUpdateHandler = { path in
if path.status == .satisfied {
print(" 网络可用,执行请求")
// TODO: 在这里重新发起请求
monitor.stop()
}
}
monitor.start(queue: queue)
当用户允许蜂窝数据后,path.status 会变为 .satisfied,我们可以在这里触发第一次请求并停止监听。
3.2 Alamofire 网络状态监听
Alamofire 内部在 iOS 12+ 已经用 NWPathMonitor 实现监听,只是为它包装了一层,使用代码如下:
Swift
import Alamofire
NetworkReachabilityManager()?.startListening { status in
switch status {
case .reachable(.ethernetOrWiFi), .reachable(.cellular):
print(" 网络可用,执行请求")
// TODO: 在这里重新发起请求
default: break
}
}
3.3 在SwiftUI实际项目中解决问题
在实际项目当中,通常我们会有一个专门负责网络请求的类,我们可以将该功能封装到此类之下,比如有一个PHNetwork类负责网络请求,我们以 Alamofire 为例代码实现如下:
Swift
/// 监听网络恢复可用后回调
/// - Parameter completion: 网络可用时回调
static func onNetworkAvailable(_ completion: @escaping () -> Void) {
let reachabilityManager = NetworkReachabilityManager()
reachabilityManager?.startListening(onUpdatePerforming: { status in
switch status {
case .reachable(.ethernetOrWiFi), .reachable(.cellular):
completion()
reachabilityManager?.stopListening()
default:
break
}
})
}
我们在这里定义了一个类方法,当监听到网络数据可用后,直接停止监听。
接下来我们就需要在APP首次请求网络的地方使用这个方法,比如我们在发现页会首次进行网络请求,那么就在它的onAppear()方法下开始进行网络监听。
Swift
var body: some View {
ZStack(alignment: .top) {
....
}
.navigationTitle("发现")
.onAppear() {
monitorNetwork()
fetchDramaList()
}
}
Swift
/// 网络监听
private func monitorNetwork() {
if isNetworkAvailable {
return
}
PHNetwork.onNetworkAvailable {
isNetworkAvailable = true
fetchDramaList()
}
}
获取到网络之后,再次调用fetchDramaList()方法来获取列表数据。
四. 结语
首个网络请求失败的问题,看似小,却在许多新 App 的用户体验中留下过坑。其实它的本质在网络本身,而在于系统机制与开发者预期之间的差异。理解了这个机制,我们就能主动设计更友好的请求策略:在用户授权后自动重试,让 App 更加稳健、自然,也更贴近真实的使用节奏。
希望这篇文章能让你在面对类似问题时,不再手足无措,而是胸有成竹。