Reputation: 330
I'm trying to control the volume of the Apple Watch itself in code from SwiftUI.
I'm streaming audio using the AVPlayer
.
Is there an API to set the Volume of the Watch or use to Digital Crown to control the volume without
volume
property on the AVPlayer
. This just set the volume relative to the system volume. So if the system is muted it does not increase the volume.WKInterfaceVolumeControl
. This does the job, but it can not be sized does and takes a lot of space on the small screen.Upvotes: 5
Views: 3034
Reputation: 11
leoMehlig's answer works for me as is, but I noticed the embedded WKInterfaceVolumeControl was losing focus when I would tap anywhere on the watch screen.
This was because I had a .focusable(true)
modifier in the view hierarchy, so any view being tapped further up in the hierarchy would keep the focus.
I had added the .focusable(true)
when I was trying to bind AVPlayer.volume
to the digital crown rotation, it was no longer needed when using WKInterfaceVolumeControl
Upvotes: 0
Reputation: 58149
leoMehlig's answer only works for me if I add a bit of delay and resign the focus before focusing for the first time.
So, speaking in code, I changed this:
DispatchQueue.main.async {
view.focus()
}
to this:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
view.resignFocus()
view.focus()
}
Upvotes: 1
Reputation: 330
The workaround I ended up with was this:
WKInterfaceVolumeControl
to use it in SwiftUIstruct VolumeView: WKInterfaceObjectRepresentable {
typealias WKInterfaceObjectType = WKInterfaceVolumeControl
func makeWKInterfaceObject(context: Self.Context) -> WKInterfaceVolumeControl {
let view = WKInterfaceVolumeControl(origin: .local)
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak view] timer in
if let view = view {
view.focus()
} else {
timer.invalidate()
}
}
DispatchQueue.main.async {
view.focus()
}
return view
}
func updateWKInterfaceObject(_ wkInterfaceObject: WKInterfaceVolumeControl, context: WKInterfaceObjectRepresentableContext<VolumeView>) {
}
}
VolumeView
to the view hierarchy with opacity = 0
. .background(VolumeView().opacity(0))
volumeObserver = AVAudioSession.sharedInstance().observe(\.outputVolume) { session, _ in
print("Output volume: \(session.outputVolume)")
self.volume = Double(session.outputVolume)
}
With that you can update some other view, but keep in mind that especially on older what's the update does not always happen (immediately).
Upvotes: 9