Unhandled Exception: Invalid argument: is a regular instance: Instance of 'LocationDto' - flutter

currently I am us this plugin to get the background location of a user, works great with ios but fails on android after recent updates and the plugin progress stalled, I am now faced with the issue below
so, in my main class i have this
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
// onLineStatus = UserSimplePreferences.getUsername() ?? ''
onLineStatus = UserSimplePrefences.getButtonStatus() ?? false;
displayToastMessage(onLineStatus.toString(), context);
osmController = MapController(
initMapWithUserPosition: true,
//initPosition: initPosition,
);
osmController.addObserver(this);
scaffoldKey = GlobalKey<ScaffoldState>();
if (IsolateNameServer.lookupPortByName(
LocationServiceRepository.isolateName) !=
null) {
IsolateNameServer.removePortNameMapping(
LocationServiceRepository.isolateName);
}
IsolateNameServer.registerPortWithName(
port.sendPort, LocationServiceRepository.isolateName);
port.listen(
(dynamic data) async {
if (data != null) await updateUI(data);
},
);
initPlatformState();
}
Future<void> updateUI(LocationDto data) async {
await _updateNotificationText(data);
}
Future<void> _updateNotificationText(LocationDto data) async {
await BackgroundLocator.updateNotificationText(
title: "Your location is updated",
msg: "${DateTime.now()}",
bigMsg: "${data.latitude}, ${data.longitude}");
}
Future<void> initPlatformState() async {
print('Initializing...');
await BackgroundLocator.initialize();
await BackgroundLocator.isServiceRunning();
}
Future<void> _startLocator() async {
Map<String, dynamic> data = {'countInit': 1};
return await BackgroundLocator.registerLocationUpdate(
LocationCallbackHandler.callback,
initCallback: LocationCallbackHandler.initCallback,
initDataCallback: data,
disposeCallback: LocationCallbackHandler.disposeCallback,
iosSettings: IOSSettings(
accuracy: LocationAccuracy.NAVIGATION,
distanceFilter: 0,
stopWithTerminate: true),
autoStop: false,
androidSettings: AndroidSettings(
accuracy: LocationAccuracy.NAVIGATION,
interval: 5,
distanceFilter: 0,
client: LocationClient.google,
androidNotificationSettings: AndroidNotificationSettings(
notificationChannelName: 'Location tracking',
notificationTitle: 'Start Location Tracking',
notificationMsg: 'Track location in background',
notificationBigMsg:
'Background location is on to keep the app up-tp-date with your location. This is required for main features to work properly when the app is not running.',
notificationIconColor: Colors.grey,
notificationTapCallback:
LocationCallbackHandler.notificationCallback)));
}
This is the LocationRepositoryClass
class LocationServiceRepository {
static LocationServiceRepository _instance = LocationServiceRepository._();
LocationServiceRepository._();
factory LocationServiceRepository() {
return _instance;
}
static const String isolateName = 'LocatorIsolate';
int _count = -1;
Future<void> init(Map<dynamic, dynamic> params) async {
//TODO change logs
print("***********Init callback handler");
if (params.containsKey('countInit')) {
dynamic tmpCount = params['countInit'];
if (tmpCount is double) {
_count = tmpCount.toInt();
} else if (tmpCount is String) {
_count = int.parse(tmpCount);
} else if (tmpCount is int) {
_count = tmpCount;
} else {
_count = -2;
}
} else {
_count = 0;
}
print("$_count");
await setLogLabel("start");
final SendPort? send = IsolateNameServer.lookupPortByName(isolateName);
send?.send(null);
}
Future<void> dispose() async {
print("***********Dispose callback handler");
print("$_count");
await setLogLabel("end");
final SendPort? send = IsolateNameServer.lookupPortByName(isolateName);
send?.send(null);
}
#pragma('vm:entry-point')
Future<void> callback(LocationDto locationDto) async {
print('$_count location in dart: ${locationDto.toString()}');
await setLogPosition(_count, locationDto);
final SendPort? send = IsolateNameServer.lookupPortByName(isolateName);
send?.send(locationDto);//error here
_count++;
}
static Future<void> setLogLabel(String label) async {
final date = DateTime.now();
// await FileManager.writeToLogFile(
// '------------\n$label: ${formatDateLog(date)}\n------------\n');
}
static Future<void> setLogPosition(int count, LocationDto data) async {
final date = DateTime.now();
// await FileManager.writeToLogFile(
// '$count : ${formatDateLog(date)} --> ${formatLog(data)} --- isMocked: ${data.isMocked}\n');
}
static double dp(double val, int places) {
num mod = pow(10.0, places);
return ((val * mod).round().toDouble() / mod);
}
static String formatDateLog(DateTime date) {
return date.hour.toString() +
":" +
date.minute.toString() +
":" +
date.second.toString();
}
static String formatLog(LocationDto locationDto) {
return dp(locationDto.latitude, 4).toString() +
" " +
dp(locationDto.longitude, 4).toString();
}
}
and this is the locationCallbackHandler class
class LocationCallbackHandler {
static Future<void> initCallback(Map<dynamic, dynamic> params) async {
LocationServiceRepository myLocationCallbackRepository =
LocationServiceRepository();
await myLocationCallbackRepository.init(params);
}
static Future<void> disposeCallback() async {
LocationServiceRepository myLocationCallbackRepository =
LocationServiceRepository();
await myLocationCallbackRepository.dispose();
}
#pragma('vm:entry-point')
static void callback(LocationDto locationDto) async {
LocationServiceRepository myLocationCallbackRepository =
LocationServiceRepository();
await myLocationCallbackRepository.callback(locationDto);
}
static Future<void> notificationCallback() async {
print('***notificationCallback');
}
}
Everthing was working fine until this update with flutter and kotlin, Now i have the error
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument: is a regular instance: Instance of 'LocationDto'
E/flutter (26006): #0 _SendPort._sendInternal (dart:isolate-patch/isolate_patch.dart:249:43)
E/flutter (26006): #1 _SendPort.send (dart:isolate-patch/isolate_patch.dart:230:5)
E/flutter (26006): #2 LocationServiceRepository.callback
package:drivers_app/tabPages/location_service_reposirtory.dart:59
The error points to this code
#pragma('vm:entry-point')
Future<void> callback(LocationDto locationDto) async {
print('$_count location in dart: ${locationDto.toString()}');
await setLogPosition(_count, locationDto);
final SendPort? send = IsolateNameServer.lookupPortByName(isolateName);
send?.send(locationDto); //error here
_count++;
}
There is no reply from the plugin developer, Any help would be appreciated.

