Flutter Plugin
Latest version: 2.7.3
Getting started
-
Run this command with Flutter:
$ flutter pub add vdocipher_flutter
This will add a line like this to your package's pubspec.yaml (and run an implicit
dart pub get
):dependencies:
vdocipher_flutter: ^2.7.3Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.
-
In android section use Theme.AppCompat theme with
MainActivity
:Make this change in
android/app/src/main/res/values/styles.xml
.<style name="NormalTheme" parent="Theme.AppCompat.Light.NoActionBar">
....
</style>
NOTE: There can be multiple styles.xml files depending on the project structure. Please make the above change in all of them, such as
values-night/styles.xml
andvalues/styles.xml
.
-
In android section extend the FlutterFragmentActivity class in your MainActivity file:
Make this change in
android/app/src/main/java/com/project-name/MainActivity.java
.class MainActivity extends FlutterFragmentActivity {
} -
Import player in your Dart code like this:
import 'package:vdocipher_flutter/vdocipher_flutter.dart';
Widget playerWidget = VdoPlayer(
embedInfo: SAMPLE_1,
onPlayerCreated: (controller) => _onPlayerCreated(controller),
onFullscreenChange: _onFullscreenChange,
onError: _onVdoError,
controls: true, //optional, set false to disable player controls.
);
Without using Theme.AppCompat theme with MainActivity.java and extending from FlutterFragmentActivity, as mentioned in the 2nd and 3rd steps, our plugin will throw exception. For a better understanding, please take a look at our sample app.
Using ProGuard
If you use ProGuard in your app, you might need to add the following rule to your ProGuard file.
To add Proguard rules, please follow these steps:
- Create a file named "proguard-rules.pro" in the "android/app" directory.
Add the following line to your Proguard rules:
-keep class androidx.media3.common.MediaLibraryInfo { *; }
- In your "android/app/build.gradle" file, enable Proguard for the app by adding the following configuration within the "buildTypes" section for the "release" build type:
buildTypes {
release {
...
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
...
}
}
Example
samples.dart
import 'package:vdocipher_flutter/vdocipher_flutter.dart';
const EmbedInfo SAMPLE_1 = EmbedInfo.streaming(
otp: '20160313versASE313N2GIgnZjjFKOYWXnZY1ms8Y5YmvgJnt3v2phvCl7G9BsrJ',
playbackInfo: 'eyJ2aWRlb0lkIjoiYTllYWUwOTZjZDg4NGRiYmEzNTE1M2VlNDJhNTA0YTgifQ=='
embedInfoOptions: EmbedInfoOptions(
autoplay: true
)
);
const EmbedInfo SAMPLE_2 = EmbedInfo.streaming(
otp: '20160313versASE313CBS0f0mkwrNqTswuCYx7Lo41GpQ3r06wbx2WgOUASrQIgH',
playbackInfo: 'eyJ2aWRlb0lkIjoiYTllYWUwOTZjZDg4NGRiYmEzNTE1M2VlNDJhNTA0YTgifQ=='
);
vdoplayback_view.dart
import 'package:flutter/material.dart';
import 'package:vdocipher_flutter/vdocipher_flutter.dart';
import 'package:vdocipher_flutter_example/samples.dart';
class VdoPlaybackView extends StatefulWidget {
_VdoPlaybackViewState createState() => _VdoPlaybackViewState();
}
class _VdoPlaybackViewState extends State<VdoPlaybackView> {
VdoPlayerController? _controller;
ValueNotifier<bool> _isFullScreen = ValueNotifier(false);
Widget build(BuildContext context) {
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Flexible(child: Container(
child: VdoPlayer(
embedInfo: SAMPLE_1,
onPlayerCreated: (controller) => _onPlayerCreated(controller),
onFullscreenChange: _onFullscreenChange,
onError: _onVdoError,
controls: true, //optional, set false to disable player controls
),
width: MediaQuery.of(context).size.width,
height: _isFullScreen.value ? MediaQuery.of(context).size.height : _getHeightForWidth(MediaQuery.of(context).size.width),
)),
ValueListenableBuilder(
valueListenable: _isFullScreen,
builder: (context, dynamic value, child) {
return value ? SizedBox.shrink() : _nonFullScreenContent();
}),
])
);
}
_onVdoError(VdoError vdoError) {
print("Oops, the system encountered a problem: " + vdoError.message);
}
_onPlayerCreated(VdoPlayerController? controller) {
setState(() {
_controller = controller;
_onEventChange(_controller);
});
}
_onEventChange(VdoPlayerController? controller) {
controller!.addListener(() {
VdoPlayerValue value = controller.value;
print("VdoControllerListner"
"\nloading: ${value.isLoading} "
"\nplaying: ${value.isPlaying} "
"\nbuffering: ${value.isBuffering} "
"\nended: ${value.isEnded}"
);
});
}
_onFullscreenChange(isFullscreen) {
setState(() {
_isFullScreen.value = isFullscreen;
});
}
_nonFullScreenContent() {
return Column(
children: [
Text('Sample Playback', style: TextStyle(fontSize: 20.0),)
]);
}
double _getHeightForWidth(double width) {
return width / aspectRatio;
}
}
main.dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:vdocipher_flutter/vdocipher_flutter.dart';
import 'package:vdocipher_flutter_example/vdoplayback_view.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'VdoCipher Sample Application',
home: MyHome(),
navigatorObservers: [VdoPlayerController.navigatorObserver('/player/(.*)')],
theme: ThemeData(
primaryColor: Colors.white,
textTheme: TextTheme(bodyText1: TextStyle(fontSize: 12.0))),
);
}
}
class MyHome extends StatefulWidget {
_MyHomeState createState() => _MyHomeState();
}
class _MyHomeState extends State<MyHome> {
String? _nativePlatformLibraryVersion = 'Unknown';
void initState() {
super.initState();
getNativeLibraryVersion();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> getNativeLibraryVersion() async {
String? version;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
version = await (Platform.isIOS ? VdocipherMethodChannel.nativeIOSAndroidLibraryVersion : VdocipherMethodChannel.nativeAndroidLibraryVersion);
} on PlatformException {
version = 'Failed to get native platform library version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_nativePlatformLibraryVersion = version;
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('VdoCipher Sample Application'),
),
body: Center(child: Column(
children: <Widget>[
Expanded(child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: _goToVideoPlayback,
child: const Text('Online Playback',
style: TextStyle(fontSize: 20)),
),
ElevatedButton(
onPressed: null,
child: const Text('Todo: video selection',
style: TextStyle(fontSize: 20)),
)
])),
Padding(padding: EdgeInsets.all(16.0),
child: Text('Native ${Platform.isIOS ? 'iOS' : 'Android'} library version: $_nativePlatformLibraryVersion',
style: TextStyle(color: Colors.grey, fontSize: 16.0)))
],
))
);
}
void _goToVideoPlayback() {
Navigator.of(context).push(
MaterialPageRoute<void>(
settings: RouteSettings(name: '/player/sample/video'),
builder: (BuildContext context) {
return VdoPlaybackView();
},
),
);
}
}