platform interface.
This commit is contained in:
parent
c9abbd0c98
commit
1552eebe83
|
@ -0,0 +1,11 @@
|
|||
# Files and directories created by pub
|
||||
.dart_tool/
|
||||
.packages
|
||||
# Remove the following pattern if you wish to check in your lock file
|
||||
pubspec.lock
|
||||
|
||||
# Conventional directory for build outputs
|
||||
build/
|
||||
|
||||
# Directory created by dartdoc
|
||||
doc/api/
|
|
@ -0,0 +1,3 @@
|
|||
## 0.0.1
|
||||
|
||||
- Initial version.
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Ryan Heise and the project contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,26 @@
|
|||
# just_audio_platform_interface
|
||||
|
||||
A common platform interface for the [`just_audio`][../just_audio] plugin.
|
||||
|
||||
This interface allows platform-specific implementations of the `just_audio`
|
||||
plugin, as well as the plugin itself, to ensure they are supporting the
|
||||
same interface.
|
||||
|
||||
# Usage
|
||||
|
||||
To implement a new platform-specific implementation of `just_audio`, extend
|
||||
[`JustAudioPlatform`][2] with an implementation that performs the
|
||||
platform-specific behavior, and when you register your plugin, set the default
|
||||
`JustAudioPlatform` by calling
|
||||
`JustAudioPlatform.instance = MyPlatformJustAudio()`.
|
||||
|
||||
# Note on breaking changes
|
||||
|
||||
Strongly prefer non-breaking changes (such as adding a method to the interface)
|
||||
over breaking changes for this package.
|
||||
|
||||
See https://flutter.dev/go/platform-interface-breaking-changes for a discussion
|
||||
on why a less-clean interface is preferable to a breaking change.
|
||||
|
||||
[1]: ../just_audio
|
||||
[2]: lib/just_audio_platform_interface.dart
|
|
@ -0,0 +1,426 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:meta/meta.dart' show required;
|
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||
|
||||
import 'method_channel_just_audio.dart';
|
||||
|
||||
/// The interface that implementations of just_audio must implement.
|
||||
///
|
||||
/// Platform implementations should extend this class rather than implement it
|
||||
/// as `just_audio` does not consider newly added methods to be breaking
|
||||
/// changes. Extending this class (using `extends`) ensures that the subclass
|
||||
/// will get the default implementation, while platform implementations that
|
||||
/// `implements` this interface will be broken by newly added
|
||||
/// [JustAudioPlatform] methods.
|
||||
abstract class JustAudioPlatform extends PlatformInterface {
|
||||
/// Constructs a JustAudioPlatform.
|
||||
JustAudioPlatform() : super(token: _token);
|
||||
|
||||
static final Object _token = Object();
|
||||
|
||||
static JustAudioPlatform _instance = MethodChannelJustAudio();
|
||||
|
||||
/// The default instance of [JustAudioPlatform] to use.
|
||||
///
|
||||
/// Defaults to [MethodChannelJustAudio].
|
||||
static JustAudioPlatform get instance => _instance;
|
||||
|
||||
/// Platform-specific plugins should set this with their own platform-specific
|
||||
/// class that extends [JustAudioPlatform] when they register themselves.
|
||||
// TODO(amirh): Extract common platform interface logic.
|
||||
// https://github.com/flutter/flutter/issues/43368
|
||||
static set instance(JustAudioPlatform instance) {
|
||||
PlatformInterface.verifyToken(instance, _token);
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
/// Creates a new player and returns a nested platform interface for
|
||||
/// communicating with that player.
|
||||
Future<AudioPlayerPlatform> init(InitRequest request) {
|
||||
throw UnimplementedError('init() has not been implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
/// A nested platform interface for communicating with a particular player
|
||||
/// instance.
|
||||
abstract class AudioPlayerPlatform {
|
||||
Future<LoadResponse> load(LoadRequest request);
|
||||
Future<PlayResponse> play(PlayRequest request);
|
||||
Future<PauseResponse> pause(PauseRequest request);
|
||||
Future<SetVolumeResponse> setVolume(SetVolumeRequest request);
|
||||
Future<SetSpeedResponse> setSpeed(SetSpeedRequest request);
|
||||
Future<SetLoopModeResponse> setLoopMode(SetLoopModeRequest request);
|
||||
Future<SetShuffleModeResponse> setShuffleMode(SetShuffleModeRequest request);
|
||||
Future<SetAutomaticallyWaitsToMinimizeStallingResponse>
|
||||
setAutomaticallyWaitsToMinimizeStalling(
|
||||
SetAutomaticallyWaitsToMinimizeStallingRequest request);
|
||||
Future<SeekResponse> seek(SeekRequest request);
|
||||
Future<SetAndroidAudioAttributesResponse> setAndroidAudioAttributes(
|
||||
SetAndroidAudioAttributesRequest request);
|
||||
Future<DisposeResponse> dispose(DisposeRequest request);
|
||||
Future<ConcatenatingInsertAllResponse> concatenatingInsertAll(
|
||||
ConcatenatingInsertAllRequest request);
|
||||
Future<ConcatenatingRemoveRangeResponse> concatenatingRemoveRange(
|
||||
ConcatenatingRemoveRangeRequest request);
|
||||
Future<ConcatenatingMoveResponse> concatenatingMove(
|
||||
ConcatenatingMoveRequest request);
|
||||
}
|
||||
|
||||
class InitRequest {
|
||||
final String id;
|
||||
|
||||
InitRequest({@required this.id});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'id': id,
|
||||
};
|
||||
}
|
||||
|
||||
class LoadRequest {
|
||||
final AudioSourceMessage audioSourceMessage;
|
||||
|
||||
LoadRequest({@required this.audioSourceMessage});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'audioSource': audioSourceMessage.toMap(),
|
||||
};
|
||||
}
|
||||
|
||||
class LoadResponse {
|
||||
final Duration duration;
|
||||
|
||||
LoadResponse({@required this.duration});
|
||||
|
||||
static LoadResponse fromMap(Map<dynamic, dynamic> map) => LoadResponse(
|
||||
duration: map['duration'] != null
|
||||
? Duration(microseconds: map['duration'])
|
||||
: null);
|
||||
}
|
||||
|
||||
class PlayRequest {
|
||||
Map<dynamic, dynamic> toMap() => {};
|
||||
}
|
||||
|
||||
class PlayResponse {
|
||||
static PlayResponse fromMap(Map<dynamic, dynamic> map) => PlayResponse();
|
||||
}
|
||||
|
||||
class PauseRequest {
|
||||
Map<dynamic, dynamic> toMap() => {};
|
||||
}
|
||||
|
||||
class PauseResponse {
|
||||
static PauseResponse fromMap(Map<dynamic, dynamic> map) => PauseResponse();
|
||||
}
|
||||
|
||||
class SetVolumeRequest {
|
||||
final double volume;
|
||||
|
||||
SetVolumeRequest({@required this.volume});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'volume': volume,
|
||||
};
|
||||
}
|
||||
|
||||
class SetVolumeResponse {
|
||||
static SetVolumeResponse fromMap(Map<dynamic, dynamic> map) =>
|
||||
SetVolumeResponse();
|
||||
}
|
||||
|
||||
class SetSpeedRequest {
|
||||
final double speed;
|
||||
|
||||
SetSpeedRequest({@required this.speed});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'speed': speed,
|
||||
};
|
||||
}
|
||||
|
||||
class SetSpeedResponse {
|
||||
static SetSpeedResponse fromMap(Map<dynamic, dynamic> map) =>
|
||||
SetSpeedResponse();
|
||||
}
|
||||
|
||||
class SetLoopModeRequest {
|
||||
final LoopModeMessage loopMode;
|
||||
|
||||
SetLoopModeRequest({@required this.loopMode});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'loopMode': describeEnum(loopMode),
|
||||
};
|
||||
}
|
||||
|
||||
class SetLoopModeResponse {
|
||||
static SetLoopModeResponse fromMap(Map<dynamic, dynamic> map) =>
|
||||
SetLoopModeResponse();
|
||||
}
|
||||
|
||||
enum LoopModeMessage { off, one, all }
|
||||
|
||||
class SetShuffleModeRequest {
|
||||
final ShuffleModeMessage shuffleMode;
|
||||
|
||||
SetShuffleModeRequest({@required this.shuffleMode});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'shuffleMode': describeEnum(shuffleMode),
|
||||
};
|
||||
}
|
||||
|
||||
class SetShuffleModeResponse {
|
||||
static SetShuffleModeResponse fromMap(Map<dynamic, dynamic> map) =>
|
||||
SetShuffleModeResponse();
|
||||
}
|
||||
|
||||
enum ShuffleModeMessage { none, all }
|
||||
|
||||
class SetAutomaticallyWaitsToMinimizeStallingRequest {
|
||||
final bool enabled;
|
||||
|
||||
SetAutomaticallyWaitsToMinimizeStallingRequest({@required this.enabled});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'enabled': enabled,
|
||||
};
|
||||
}
|
||||
|
||||
class SetAutomaticallyWaitsToMinimizeStallingResponse {
|
||||
static SetAutomaticallyWaitsToMinimizeStallingResponse fromMap(
|
||||
Map<dynamic, dynamic> map) =>
|
||||
SetAutomaticallyWaitsToMinimizeStallingResponse();
|
||||
}
|
||||
|
||||
class SeekRequest {
|
||||
final Duration position;
|
||||
final int index;
|
||||
|
||||
SeekRequest({@required this.position, this.index});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'position': position.inMicroseconds,
|
||||
'index': index,
|
||||
};
|
||||
}
|
||||
|
||||
class SeekResponse {
|
||||
static SeekResponse fromMap(Map<dynamic, dynamic> map) => SeekResponse();
|
||||
}
|
||||
|
||||
class SetAndroidAudioAttributesRequest {
|
||||
final int contentType;
|
||||
final int flags;
|
||||
final int usage;
|
||||
|
||||
SetAndroidAudioAttributesRequest({
|
||||
@required this.contentType,
|
||||
@required this.flags,
|
||||
@required this.usage,
|
||||
});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'contentType': contentType,
|
||||
'flags': flags,
|
||||
'usage': usage,
|
||||
};
|
||||
}
|
||||
|
||||
class SetAndroidAudioAttributesResponse {
|
||||
static SetAndroidAudioAttributesResponse fromMap(Map<dynamic, dynamic> map) =>
|
||||
SetAndroidAudioAttributesResponse();
|
||||
}
|
||||
|
||||
class DisposeRequest {
|
||||
Map<dynamic, dynamic> toMap() => {};
|
||||
}
|
||||
|
||||
class DisposeResponse {
|
||||
static DisposeResponse fromMap(Map<dynamic, dynamic> map) =>
|
||||
DisposeResponse();
|
||||
}
|
||||
|
||||
class ConcatenatingInsertAllRequest {
|
||||
final int index;
|
||||
final List<AudioSourceMessage> children;
|
||||
|
||||
ConcatenatingInsertAllRequest({
|
||||
@required this.index,
|
||||
@required this.children,
|
||||
});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'index': index,
|
||||
'children': children.map((child) => child.toMap()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
class ConcatenatingInsertAllResponse {
|
||||
static ConcatenatingInsertAllResponse fromMap(Map<dynamic, dynamic> map) =>
|
||||
ConcatenatingInsertAllResponse();
|
||||
}
|
||||
|
||||
class ConcatenatingRemoveRangeRequest {
|
||||
final int startIndex;
|
||||
final int endIndex;
|
||||
|
||||
ConcatenatingRemoveRangeRequest({
|
||||
@required this.startIndex,
|
||||
@required this.endIndex,
|
||||
});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'startIndex': startIndex,
|
||||
'endIndex': endIndex,
|
||||
};
|
||||
}
|
||||
|
||||
class ConcatenatingRemoveRangeResponse {
|
||||
static ConcatenatingRemoveRangeResponse fromMap(Map<dynamic, dynamic> map) =>
|
||||
ConcatenatingRemoveRangeResponse();
|
||||
}
|
||||
|
||||
class ConcatenatingMoveRequest {
|
||||
final int currentIndex;
|
||||
final int newIndex;
|
||||
|
||||
ConcatenatingMoveRequest({this.currentIndex, this.newIndex});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'currentIndex': currentIndex,
|
||||
'newIndex': newIndex,
|
||||
};
|
||||
}
|
||||
|
||||
class ConcatenatingMoveResponse {
|
||||
static ConcatenatingMoveResponse fromMap(Map<dynamic, dynamic> map) =>
|
||||
ConcatenatingMoveResponse();
|
||||
}
|
||||
|
||||
abstract class AudioSourceMessage {
|
||||
final String id;
|
||||
|
||||
AudioSourceMessage({@required this.id});
|
||||
|
||||
Map<dynamic, dynamic> toMap();
|
||||
}
|
||||
|
||||
abstract class IndexedAudioSourceMessage extends AudioSourceMessage {
|
||||
IndexedAudioSourceMessage({@required String id}) : super(id: id);
|
||||
}
|
||||
|
||||
abstract class UriAudioSourceMessage extends IndexedAudioSourceMessage {
|
||||
final String uri;
|
||||
final Map<dynamic, dynamic> headers;
|
||||
|
||||
UriAudioSourceMessage({
|
||||
@required String id,
|
||||
@required this.uri,
|
||||
@required this.headers,
|
||||
}) : super(id: id);
|
||||
}
|
||||
|
||||
class ProgressiveAudioSourceMessage extends UriAudioSourceMessage {
|
||||
ProgressiveAudioSourceMessage({
|
||||
@required String id,
|
||||
@required String uri,
|
||||
@required Map<dynamic, dynamic> headers,
|
||||
}) : super(id: id, uri: uri, headers: headers);
|
||||
|
||||
@override
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'id': id,
|
||||
'uri': uri,
|
||||
'headers': headers,
|
||||
};
|
||||
}
|
||||
|
||||
class DashAudioSourceMessage extends UriAudioSourceMessage {
|
||||
DashAudioSourceMessage({
|
||||
@required String id,
|
||||
@required String uri,
|
||||
@required Map<dynamic, dynamic> headers,
|
||||
}) : super(id: id, uri: uri, headers: headers);
|
||||
|
||||
@override
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'id': id,
|
||||
'uri': uri,
|
||||
'headers': headers,
|
||||
};
|
||||
}
|
||||
|
||||
class HlsAudioSourceMessage extends UriAudioSourceMessage {
|
||||
HlsAudioSourceMessage({
|
||||
@required String id,
|
||||
@required String uri,
|
||||
@required Map<dynamic, dynamic> headers,
|
||||
}) : super(id: id, uri: uri, headers: headers);
|
||||
|
||||
@override
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'id': id,
|
||||
'uri': uri,
|
||||
'headers': headers,
|
||||
};
|
||||
}
|
||||
|
||||
class ConcatenatingAudioSourceMessage extends AudioSourceMessage {
|
||||
final List<AudioSourceMessage> children;
|
||||
final bool useLazyPreparation;
|
||||
|
||||
ConcatenatingAudioSourceMessage({
|
||||
@required String id,
|
||||
@required this.children,
|
||||
@required this.useLazyPreparation,
|
||||
}) : super(id: id);
|
||||
|
||||
@override
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'id': id,
|
||||
'children': children.map((child) => child.toMap()).toList(),
|
||||
'useLazyPreparation': useLazyPreparation,
|
||||
};
|
||||
}
|
||||
|
||||
class ClippingAudioSourceMessage extends IndexedAudioSourceMessage {
|
||||
final UriAudioSourceMessage child;
|
||||
final Duration start;
|
||||
final Duration end;
|
||||
|
||||
ClippingAudioSourceMessage({
|
||||
@required String id,
|
||||
@required this.child,
|
||||
@required this.start,
|
||||
@required this.end,
|
||||
}) : super(id: id);
|
||||
|
||||
@override
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'id': id,
|
||||
'child': child.toMap(),
|
||||
'start': start.inMicroseconds,
|
||||
'end': end.inMicroseconds,
|
||||
};
|
||||
}
|
||||
|
||||
class LoopingAudioSourceMessage extends AudioSourceMessage {
|
||||
final AudioSourceMessage child;
|
||||
final int count;
|
||||
|
||||
LoopingAudioSourceMessage({
|
||||
@required String id,
|
||||
@required this.child,
|
||||
@required this.count,
|
||||
}) : super(id: id);
|
||||
|
||||
@override
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'id': id,
|
||||
'child': child.toMap(),
|
||||
'count': count,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'just_audio_platform_interface.dart';
|
||||
|
||||
/// An implementation of [JustAudioPlatform] that uses method channels.
|
||||
class MethodChannelJustAudio extends JustAudioPlatform {
|
||||
static final _mainChannel = MethodChannel('com.ryanheise.just_audio.methods');
|
||||
|
||||
@override
|
||||
Future<AudioPlayerPlatform> init(InitRequest request) async {
|
||||
await _mainChannel.invokeMethod('init', request.toMap());
|
||||
return MethodChannelAudioPlayer(request.id);
|
||||
}
|
||||
}
|
||||
|
||||
class MethodChannelAudioPlayer extends AudioPlayerPlatform {
|
||||
final String id;
|
||||
final MethodChannel _channel;
|
||||
|
||||
MethodChannelAudioPlayer(this.id)
|
||||
: _channel = MethodChannel('com.ryanheise.just_audio.methods.$id');
|
||||
|
||||
@override
|
||||
Future<LoadResponse> load(LoadRequest request) async {
|
||||
return (await _channel.invokeMethod('load', request?.toMap()))?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<PlayResponse> play(PlayRequest request) async {
|
||||
return (await _channel.invokeMethod('play', request?.toMap()))?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<PauseResponse> pause(PauseRequest request) async {
|
||||
return (await _channel.invokeMethod('pause', request?.toMap()))?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SetVolumeResponse> setVolume(SetVolumeRequest request) async {
|
||||
return (await _channel.invokeMethod('setVolume', request?.toMap()))
|
||||
?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SetSpeedResponse> setSpeed(SetSpeedRequest request) async {
|
||||
return (await _channel.invokeMethod('setSpeed', request?.toMap()))
|
||||
?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SetLoopModeResponse> setLoopMode(SetLoopModeRequest request) async {
|
||||
return (await _channel.invokeMethod('setLoopMode', request?.toMap()))
|
||||
?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SetShuffleModeResponse> setShuffleMode(
|
||||
SetShuffleModeRequest request) async {
|
||||
return (await _channel.invokeMethod('setShuffleMode', request?.toMap()))
|
||||
?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SetAutomaticallyWaitsToMinimizeStallingResponse>
|
||||
setAutomaticallyWaitsToMinimizeStalling(
|
||||
SetAutomaticallyWaitsToMinimizeStallingRequest request) async {
|
||||
return (await _channel.invokeMethod(
|
||||
'setAutomaticallyWaitsToMinimizeStalling', request?.toMap()))
|
||||
?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SeekResponse> seek(SeekRequest request) async {
|
||||
return (await _channel.invokeMethod('seek', request?.toMap()))?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SetAndroidAudioAttributesResponse> setAndroidAudioAttributes(
|
||||
SetAndroidAudioAttributesRequest request) async {
|
||||
return (await _channel.invokeMethod(
|
||||
'setAndroidAudioAttributes', request?.toMap()))
|
||||
?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DisposeResponse> dispose(DisposeRequest request) async {
|
||||
return (await _channel.invokeMethod('dispose', request?.toMap()))
|
||||
?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ConcatenatingInsertAllResponse> concatenatingInsertAll(
|
||||
ConcatenatingInsertAllRequest request) async {
|
||||
return (await _channel.invokeMethod(
|
||||
'concatenatingInsertAll', request?.toMap()))
|
||||
?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ConcatenatingRemoveRangeResponse> concatenatingRemoveRange(
|
||||
ConcatenatingRemoveRangeRequest request) async {
|
||||
return (await _channel.invokeMethod(
|
||||
'concatenatingRemoveRange', request?.toMap()))
|
||||
?.fromMap();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ConcatenatingMoveResponse> concatenatingMove(
|
||||
ConcatenatingMoveRequest request) async {
|
||||
return (await _channel.invokeMethod('concatenatingMove', request?.toMap()))
|
||||
?.fromMap();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
name: just_audio_platform_interface
|
||||
description: A common platform interface for the just_audio plugin.
|
||||
homepage: https://github.com/ryanheise/just_audio/just_audio_platform_interface
|
||||
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
|
||||
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
|
||||
version: 0.0.1
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
meta: ^1.1.8
|
||||
plugin_platform_interface: ^1.0.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
mockito: ^4.1.1
|
||||
pedantic: ^1.8.0
|
||||
|
||||
environment:
|
||||
sdk: ">=2.7.0 <3.0.0"
|
||||
flutter: ">=1.12.13+hotfix.5"
|
Loading…
Reference in New Issue