https://github.com/Yukams/background_locator_fixed/pull/53
There were some errors after updating flutter to version 3, If you run into this error then please visit the above website for the fix.

Related

Unhandled Exception: Bad state: Tried to use PaginationNotifier after `dispose` was called

I have a StateNotifierProvider that calls an async function which loads some images from the internal storage and adds them to the AsyncValue data:
//Provider declaration
final paginationImagesProvider = StateNotifierProvider.autoDispose<PaginationNotifier, AsyncValue<List<Uint8List?>>>((ref) {
return PaginationNotifier(folderId: ref.watch(localStorageSelectedFolderProvider), itemsPerBatch: 100, ref: ref);
});
//Actual class with AsyncValue as State
class PaginationNotifier extends StateNotifier<AsyncValue<List<Uint8List?>>> {
final int itemsPerBatch;
final String folderId;
final Ref ref;
int _numberOfItemsInFolder = 0;
bool _alreadyFetching = false;
bool _hasMoreItems = true;
PaginationNotifier({required this.itemsPerBatch, required this.folderId, required this.ref}) : super(const AsyncValue.loading()) {
log("PaginationNotifier created with folderId: $folderId, itemsPerBatch: $itemsPerBatch");
init();
}
final List<Uint8List?> _items = [];
void init() {
if (_items.isEmpty) {
log("fetchingFirstBatch");
_fetchFirstBatch();
}
}
Future<List<Uint8List?>> _fetchNextItems() async {
List<AssetEntity> images = (await (await PhotoManager.getAssetPathList())
.firstWhere((element) => element.id == folderId)
.getAssetListRange(start: _items.length, end: _items.length + itemsPerBatch));
List<Uint8List?> newItems = [];
for (AssetEntity image in images) {
newItems.add(await image.thumbnailData);
}
return newItems;
}
void _updateData(List<Uint8List?> result) {
if (result.isEmpty) {
state = AsyncValue.data(_items);
} else {
state = AsyncValue.data(_items..addAll(result));
}
_hasMoreItems = _numberOfItemsInFolder > _items.length;
}
Future<void> _fetchFirstBatch() async {
try {
_numberOfItemsInFolder = await (await PhotoManager.getAssetPathList()).firstWhere((element) => element.id == folderId).assetCountAsync;
state = const AsyncValue.loading();
final List<Uint8List?> result = await _fetchNextItems();
_updateData(result);
} catch (e, stk) {
state = AsyncValue.error(e, stk);
}
}
Future<void> fetchNextBatch() async {
if (_alreadyFetching || !_hasMoreItems) return;
_alreadyFetching = true;
log("data updated");
state = AsyncValue.data(_items);
try {
final result = await _fetchNextItems();
_updateData(result);
} catch (e, stk) {
state = AsyncValue.error(e, stk);
log("error catched");
}
_alreadyFetching = false;
}
}
Then I use a scroll controller attached to a CustomScrollView in order to call fetchNextBatch() when the scroll position changes:
#override
void initState() {
if (!controller.hasListeners && !controller.hasClients) {
log("listener added");
controller.addListener(() {
double maxScroll = controller.position.maxScrollExtent;
double position = controller.position.pixels;
if ((position > maxScroll * 0.2 || position == 0) && ref.read(paginationImagesProvider.notifier).mounted) {
ref.read(paginationImagesProvider.notifier).fetchNextBatch();
}
});
}
super.initState();
}
The problem is that when the StateNotifierProvider is fetching more data in the async function fetchNextBatch() and I go back on the navigator (like navigator.pop()), Flutter gives me an error:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Bad state: Tried to use PaginationNotifier after dispose was called.
Consider checking mounted.
I think that the async function responsible of loading data completes after I've popped the page from the Stack (which triggers a Provider dispose).
I'm probably missing something and I still haven't found a fix for this error, any help is appreciated.

