You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift实现仿Teams悬浮通话窗口:支持最大化与最小化

iOS 实现全局悬浮通话窗口(类似Microsoft Teams)

可以实现这种全局悬浮的通话窗口功能,iOS平台有两种主流技术方案,分别对应不同的自定义需求:

方案一:系统原生画中画(Picture in Picture)框架(官方推荐)

这是iOS为视频通话/媒体播放场景提供的原生悬浮方案,天然支持在主屏幕和其他应用上方显示,步骤如下:

  1. 配置权限:
    • 在Info.plist中添加UIBackgroundModes并勾选voip,确保应用后台通话时保持活跃
    • 添加NSPictureInPictureUsageDescription,说明画中画功能的用途
  2. 集成AVKit框架实现PiP:
    将你的视频通话视图包装为AVPlayerLayer,通过AVPictureInPictureController启动悬浮模式:
    import AVKit
    
    // 初始化PiP控制器(yourVideoPlayerLayer为你的视频画面层)
    guard let pipController = try? AVPictureInPictureController(playerLayer: yourVideoPlayerLayer) else {
        return
    }
    pipController.delegate = self
    
    // 用户点击最小化时启动PiP
    if pipController.isPictureInPictureSupported {
        pipController.startPictureInPicture()
    }
    
  3. 自定义交互:通过实现AVPictureInPictureControllerDelegate协议,处理PiP状态切换事件,比如从悬浮窗切回应用全屏。

优点:系统原生支持,无需复杂的后台状态管理,兼容性好;缺点:悬浮窗样式受系统限制,自定义程度较低。

方案二:自定义全局悬浮窗口(基于UIWindow+VOIP后台权限)

如果需要完全自定义悬浮窗的样式、大小和拖拽交互(和Teams的效果完全匹配),可以采用这种方案:

  1. 配置后台权限:
    • 开启VOIP后台模式(同方案一),同时集成PushKit接收VOIP推送,确保应用在后台不会被系统杀死
  2. 创建自定义悬浮窗口:
    class FloatingCallWindow: UIWindow {
        private let callView = CallCustomView(frame: CGRect(x: 0, y: 0, width: 160, height: 220))
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            windowLevel = .alert + 1 // 设置窗口级别高于系统弹窗
            backgroundColor = .clear
            addSubview(callView)
            // 添加拖拽手势
            let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
            addGestureRecognizer(panGesture)
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        @objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
            let translation = gesture.translation(in: self)
            center = CGPoint(x: center.x + translation.x, y: center.y + translation.y)
            gesture.setTranslation(.zero, in: self)
        }
    }
    
  3. 在SceneDelegate中管理窗口生命周期:
    class SceneDelegate: UIResponder, UIWindowSceneDelegate {
        var window: UIWindow?
        private var floatingWindow: FloatingCallWindow?
    
        func sceneDidEnterBackground(_ scene: UIScene) {
            // 进入后台时显示悬浮窗
            guard let windowScene = scene as? UIWindowScene else { return }
            floatingWindow = FloatingCallWindow(frame: CGRect(x: 40, y: 120, width: 160, height: 220))
            floatingWindow?.windowScene = windowScene
            floatingWindow?.isHidden = false
        }
    
        func sceneWillEnterForeground(_ scene: UIScene) {
            // 回到前台时隐藏悬浮窗,切换回主通话界面
            floatingWindow?.isHidden = true
            floatingWindow = nil
        }
    }
    
  4. 实现最大化/最小化逻辑:在自定义的CallCustomView中添加按钮,点击时调整悬浮窗的frame大小,或者切换回主应用的全屏界面。

优点:完全自定义样式和交互,完美匹配Teams的功能;缺点:需要严格维护后台活跃状态,否则应用可能被系统回收,开发成本更高。

关键注意事项

  • 必须遵守iOS后台规则:VOIP应用需通过PushKit接收推送,不能仅依赖后台模式保持活跃
  • 自定义悬浮窗的尺寸不能过大,避免被系统判定为违规
  • 所有功能需在真机上测试,模拟器对后台窗口和PiP的支持有限

内容的提问来源于stack exchange,提问作者Asad Farooq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 01:55:15