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

iOS 18下RealityKit的VideoMaterial显示粉色条纹,iOS17正常如何修复?

iOS 18中RealityKit VideoMaterial渲染粉色条纹问题修复

问题背景

在iOS 17上正常运行的RealityKit视频屏幕代码,到iOS 18中出现粉色条纹渲染(苹果工程师提示这是材质未正确应用的表现)。视频屏幕基于ARImageAnchor锚定,使用AVPlayer和VideoMaterial实现,但所有基础验证(URL正确性、Player初始化、播放状态)均无问题。

复现步骤

  • 创建平面作为视频载体
  • 通过AVPlayerItem为平面应用VideoMaterial
  • 将模型实体锚定到ARImageAnchor

预期结果

视频正常渲染在RealityKit平面上并播放

实际结果

iOS 18中平面显示粉色条纹,VideoMaterial未生效

iOS 18相关行为变化分析

iOS 18对RealityKit与AVFoundation的交互逻辑做了更严格的校验,主要影响点包括:

  1. VideoMaterial绑定时机:iOS 18要求VideoMaterial初始化时,关联的AVPlayer必须已持有就绪状态的AVPlayerItem,否则会触发缺失材质的默认粉色渲染
  2. AVPlayer生命周期管理:对未就绪Player的弱引用处理更严格,若Player在绑定材质时无有效内容,RealityKit会直接放弃材质加载
  3. Notification监听有效性:原代码中监听player.currentItem的播放结束通知,当Player替换Item后,旧观察者会失效,导致视频无法循环,但这不是粉色条纹的直接原因

修复方案

针对上述变化,对代码做以下调整:

1. 确保AVPlayer初始化时已绑定就绪的AVPlayerItem

修改createVideoMaterial方法,直接用已准备好的AVPlayerItem初始化AVPlayer,避免先创建空Player再替换Item:

private func createVideoMaterial(with videoItem: AVPlayerItem, uuid: UUID) -> VideoMaterial {
    // 直接用就绪的AVPlayerItem初始化Player
    let player = AVPlayer(playerItem: videoItem)
    player.actionAtItemEnd = .none
    
    // 确保Player有有效内容后再创建VideoMaterial
    let videoMaterial = VideoMaterial(avPlayer: player)
    player.play()
    
    // 修正通知监听:直接绑定传入的videoItem,避免后续Item替换导致监听失效
    NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, 
                                           object: videoItem, 
                                           queue: .main) { [weak player] _ in
        guard let player = player else { return }
        player.seek(to: .zero)
        player.play()
    }
    
    videoPlayers[uuid] = player
    return videoMaterial
}

2. 等待AVAsset加载完成后再创建AVPlayerItem

iOS 18对未加载完成的Asset兼容性下降,需确保AVAsset处于可播放状态后再生成AVPlayerItem:

// 修改为异步方法,确保Asset加载完成
private func createVideoItem(with url: URL, completion: @escaping (AVPlayerItem?) -> Void) {
    let asset = AVURLAsset(url: url)
    // 加载必要的资源键,确保Asset可播放
    let requiredKeys = ["playable", "tracks"]
    
    asset.loadValuesAsynchronously(forKeys: requiredKeys) {
        var loadError: NSError?
        defer {
            DispatchQueue.main.async {
                if loadError != nil {
                    completion(nil)
                } else {
                    completion(AVPlayerItem(asset: asset))
                }
            }
        }
        
        // 校验所有必要资源是否加载完成
        for key in requiredKeys {
            guard asset.statusOfValue(forKey: key, error: &loadError) == .loaded else {
                return
            }
        }
    }
}

3. 调整视频屏幕创建流程为异步

对应createVideoScreen方法,改为异步调用确保PlayerItem就绪:

private func createVideoScreen(width: Float, height: Float, url: URL, uuid: UUID, completion: @escaping (ModelEntity?) -> Void) {
    let screenMesh = MeshResource.generatePlane(width: width, height: height)
    
    createVideoItem(with: url) { [weak self] videoItem in
        guard let self = self, let videoItem = videoItem else {
            completion(nil)
            return
        }
        let videoMaterial = self.createVideoMaterial(with: videoItem, uuid: uuid)
        let videoScreenModel = ModelEntity(mesh: screenMesh, materials: [videoMaterial])
        completion(videoScreenModel)
    }
}

4. 调用时适配异步逻辑

在placeVideoScreen前,先异步创建视频屏幕:

// 示例调用
createVideoScreen(width: 1.0, height: 0.5, url: videoURL, uuid: videoUUID) { [weak self] videoScreen in
    guard let self = self, let videoScreen = videoScreen, let imageAnchor = imageAnchor else { return }
    self.placeVideoScreen(videoScreen: videoScreen, imageAnchor: imageAnchor, uuid: videoUUID)
}

关键修复点总结

  • 确保VideoMaterial绑定的AVPlayer在初始化时已持有就绪状态的AVPlayerItem
  • 异步等待AVAsset加载完成,避免使用未就绪的资源创建PlayerItem
  • 修正Notification监听对象,保证视频循环逻辑的有效性
  • 维持对AVPlayer的强引用(通过videoPlayers字典),防止Player被提前释放

内容的提问来源于stack exchange,提问作者Joao Ponte

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 21:35:19