Why I got : Error: MissingPluginException(No implementation found for method startScan on channel flutter_bluetooth_brazilian/methods)?

I'm trying to connect devices with Bluetooth and then share data. The problem now is that I always get: Missing Plugin Exception for flutter_bluetooth bluetooth_Brazilian.
this is bluetooth_manager.dart code:
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:rxdart/rxdart.dart';
import 'bluetooth_device.dart';
/// A BluetoothManager.
class BluetoothManager {
static const String NAMESPACE = 'flutter_bluetooth_brazilian';
static const int CONNECTED = 1;
static const int DISCONNECTED = 0;
static const MethodChannel _channel =
const MethodChannel('$NAMESPACE/methods');
static const EventChannel _stateChannel =
const EventChannel('$NAMESPACE/state');
Stream<MethodCall> get _methodStream => _methodStreamController.stream;
final StreamController<MethodCall> _methodStreamController =
StreamController.broadcast();
BluetoothManager._() {
_channel.setMethodCallHandler((MethodCall call) {
_methodStreamController.add(call);
return;
});
}
static BluetoothManager _instance = BluetoothManager._();
static BluetoothManager get instance => _instance;
// Future<bool> get isAvailable async =>
// await _channel.invokeMethod('isAvailable').then<bool>((d) => d);
// Future<bool> get isOn async =>
// await _channel.invokeMethod('isOn').then<bool>((d) => d);
Future<bool> get isConnected async =>
await _channel.invokeMethod('isConnected');
BehaviorSubject<bool> _isScanning = BehaviorSubject.seeded(false);
Stream<bool> get isScanning => _isScanning.stream;
BehaviorSubject<List<BluetoothDevice>> _scanResults =
BehaviorSubject.seeded([]);
Stream<List<BluetoothDevice>> get scanResults => _scanResults.stream;
PublishSubject _stopScanPill = new PublishSubject();
/// Gets the current state of the Bluetooth module
Stream<int> get state async* {
yield await _channel.invokeMethod('state').then((s) => s);
yield* _stateChannel.receiveBroadcastStream().map((s) => s);
}
/// Starts a scan for Bluetooth Low Energy devices
/// Timeout closes the stream after a specified [Duration]
Stream<BluetoothDevice> scan({
Duration timeout,
}) async* {
if (_isScanning.value == true) {
throw Exception('Another scan is already in progress.');
}
// Emit to isScanning
_isScanning.add(true);
final killStreams = <Stream>[];
killStreams.add(_stopScanPill);
if (timeout != null) {
killStreams.add(Rx.timer(null, timeout));
}
// Clear scan results list
_scanResults.add(<BluetoothDevice>[]);
try {
await _channel.invokeMethod('startScan');
} catch (e) {
print('Error starting scan.');
_stopScanPill.add(null);
_isScanning.add(false);
throw e;
}
yield* BluetoothManager.instance._methodStream
.where((m) => m.method == "ScanResult")
.map((m) => m.arguments)
.takeUntil(Rx.merge(killStreams))
.doOnDone(stopScan)
.map((map) {
final device = BluetoothDevice.fromJson(Map<String, dynamic>.from(map));
final List<BluetoothDevice> list = _scanResults.value;
int newIndex = -1;
list.asMap().forEach((index, e) {
if (e.address == device.address) {
newIndex = index;
}
});
if (newIndex != -1) {
list[newIndex] = device;
} else {
list.add(device);
}
_scanResults.add(list);
return device;
});
}
Future startScan({
Duration timeout,
}) async {
await scan(timeout: timeout).drain();
return _scanResults.value;
}
/// Stops a scan for Bluetooth Low Energy devices
Future stopScan() async {
await _channel.invokeMethod('stopScan');
_stopScanPill.add(null);
_isScanning.add(false);
}
Future<dynamic> connect(BluetoothDevice device) =>
_channel.invokeMethod('connect', device.toJson());
Future<dynamic> disconnect() => _channel.invokeMethod('disconnect');
Future<dynamic> destroy() => _channel.invokeMethod('destroy');
Future<dynamic> writeData(List<int> bytes) {
Map<String, Object> args = Map();
args['bytes'] = bytes;
args['length'] = bytes.length;
_channel.invokeMethod('writeData', args);
return Future.value(true);
}
}
flutter_bluetooth_brazilian doesn't support the web platform. You can check the supported platforms right on the plugin's page at https://pub.dev.

