fix(player): nie twórz playera, gdy apka jest w tle
expo-video wola w init konstruktora VideoPlayer bezwarunkowy startService dla androidx.media3 MediaSessionService (VideoPlayer.kt:233), a Android od 8.0 zabrania startu zwyklego serwisu z tla. Gdy ekran playera montowal sie juz w tle (user wyszedl w trakcie resolve albo system wznowil stos ekranow), konstruktor rzucal IllegalStateException i zamiast wideo pokazywal sie ekran bledu. GOON-12: 63 wystapienia, 28 osob, wszystkie z in_foreground=false. Konfiguracja tego nie wylacza, wiec bramkujemy montowanie: hooka nie da sie warunkowac, stad wlasciwy ekran wyjechal do PlayerScreenActive, a eksportowany PlayerScreen czeka na AppState 'active'. Bramka dziala tylko przy montowaniu, wiec zejscie w tlo z juz dzialajacym playerem nie przerywa odtwarzania. Opublikowane OTA na 1.2 i 1.1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
544de9c5ba
commit
b4c1216133
2 changed files with 48 additions and 0 deletions
|
|
@ -16,6 +16,13 @@ export type ChangelogEntry = {
|
|||
};
|
||||
|
||||
export const CHANGELOG: ChangelogEntry[] = [
|
||||
{
|
||||
id: '2026-08-20b',
|
||||
date: 'August 2026',
|
||||
items: [
|
||||
'Fixed a crash that replaced the video with an error screen. If you left the app while a scene was still opening, or Android restored the player by itself, the player refused to start. It now waits until the app is back on screen and then plays normally.',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '2026-08-20',
|
||||
date: 'August 2026',
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import {
|
|||
ActivityIndicator,
|
||||
Alert,
|
||||
Animated,
|
||||
AppState,
|
||||
LayoutChangeEvent,
|
||||
Pressable,
|
||||
StatusBar,
|
||||
|
|
@ -133,7 +134,47 @@ function detectMode(url: string): 'video' | 'webview' {
|
|||
return 'video';
|
||||
}
|
||||
|
||||
/** Bramka na konstruowanie playera.
|
||||
*
|
||||
* `new VideoPlayer(...)` w expo-video BEZWARUNKOWO wola w `init` startService dla
|
||||
* androidx.media3 MediaSessionService (VideoPlayer.kt:233), a Android od 8.0 zabrania
|
||||
* startu zwyklego serwisu z tla. Efekt: gdy ekran playera zamontuje sie, kiedy apka
|
||||
* jest juz w tle (user wyszedl w trakcie resolve albo system wznowil stos ekranow),
|
||||
* konstruktor rzuca IllegalStateException i uzytkownik dostaje ekran bledu zamiast
|
||||
* wideo. GOON-12: 63 wystapienia, 28 osob, wszystkie z in_foreground=false.
|
||||
*
|
||||
* Nie da sie tego wylaczyc konfiguracja, wiec po prostu nie tworzymy playera, dopoki
|
||||
* nie jestesmy na wierzchu. Hookow nie da sie warunkowac, stad osobny komponent.
|
||||
* Bramka dziala TYLKO przy montowaniu: gdy player juz istnieje, zejscie w tlo jest
|
||||
* bezpieczne (serwis jest zbindowany) i odtwarzania nie przerywamy.
|
||||
*/
|
||||
export function PlayerScreen() {
|
||||
const [foreground, setForeground] = React.useState(
|
||||
() => AppState.currentState === 'active',
|
||||
);
|
||||
React.useEffect(() => {
|
||||
if (foreground) return;
|
||||
const sub = AppState.addEventListener('change', (next) => {
|
||||
if (next === 'active') setForeground(true);
|
||||
});
|
||||
return () => sub.remove();
|
||||
}, [foreground]);
|
||||
|
||||
if (!foreground) {
|
||||
return (
|
||||
<View style={gateStyles.wait}>
|
||||
<ActivityIndicator color="#fff" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
return <PlayerScreenActive />;
|
||||
}
|
||||
|
||||
const gateStyles = StyleSheet.create({
|
||||
wait: { flex: 1, backgroundColor: '#000', alignItems: 'center', justifyContent: 'center' },
|
||||
});
|
||||
|
||||
function PlayerScreenActive() {
|
||||
const route = useRoute<RouteProp<RootStackParamList, 'Player'>>();
|
||||
const params = route.params as RouteParams;
|
||||
const mode = params.mode ?? detectMode(params.url);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue