feat: native Android audio via Media3 ExoPlayer + full NSBridge JS adapter
- Replace legacy MediaBrowserServiceCompat/MediaSessionCompat with
Media3 MediaSessionService (MusicService.kt) + ExoPlayer set to
WAKE_MODE_NETWORK — holds WakeLock + WifiLock through Doze so audio
plays uninterrupted on locked screen
- Media3 manages the notification; no manual NotificationCompat.Builder
→ no disappear/reappear flicker when skipping tracks
- Full bidirectional bridge:
JS → native: window.NSBridge.* (WebBridge.kt, 13 methods)
Native → JS: window.NSPlayer.* callbacks (onReady, onTrackChanged,
onPositionUpdate, onPlaybackStateChanged, onQueueEnded, onError)
- player.js: progressive enhancement — all playback routes through
NSBridge when running inside the wrapper, falls back to S.audio on
plain PWA/browser; removes all window.Android.* calls
- main.js: guard _onForeground mediaSession playbackState setter behind
!window.NSBridge so native Media3 session is never stomped
- ProGuard rules updated to keep WebBridge @JavascriptInterface methods
and Media3 classes
- bridge-test.html: manual integration test page for every bridge method
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
1ede8727a2
commit
0e17d2e5db
15 files changed
+1093
-95
No files matched your search
+5
-3
@@ -166,10 +166,12 @@ window.addEventListener('load', () => {
|
||||
const s = S.queue[S.qIdx];
|
||||
if(!s) return;
|
||||
updateMediaSession(s);
|
||||
// Don't stomp playbackState during a src-swap — _trackChanging guards the transition
|
||||
if(navigator.mediaSession && !S._trackChanging)
|
||||
// Don't stomp playbackState during a src-swap — _trackChanging guards the transition.
|
||||
// Skip when native is active: Media3 owns the system media session.
|
||||
if(navigator.mediaSession && !S._trackChanging && !window.NSBridge)
|
||||
navigator.mediaSession.playbackState = S.audio.paused ? 'paused' : 'playing';
|
||||
// If audio was playing before backgrounding but is now paused (OS kill), try to resume
|
||||
// If audio was playing before backgrounding but is now paused (OS kill), try to resume.
|
||||
// No-op when native (S.audio.src is empty; native handles its own recovery).
|
||||
if(!S.audio.paused) return;
|
||||
if(s && S.audio.src) S.audio.play().catch(() => { S._trackChanging = false; });
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user