How to pass data between isolates in flutter dart

I am buiding an app were I want to run a batch operation in firestore and I want to run it in a different isolate. Here is my code for spawning the isolate:
Future<void> _startAnotherIsolate(String mediaUrl) async {
final isolate = await FlutterIsolate.spawn(isolate1,"hello"); // i need to pass 2 more
arguments
Timer(Duration(seconds: 5), () {
print("Pausing Isolate 1");
isolate.pause();
});
Timer(Duration(seconds: 10), () {
print("Resuming Isolate 1");
isolate.resume();
});
Timer(Duration(seconds: 20), () {
print("Killing Isolate 1");
isolate.kill();
});
}
My code for the isolate:
void isolate1(String data1, String data2) async {
await Firebase.initializeApp();
print("changing profile picture: $phone");
Timer.periodic(Duration(seconds: 1), (timer) => print("Timer Running From Isolate 1"));
var db = FirebaseFirestore.instance;
var batch = db.batch();
FirebaseFirestore.instance.collection("posts").doc(phone).collection("userPosts")
.get().then((querySnapshot) {
for (var document in querySnapshot.docs) {
try {
batch.update(document.reference,{'user_image': mediaUrl});
} on FormatException catch (error) {
// If a document ID is unparsable. Example "lRt931gu83iukSSLwyei" is unparsable.
// print("The document ${error.source} could not be parsed.");
return null;
}
}
return batch.commit();
});
}
I have seen This link and this link but they are not helpful
import 'dart:isolate';
class RequiredArgs {
late final SendPort sendPort;
late int id;
RequiredArgs(this.id, this.sendPort);
}
Future<void> main() async {
ReceivePort receivePort = ReceivePort();
RequiredArgs requiredArgs = RequiredArgs(1122, receivePort.sendPort);
Isolate isolate = await Isolate.spawn(download, requiredArgs);
var resp = await receivePort.first;
print(resp);
}
void download(RequiredArgs requiredArgs) {
final SendPort sendPort = requiredArgs.sendPort;
final id = requiredArgs.id;
print(id);
sendPort.send("yes");
}
We pass the value using the RequiredArgs class. Hope my answer helps.

Flutter AudioService plugin not working on Ios release

