Я реализую компонент Video для воспроизведения звука:
import React, {Component} from 'react';
import {StyleSheet, View,} from 'react-native';
import Video from 'react-native-video';
export default class App extends Component {
render() {
return (
<View style = {styles.container}>
<Video source = {require('./cats.mp3')}
ref = {(ref) => {
this.player = ref
}}
playInBackground = {true}
playWhenInactive = {true}
onBuffer = {this.onBuffer}
onEnd = {this.onEnd}
onError = {this.videoError}
/>
</View>
);
}
}
При запуске на физическом устройстве (Pixel 2 8.1.0) и выходе из приложения в фоновом режиме воспроизведение звука останавливается через 3-10 минут и приложение вылетает. Воспроизведение можно возобновить, только перезапустив приложение. Проблема появляется только тогда, когда к устройству не подключен кабель питания. Когда есть внешнее питание, приложение работает как положено.
Я вытащил это из журнала:
ActivityManager: Killing 20894:com.videotest/u0a419 (adj 700): excessive cpu 53130 during 300068 dur=1762444 limit=2
Похоже, Android отклоняет приложение из-за неправильного использования процессора? Что может быть решением, чтобы заставить ОС разрешать этому приложению работать без перебоев, как это происходит при наличии внешнего источника питания?
реагировать на родную версию: 0.57 версия реакции-нативного видео: 3.2.1
Я только что ответил на этот вопрос о проблемах с исходным видео здесь и скопирую его сюда.
================================================== =======
Мне удалось решить эту проблему, по крайней мере, для моего варианта использования, следуя рекомендациям ExoPlayer FAQ для фонового звука: https://google.github.io/ExoPlayer/faqs.html#how-do-i-keep-audio-playing-when-my-app-is-backgounded:
How do I keep audio playing when my app is backgrounded?
There are a few steps that you need to take to ensure continued playback of audio when your app is in the background:
- You need to have a running foreground service. This prevents the system from killing your process to free up resources.
- You need to hold a WifiLock and a WakeLock. These ensure that the system keeps the WiFi radio and CPU awake.
It’s important that you stop the service and release the locks as soon as audio is no longer being played.
Чтобы реализовать wakelock и wifilock в RN, я добавил этот пакет: "react-native-wakeful": "^ 0.1.0"
Чтобы реализовать службу переднего плана в RN, я добавил этот пакет: "@ voximplant / react-native-foreground-service": "^ 1.1.0"
Обязательно обновите AndroidManifest.xml, как описано в README для этих двух пакетов.
В этом демонстрационном репозитории App.js есть наглядный пример использования службы переднего плана: https://github.com/voximplant/react-native-foreground-service-demo/blob/master/App.js:
/**
* Copyright (c) 2011-2019, Zingaya, Inc. All rights reserved.
*
* @format
* @flow
* @lint-ignore-every XPLATJSCOPYRIGHT1
*/
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, Button} from 'react-native';
import VIForegroundService from "@voximplant/react-native-foreground-service";
type Props = {};
export default class App extends Component<Props> {
async startService() {
if (Platform.OS !== 'android') {
console.info('Only Android platform is supported');
return;
}
if (Platform.Version >= 26) {
const channelConfig = {
id: 'ForegroundServiceChannel',
name: 'Notification Channel',
description: 'Notification Channel for Foreground Service',
enableVibration: false,
importance: 2
};
await VIForegroundService.createNotificationChannel(channelConfig);
}
const notificationConfig = {
id: 3456,
title: 'Foreground Service',
text: 'Foreground service is running',
icon: 'ic_notification',
priority: 0
};
if (Platform.Version >= 26) {
notificationConfig.channelId = 'ForegroundServiceChannel';
}
await VIForegroundService.startService(notificationConfig);
}
async stopService() {
await VIForegroundService.stopService();
}
render() {
return (
<View style = {styles.container}>
<Button title = "Start foreground service" onPress = {() => this.startService()}/>
<View style = {styles.space}/>
<Button title = "Stop foreground service" onPress = {() => this.stopService()}/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
space: {
flex: 0.1
}
});
Единственное, чего не хватает в этом примере, так это того, что stopService() нуждается в защите с самого начала:
async stopService() {
// Only Android platform is supported
if (Platform.OS !== 'android') {
return;
}
await VIForegroundService.stopService();
}
В моем приложении, когда пользователь нажимает кнопку Play / Pause, я делаю следующее:
// play or pause the player, then.....
if (this.isPaused) {
// release wakelock, wifilock and stop foreground service
wakeful.release();
this.stopService();
} else {
// acquire wakelock, wifilock and start foreground service
wakeful.acquire();
this.startService();
}
wakeful.release() / wakeful.acquire() можно оставить для iOS, поскольку в этом случае они просто не работают.
Если кому-то понадобится помощь, просто дайте мне знать :)