Проблемы с полноэкранным режимом видеоплеера WebView, ориентацией и синхронизацией истории просмотра во Flutter (webviewIOS

Программируем под IOS
Ответить
Anonymous
 Проблемы с полноэкранным режимом видеоплеера WebView, ориентацией и синхронизацией истории просмотра во Flutter (webview

Сообщение Anonymous »

Описание проблемы
Я создаю полноэкранный видеоплеер во Flutter, используя webview_flutter: ^4.13.0. Игрок должен:
  • Запустить непосредственно в альбомном режиме
  • Скрыть полноэкранную кнопку WebView по умолчанию
  • Отслеживать время воспроизведения (currentTime и длительность) из JavaScript.
  • Сохранять историю просмотра (время паузы, процент завершения и т. д.)
  • Восстанавливать воспроизведение, когда пользователь возвращается
  • Безопасный выход из полноэкранного режима и восстановление наложений пользовательского интерфейса
  • Предотвращение множественного выхода вызовы
В основном всё работает, но код усложнился. Я хочу убедиться, что:
  • Мой подход правильный
  • Я не оставляю утечек памяти (интервалы, блокировки ориентации, очистка WebView)
  • Я правильно использую WebView API для отслеживания хода видео
  • Логика _handleSafeExit верна как для Android, так и для iOS.
  • Внедрение JavaScript с полноэкранной блокировкой безопасно.
Ниже приведен полный код с пояснениями по разделам. Я добавил комментарии перед каждым разделом, чтобы прояснить, что делает код.

1. Виджет VideoPlayerScreen
class VideoPlayerScreen extends StatefulWidget {
final String streamUrl;
final String videoId;
final String videoType;
final String? watchHistoryId;
final String? savedPauseTime;

const VideoPlayerScreen({
required this.streamUrl,
required this.videoId,
required this.videoType,
this.watchHistoryId,
this.savedPauseTime,
super.key,
});

@override
State createState() => _VideoPlayerScreenState();
}


2. Настройка WebView
Загружает URL-адрес потока, подключает прослушиватель JavaScript и отслеживает ход выполнения.
void _setupVideoPlayer() {
final controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel('flutterVideoPlayer', onMessageReceived: _onJsMessage)
..setNavigationDelegate(NavigationDelegate(onPageFinished: _onPageLoaded))
..loadRequest(Uri.parse(widget.streamUrl));

setState(() {
_controller = controller;
_isControllerReady = true;
});
}


3. Внедрите JavaScript, чтобы отключить полноэкранную кнопку
Встроенный iframe имеет собственный полноэкранный пользовательский интерфейс, поэтому мы скрываем его:
void _hideFullscreenButton() {
_controller.runJavaScript("""
// JS that hides fullscreen button on video element
""");
}


4. Синхронизируйте продолжительность и текущее время с помощью JS → Flutter Bridge
addJavaScriptChannel(
'flutterVideoPlayer',
onMessageReceived: (message) {
final data = json.decode(message.message);
setState(() {
_currentTime = (data['currentTime'] ?? 0).toDouble();
_duration = (data['duration'] ?? 0).toDouble();
});
},
);


5. Логика сохранения истории просмотра
Обновляет время паузы, общую продолжительность и процент завершения:
Future _handleWatchHistory() async {
if (_currentWatchHistoryId != null) {
...
await _videoPlayerAPI.addPauseTime(...);
await _videoPlayerAPI.updateCompletionPercentage(...);
}
}


6. Безопасный выход
Гарантирует отсутствие двойного нажатия и восстанавливает ориентацию/пользовательский интерфейс:
Future _handleSafeExit() async {
if (_isDisposed) return;
_isDisposed = true;

await SystemChrome.setEnabledSystemUIMode(...);
await SystemChrome.setPreferredOrientations([...]);

unawaited(_handleWatchHistory());

if (mounted) Navigator.of(context).pop();
}


7. Dispose
Очищает таймеры, интервалы JS, ориентацию и контроллер WebView:
@override
void dispose() {
_isDisposed = true;
_hideTimer?.cancel();

_controller.runJavaScript(
'if (window.__videoInterval) clearInterval(window.__videoInterval);'
);

SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual);
_controller.clearCache();

super.dispose();
}


Актуальная проблема/вопросы
Код работает нормально на Android, но на iOS он полностью приводит к сбою приложения.
Мои основные вопросы:
  • Правильно ли это отслеживать прогресс видео внутри WebView с помощью JavaScript?
  • Это мой метод блокировать полноэкранные кнопки безопасно и надежно?
  • Правильно ли написан _handleSafeExit() для предотвращения множественных всплывающих окон?
  • Правильно ли я управляю ориентацией и системным пользовательским интерфейсом?
  • Правильна ли очистка удаления для интервалов WebView и JS?
Если какая-либо часть может быть оптимизирована или небезопасна, укажите это.
Вот для справки функция истории просмотра:
Future _handleWatchHistory() async {
if (_currentWatchHistoryId != null) {
...
await _videoPlayerAPI.addPauseTime(...);
await _videoPlayerAPI.updateCompletionPercentage(...);
}
}


Подробнее здесь: https://stackoverflow.com/questions/798 ... es-in-flut
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»