I'm using AudioService plugin and it works fine on Android and in debug mode in iOS. But once I test it on a real iOS device (in release mode) It's giving me exceptions
first at all
void quranStartListeningPoint() => AudioServiceBackground.run(() => QuranAudioService());
second this is my play Function
void startListeningToAyah({model.Ayah ayah, model.Surah surah}) {
if (AudioService.running) {
await AudioService.stop();
await Future.delayed(Duration(seconds: 1));
}
await AudioService.start(
androidNotificationColor: 0XFFB590EE,
backgroundTaskEntrypoint: quranStartListeningPoint,
params: {
'sheikhId': "$selectedReciter",
"ayahIndex": ayah.numberInSurah,
"surah": surah.number,
"quranModel": _quranDao.quranModelAsJson
},
);
}
Next I convert quranModelAsJson from a json to a model because I need the whole model in the Service Class and this is the only way to send it (as I think)
class QuranAudioService extends BackgroundAudioTask {
final _audioPlayer = AudioPlayer();
final String baseUrl = "https://cdn.alquran.cloud/media/audio/ayah/";
String ayahUrl;
int surahNumber;
int ayahIndex;
int renewSurah = 0;
QuranModel model;
Surah surah;
String sheikhId;
#override
Future<void> onStart(Map<String, dynamic> params) async {
await _audioPlayer.setReleaseMode(ReleaseMode.STOP);
implementParams(params);
onCompleteListener();
AudioServiceBackground.setState(
systemActions: [MediaAction.seekTo],
controls: getPlayControllers(),
playing: true,
processingState: AudioProcessingState.connecting);
ayahUrl = "$baseUrl$sheikhId/${surah.ayahs[ayahIndex].number}";
await _audioPlayer.play("$ayahUrl");
setMediaItem();
AudioServiceBackground.setState(
controls: getPlayControllers(),
playing: true,
processingState: AudioProcessingState.ready,
systemActions: [MediaAction.seekTo],
);
}
void setMediaItem() {
AudioServiceBackground.setMediaItem(
MediaItem(
extras: {"surahIndex": surahNumber, "renewSurah": renewSurah},
id: "$ayahIndex",
album: "${surah.englishName}",
title: "${surah.name}",
),
);
}
#override
Future<void> onPause() async {
// Broadcast that we're paused, and what controls are available.
AudioServiceBackground.setState(
controls: getPauseControllers(),
systemActions: [MediaAction.seekTo],
playing: false,
processingState: AudioProcessingState.ready);
// Pause the audio.
_audioPlayer.pause();
}
#override
Future<void> onStop() async {
_audioPlayer.stop();
if (ayahIndex == surah.ayahs.length) {
await AudioServiceBackground.setState(
controls: [replayControl],
playing: false,
processingState: AudioProcessingState.stopped);
} else {
await AudioServiceBackground.setState(
controls: [],
playing: false,
processingState: AudioProcessingState.stopped);
return super.onStop();
}
}
#override
Future<void> onPlay() async {
setMediaItem();
AudioServiceBackground.setState(
controls: getPlayControllers(),
playing: true,
processingState: AudioProcessingState.ready,
systemActions: [MediaAction.seekTo],
);
await _audioPlayer.play(ayahUrl);
renewSurah = 0;
}
#override
Future<void> onSkipToNext() async {
playNext();
}
#override
Future<void> onSkipToPrevious() async {
playPrevious();
}
// #override
// void onRewind() {
// ayahIndex = 0;
// ayahUrl = "$baseUrl$sheikhId/${surah.ayahs[ayahIndex].number}";
// this.onPlay();
// }
void implementParams(Map<String, dynamic> params) {
surahNumber = params["surah"] - 1;
ayahIndex = params["ayahIndex"] - 1;
sheikhId = params["sheikhId"];
if (model == null) model = QuranModel.fromJson(params["quranModel"]);
surah = model.surahs[surahNumber];
}
void onCompleteListener() {
_audioPlayer.onPlayerCompletion.listen((event) {
playNext();
});
}
void playNext() async {
ayahIndex++;
if (ayahIndex < surah.ayahs.length) {
ayahUrl = "$baseUrl$sheikhId/${surah.ayahs[ayahIndex].number}";
this.onPlay();
} else
changeNextSurahIndex();
}
void changeNextSurahIndex() {
renewSurah = 1;
if (surahNumber == 113) {
surahNumber = 0;
} else
surahNumber++;
ayahIndex = 0;
surah = model.surahs[surahNumber];
ayahUrl = "$baseUrl$sheikhId/${surah.ayahs[ayahIndex].number}";
this.onPlay();
}
void changePreviousSurahIndex() {
if (surahNumber == 0) {
surahNumber = 113;
} else
surahNumber--;
ayahIndex = 0;
renewSurah = 1;
surah = model.surahs[surahNumber];
ayahUrl = "$baseUrl$sheikhId/${surah.ayahs[ayahIndex].number}";
this.onPlay();
}
void playPrevious() async {
if (ayahIndex > 0) {
ayahIndex--;
ayahUrl = "$baseUrl$sheikhId/${surah.ayahs[ayahIndex].number}";
this.onPlay();
} else {
changePreviousSurahIndex();
}
}
List<MediaControl> getPlayControllers() {
return [
skipToNextControl,
pauseControl,
skipToPreviousControl,
stopControl
];
}
List<MediaControl> getPauseControllers() {
return [skipToNextControl, playControl, skipToPreviousControl, stopControl];
}
}
It was always giving me that ayahs was called on null
which means my json didnt converted to the model
so I deleted this implementation and added just a url to play
and the exception was
2020-08-31 17:58:08.458205-0400 Runner[700:75506] iOS => call startHeadlessService, playerId bb98efb6-a819-4ea7-a566-1dc6f0ff3df4
2020-08-31 17:58:08.471709-0400 Runner[700:76237] [VERBOSE-2:ui_dart_state.cc(166)] Unhandled Exception: NoSuchMethodError: The method '*' was called on null.
Receiver: null
Tried calling: *()
#0 AudioServiceBackground.run (package:audio_service/audio_service.dart:144)
<asynchronous suspension>

