This commit is contained in:
Samuele Giacomin 2026-11-03 17:49:44 +01:00 committed by GitHub
commit 897a66d983
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 109 additions and 4 deletions

88
.github/workflows/ios-cloud-verify.yml vendored Normal file
View File

@ -0,0 +1,88 @@
name: iOS cloud verification
on:
workflow_dispatch:
inputs:
ref:
description: Branch or commit to verify
required: true
default: ios-background-playback
jobs:
build-ios:
runs-on: macos-latest
timeout-minutes: 120
steps:
- name: Checkout Spotube
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref }}
- name: Checkout ComposeNativeWebview
uses: actions/checkout@v4
with:
repository: KRTirtho/ComposeNativeWebview
ref: cbd36f88927298a28a2d64c6acf7ec3b2def6f9d
path: compose-webview
- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- name: Set up Ruby and CocoaPods
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: false
- name: Install CocoaPods
run: gem install cocoapods
- name: Set up Rust
uses: dtolnay/rust-toolchain@stable
- name: Publish ComposeNativeWebview
working-directory: compose-webview
run: |
chmod +x gradlew
./gradlew publishToMavenLocal
- name: Compile Kotlin/Native iOS
run: |
chmod +x gradlew
./gradlew :composeApp:compileKotlinIosSimulatorArm64
- name: Install CocoaPods dependencies
run: |
cd iosApp
pod install --repo-update
- name: Build unsigned iOS app
run: |
xcodebuild \
-workspace iosApp/iosApp.xcworkspace \
-scheme iosApp \
-configuration Release \
-sdk iphoneos \
-destination 'generic/platform=iOS' \
-derivedDataPath build/ios \
CODE_SIGNING_ALLOWED=NO \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGN_IDENTITY="" \
DEVELOPMENT_TEAM="" \
build
- name: Package unsigned IPA
run: |
app=$(find build/ios/Build/Products/Release-iphoneos -maxdepth 1 -name '*.app' -type d | head -1)
mkdir Payload
cp -R "$app" Payload/
zip -qry Spotube-ios-unsigned.ipa Payload
- name: Upload IPA
uses: actions/upload-artifact@v4
with:
name: spotube-ios-unsigned
path: Spotube-ios-unsigned.ipa

View File

@ -36,6 +36,7 @@ final class VlcPlayerEngineFactory: NSObject, NativePlayerEngineFactory {
/// Every VLC call is made on the main queue, in the order the Kotlin side issued it. /// Every VLC call is made on the main queue, in the order the Kotlin side issued it.
final class VlcPlayerEngine: NSObject, NativePlayerEngine, VLCMediaPlayerDelegate { final class VlcPlayerEngine: NSObject, NativePlayerEngine, VLCMediaPlayerDelegate {
private let player = VLCMediaPlayer() private let player = VLCMediaPlayer()
private let audioSession = AVAudioSession.sharedInstance()
private var listener: NativePlayerListener? private var listener: NativePlayerListener?
private var released = false private var released = false
@ -47,7 +48,6 @@ final class VlcPlayerEngine: NSObject, NativePlayerEngine, VLCMediaPlayerDelegat
override init() { override init() {
super.init() super.init()
player.delegate = self player.delegate = self
try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
} }
// MARK: NativePlayerEngine // MARK: NativePlayerEngine
@ -70,6 +70,7 @@ final class VlcPlayerEngine: NSObject, NativePlayerEngine, VLCMediaPlayerDelegat
} }
self.lastReportedDurationMs = 0 self.lastReportedDurationMs = 0
self.player.media = media self.player.media = media
self.applyPlaybackSettings()
self.report(.opening) self.report(.opening)
if autoPlay { self.startPlayback() } if autoPlay { self.startPlayback() }
} }
@ -121,11 +122,15 @@ final class VlcPlayerEngine: NSObject, NativePlayerEngine, VLCMediaPlayerDelegat
onMain { onMain {
guard !self.released else { return } guard !self.released else { return }
self.released = true self.released = true
self.listener = nil
self.player.delegate = nil self.player.delegate = nil
self.player.stop() self.player.stop()
self.player.media = nil self.player.media = nil
try? AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation) do {
try self.audioSession.setActive(false, options: .notifyOthersOnDeactivation)
} catch {
self.listener?.onError(message: "Could not deactivate audio session: \(error.localizedDescription)")
}
self.listener = nil
} }
} }
@ -172,7 +177,19 @@ final class VlcPlayerEngine: NSObject, NativePlayerEngine, VLCMediaPlayerDelegat
// MARK: Internals // MARK: Internals
private func startPlayback() { private func startPlayback() {
try? AVAudioSession.sharedInstance().setActive(true) do {
try audioSession.setCategory(.playback, mode: .default, options: [])
} catch {
listener?.onError(message: "Could not configure audio session: \(error.localizedDescription)")
return
}
do {
try audioSession.setActive(true)
} catch {
listener?.onError(message: "Could not activate audio session: \(error.localizedDescription)")
return
}
applyPlaybackSettings()
player.play() player.play()
} }