我正在为 Apple Watch 编写一个扩展,旨在通过一系列步骤引导用户。我没有手表来测试扩展,但我需要确保在完成所有步骤之前屏幕将始终保持打开状态。
有谁能告诉我 Apple Watch 显示屏何时关闭,或者是否有任何方法可以防止显示屏关闭(类似于 iOS 中 UIApplication 的 idleTimerDisabled)?
目前没有办法以编程方式阻止显示被关闭。否则,我们可以推测,只要用户与您的应用进行交互,屏幕就会一直亮着。最坏的情况是,当应用程序暂停时,您将收到一个 didDeactivate 消息,而当用户唤醒它继续运行时,您将收到一个 willActivate 消息(假设 Watch 应用程序未在其间终止)。
从 watchOS 4 开始,您可以使用此布尔值来保持显示,这将在转动手臂时旋转 UI。
https://developer.apple.com/documentation/watchkit/wkextension/2868464-isautorotating
考虑
HKWorkout
.
确保您的应用在用户查看手表时出现
https://developer.apple.com/documentation/healthkit/workouts_and_activity_rings
自从我构建了类似于 Apple 的 Mindfulness 应用程序后,我很好奇他们是如何做到的。然后我注意到有一些东西看起来像正在播放的视频。所以我开始尝试播放视频并且它有效 - 显示没有关闭。
重点是,你需要使用原生
VideoPlayer
然后在loop中播放视频。很棒的是,这个视图甚至不必是可见的,所以你可以将它放在背景中,不透明度几乎为零。
let audioURL = Bundle.main.url(forResource: "video", withExtension: "mp4")
...
let player = AVPlayer(url: audioURL)
...
.background(
VideoPlayer(player: player)
.opacity(0)
)
然后你只需要确保你循环播放视频。您可以通过在一段时间(例如 1 秒)后将玩家搜索到开头来实现此目的。这也使您可以拥有不占用太多空间的小视频文件。
private var avPlayerPlayTask: Task<Void, Never>?
...
func startAVPlayerPlayTask() {
avPlayerPlayTask?.cancel()
avPlayerPlayTask = Task {
await player.seek(to: .zero)
player.play()
try? await Task.sleep(nanoseconds: UInt64(1 * 1_000_000_000))
guard !Task.isCancelled else { return }
startAVPlayerPlayTask()
}
最后一件事。一旦您在需要时离开屏幕,请不要忘记取消任务并停止播放器,因为让播放器一直播放在电池效率方面可能会很重。
完整的工作代码(不要忘记创建一些名为
video
的短视频并将其添加到包中):
struct PlayerView: View {
@ObservedObject var viewModel: PlayerViewModel
var body: some View {
Text("Hello World!")
.background(
VideoPlayer(player: viewModel.player)
.opacity(0)
)
.onAppear { viewModel.handleAppear() }
.onDisappear { viewModel.handleDisappear() }
}
}
@MainActor final class PlayerViewModel: ObservableObject {
var player = AVPlayer()
func handleAppear() {
guard let url = Bundle.main.url(forResource: "video", withExtension: "mp4") else { return }
player.replaceCurrentItem(with: AVPlayerItem(url: url))
startAVPlayerPlayTask()
}
func handleDisappear() {
avPlayerPlayTask?.cancel()
player.replaceCurrentItem(with: nil)
}
private var avPlayerPlayTask: Task<Void, Never>?
private func startAVPlayerPlayTask() {
avPlayerPlayTask?.cancel()
avPlayerPlayTask = Task {
await player.seek(to: .zero)
player.play()
try? await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
guard !Task.isCancelled else { return }
startAVPlayerPlayTask()
}
}
}