An eexception occurs when using flutter_downloader package

I'm trying to use flutter_downloader package to download some files (images/pdf). There is a listView with ListTiles each containing a button to start downloading when clicked but this error occurs when scrolling the list view.
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: 'package:flutter_downloader/src/downloader.dart': Failed assertion: line 30 pos 12: '!_initialized': FlutterDownloader.initialize() must be called only once!
//my code is like this:
import 'dart:io';
import 'dart:isolate';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
class DownloadFile extends StatefulWidget {
DownloadFile({this.downloadUrl});
final String downloadUrl;
#override
_DownloadFileState createState() => _DownloadFileState();
}
class _DownloadFileState extends State<DownloadFile> {
String downloadId;
String _localPath;
ReceivePort _port = ReceivePort();
#override
void initState(){
super.initState();
_init();
}
Future<void> _init() async {
await FlutterDownloader.initialize();
IsolateNameServer.registerPortWithName(
_port.sendPort, 'downloader_send_port');
_port.listen((dynamic data) {
String id = data[0];
DownloadTaskStatus status = data[1];
int progress = data[2];
print("status: $status");
print("progress: $progress");
print("id == downloadId: ${id == downloadId}");
});
FlutterDownloader.registerCallback(downloadCallback);
_localPath = (await _findLocalPath()) + '/Download';
final savedDir = Directory(_localPath);
bool hasExisted = await savedDir.exists();
if (!hasExisted) {
savedDir.create();
}
}
static void downloadCallback(String id, DownloadTaskStatus status, int progress) {
print(
'Background Isolate Callback: task ($id) is in status ($status) and process ($progress)');
final SendPort send =
IsolateNameServer.lookupPortByName('downloader_send_port');
send.send([id, status, progress]);
}
Future<String> _findLocalPath() async {
final directory = await getExternalStorageDirectory();
return directory.path;
}
Future<bool> _checkPermission() async {
if (Theme.of(context).platform == TargetPlatform.android) {
PermissionStatus permission = await PermissionHandler()
.checkPermissionStatus(PermissionGroup.storage);
if (permission != PermissionStatus.granted) {
Map<PermissionGroup, PermissionStatus> permissions =
await PermissionHandler()
.requestPermissions([PermissionGroup.storage]);
if (permissions[PermissionGroup.storage] == PermissionStatus.granted) {
return true;
}
} else {
return true;
}
} else {
return true;
}
return false;
}
//----------------------------------------------------------------
#override
void dispose() {
super.dispose();
}
//---------------------------------------------------------------
#override
Widget build(BuildContext context) {
return FlatButton(
onPressed: () async {
if (await _checkPermission()) {
final taskId = await FlutterDownloader.enqueue(
url: widget.downloadUrl,
savedDir: _localPath,
showNotification:
true, // show download progress in status bar (for Android)
openFileFromNotification:
true, // click on notification to open downloaded file (for Android)
);
downloadId = taskId;
}
},
child: Text('Downloa File',style: TextStyle(color: Colors.teal),)
);
}
}
According to the Usage section in the flutter_downloader package and the error you are getting, you must call the FlutterDownloader.initialize not more than once.
You can do that in the main method of your application, just like so:
WidgetsFlutterBinding.ensureInitialized();
await FlutterDownloader.initialize();