我试着播放从防火墙存储下载的视频,但是当我播放视频时,我会得到这个错误。你能告诉我怎么改进吗?
环境
flutter 2.5.1
dart 2.14.2
video_player 2.2.5
错误
E/flutter (19565): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: PlatformException(channel-error, Unable to establish connection on channel., null, null)
E/flutter (19565): #0 VideoPlayerApi.create (package:video_player_platform_interface/messages.dart:181:7)
E/flutter (19565): <asynchronous suspension>
E/flutter (19565): #1 MethodChannelVideoPlayer.create (package:video_player_platform_interface/method_channel_video_player.dart:50:31)
E/flutter (19565): <asynchronous suspension>
E/flutter (19565): #2 VideoPlayerController.initialize (package:video_player/video_player.dart:329:19)
E/flutter (19565): <asynchronous suspension>
E/flutter (19565):
代码在下面。这几乎是BumbleBeeRemoteVideo的官方例子,我只关注播放器,因为我对从防火墙存储中播放视频感兴趣。
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: public_member_api_docs
/// An example of using the plugin, controlling lifecycle and playback of the
/// video.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
class VideoPlayPage extends StatefulWidget {
@override
_VideoPlayPageState createState() => _VideoPlayPageState();
}
class _VideoPlayPageState extends State<VideoPlayPage> {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
key: const ValueKey<String>('home_page'),
appBar: AppBar(
title: const Text('Video player example'),
actions: <Widget>[
IconButton(
key: const ValueKey<String>('push_tab'),
icon: const Icon(Icons.navigation),
onPressed: () {
Navigator.push<_PlayerVideoAndPopPage>(
context,
MaterialPageRoute<_PlayerVideoAndPopPage>(
builder: (BuildContext context) => _PlayerVideoAndPopPage(),
),
);
},
)
],
bottom: const TabBar(
isScrollable: true,
tabs: <Widget>[
Tab(
icon: Icon(Icons.cloud),
text: "Remote",
),
Tab(icon: Icon(Icons.insert_drive_file), text: "Asset"),
Tab(icon: Icon(Icons.list), text: "List example"),
],
),
),
body: TabBarView(
children: <Widget>[
_BumbleBeeRemoteVideo(),
_ButterFlyAssetVideo(),
_ButterFlyAssetVideoInList(),
],
),
),
);
}
}
class _ButterFlyAssetVideoInList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
_ExampleCard(title: "Item a"),
_ExampleCard(title: "Item b"),
_ExampleCard(title: "Item c"),
_ExampleCard(title: "Item d"),
_ExampleCard(title: "Item e"),
_ExampleCard(title: "Item f"),
_ExampleCard(title: "Item g"),
Card(
child: Column(children: <Widget>[
Column(
children: <Widget>[
const ListTile(
leading: Icon(Icons.cake),
title: Text("Video video"),
),
Stack(
alignment: FractionalOffset.bottomRight +
const FractionalOffset(-0.1, -0.1),
children: <Widget>[
_ButterFlyAssetVideo(),
Image.asset('assets/google.png'),
]),
],
),
])),
_ExampleCard(title: "Item h"),
_ExampleCard(title: "Item i"),
_ExampleCard(title: "Item j"),
_ExampleCard(title: "Item k"),
_ExampleCard(title: "Item l"),
],
);
}
}
/// A filler card to show the video in a list of scrolling contents.
class _ExampleCard extends StatelessWidget {
const _ExampleCard({Key? key, required this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: const Icon(Icons.airline_seat_flat_angled),
title: Text(title),
),
ButtonBar(
children: <Widget>[
TextButton(
child: const Text('BUY TICKETS'),
onPressed: () {
/* ... */
},
),
TextButton(
child: const Text('SELL TICKETS'),
onPressed: () {
/* ... */
},
),
],
),
],
),
);
}
}
class _ButterFlyAssetVideo extends StatefulWidget {
@override
_ButterFlyAssetVideoState createState() => _ButterFlyAssetVideoState();
}
class _ButterFlyAssetVideoState extends State<_ButterFlyAssetVideo> {
late VideoPlayerController _controller;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.asset('assets/Butterfly-209.mp4');
_controller.addListener(() {
setState(() {});
});
_controller.setLooping(true);
_controller.initialize().then((_) => setState(() {}));
_controller.play();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(top: 20.0),
),
const Text('With assets mp4'),
Container(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
VideoPlayer(_controller),
_ControlsOverlay(controller: _controller),
VideoProgressIndicator(_controller, allowScrubbing: true),
],
),
),
),
],
),
);
}
}
class _BumbleBeeRemoteVideo extends StatefulWidget {
@override
_BumbleBeeRemoteVideoState createState() => _BumbleBeeRemoteVideoState();
}
class _BumbleBeeRemoteVideoState extends State<_BumbleBeeRemoteVideo> {
late VideoPlayerController _controller;
Future<ClosedCaptionFile> _loadCaptions() async {
final String fileContents = await DefaultAssetBundle.of(context)
.loadString('assets/bumble_bee_captions.vtt');
return WebVTTCaptionFile(
fileContents); // For vtt files, use WebVTTCaptionFile
}
@override
void initState() {
super.initState();
_controller = VideoPlayerController.network(
"MYURL OF FIRESTORE STORAGE",
//closedCaptionFile: _loadCaptions(),
//videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),
);
_controller.addListener(() {
setState(() {});
});
_controller.setLooping(true);
_controller.initialize();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Container(padding: const EdgeInsets.only(top: 20.0)),
const Text('With remote mp4'),
Container(
padding: const EdgeInsets.all(20),
child: AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
VideoPlayer(_controller),
ClosedCaption(text: _controller.value.caption.text),
_ControlsOverlay(controller: _controller),
VideoProgressIndicator(_controller, allowScrubbing: true),
],
),
),
),
],
),
);
}
}
class _ControlsOverlay extends StatelessWidget {
const _ControlsOverlay({Key? key, required this.controller})
: super(key: key);
static const _examplePlaybackRates = [
0.25,
0.5,
1.0,
1.5,
2.0,
3.0,
5.0,
10.0,
];
final VideoPlayerController controller;
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
AnimatedSwitcher(
duration: Duration(milliseconds: 50),
reverseDuration: Duration(milliseconds: 200),
child: controller.value.isPlaying
? SizedBox.shrink()
: Container(
color: Colors.black26,
child: Center(
child: Icon(
Icons.play_arrow,
color: Colors.white,
size: 100.0,
),
),
),
),
GestureDetector(
onTap: () {
controller.value.isPlaying ? controller.pause() : controller.play();
},
),
Align(
alignment: Alignment.topRight,
child: PopupMenuButton<double>(
initialValue: controller.value.playbackSpeed,
tooltip: 'Playback speed',
onSelected: (speed) {
controller.setPlaybackSpeed(speed);
},
itemBuilder: (context) {
return [
for (final speed in _examplePlaybackRates)
PopupMenuItem(
value: speed,
child: Text('${speed}x'),
)
];
},
child: Padding(
padding: const EdgeInsets.symmetric(
// Using less vertical padding as the text is also longer
// horizontally, so it feels like it would need more spacing
// horizontally (matching the aspect ratio of the video).
vertical: 12,
horizontal: 16,
),
child: Text('${controller.value.playbackSpeed}x'),
),
),
),
],
);
}
}
class _PlayerVideoAndPopPage extends StatefulWidget {
@override
_PlayerVideoAndPopPageState createState() => _PlayerVideoAndPopPageState();
}
class _PlayerVideoAndPopPageState extends State<_PlayerVideoAndPopPage> {
late VideoPlayerController _videoPlayerController;
bool startedPlaying = false;
@override
void initState() {
super.initState();
_videoPlayerController =
VideoPlayerController.asset('assets/Butterfly-209.mp4');
_videoPlayerController.addListener(() {
if (startedPlaying && !_videoPlayerController.value.isPlaying) {
Navigator.pop(context);
}
});
}
@override
void dispose() {
_videoPlayerController.dispose();
super.dispose();
}
Future<bool> started() async {
await _videoPlayerController.initialize();
await _videoPlayerController.play();
startedPlaying = true;
return true;
}
@override
Widget build(BuildContext context) {
return Material(
elevation: 0,
child: Center(
child: FutureBuilder<bool>(
future: started(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (snapshot.data == true) {
return AspectRatio(
aspectRatio: _videoPlayerController.value.aspectRatio,
child: VideoPlayer(_videoPlayerController),
);
} else {
return const Text('waiting for video to load');
}
},
),
),
);
}
}
颤振医生-v
[✓] Flutter (Channel stable, 2.5.1, on macOS 11.4 20F71 darwin-x64, locale ja-JP)
• Flutter version 2.5.1 at /Users/keihoshino/Development/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision ffb2ecea52 (3 weeks ago), 2021-09-17 15:26:33 -0400
• Engine revision b3af521a05
• Dart version 2.14.2
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
• Android SDK at /Users/keihoshino/Library/Android/sdk
• Platform android-31, build-tools 31.0.0
• Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 13.0, Build version 13A233
• CocoaPods version 1.11.2
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2020.3)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7281165)
[✓] Connected device (2 available)
• sdk gphone x86 64 arm64 (mobile) • emulator-5554 • android-x64 • Android 11 (API 30) (emulator)
• Chrome (web) • chrome • web-javascript • Google Chrome 94.0.4606.71
• No issues found!
谢谢!
发布于 2021-10-06 15:54:59
我解决了。我很高兴这个话题能帮助任何有同样问题的人。
在我的例子中,我在" android /app/src/AndroidManifest.xml“中添加了这段代码,并重新启动了android模拟器。
<uses-permission android:name="android.permission.INTERNET"/>
这是我的AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.k8s.app02">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:label="app02"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
这是用视频播放器的自述描述的
谢谢!
https://stackoverflow.com/questions/69453504
复制相似问题