registerCallback not working in flutter 3.29 and flutter_downloader 1.12.0
I initialize on main.dart the plugin. In a streamstore I create the receivePort and IsolateNameServer. After that add the listen of port and add registercallback above. In 1.11.8 was working, in 1.12.0 the callback is not working.
Hey @pachecotatih I also faced the same error did you find the solution?
I reinstall to flutter 3.24 (older version) and I used to flutter_downloader 1.11.8... about this, nothing solution
And now, in 1.11.8 version and flutter 3.24, I have the problem with initialize download, and when I close the app, the download is canceled. I'm testing on my device, it's used to android 14
Yes same issue. I had to update the flutter version because AppConnect required to upload apps with SDK 18 after April 24. So updated to the latest Flutter version 3.29. Everything else works fine, but this package does not work like it supposed to. I downloaded the example code in the project, and the same issue. When I click on download file, the callback does not work and gives me this error:
E/libEGL ( 4649): called unimplemented OpenGL ES API D/EGL_emulation( 4649): app_time_stats: avg=284.93ms min=3.45ms max=10068.07ms count=36 D/DownloadWorker( 4649): DownloadWorker{url=http://enos.itcollege.ee/~jpoial/allalaadimised/reading/Android-Programming-Cookbook.pdf,filename=null,savedDir=/data/user/0/vn.hunghd.example/app_flutter,header={"auth":"test_for_sql_encoding"},isResume=false,status=ENQUEUED E/DartVM ( 4649): ERROR: To access 'package:flutter_downloader_example/home_page.dart::_MyHomePageState' from native code, it must be annotated. E/DartVM ( 4649): ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md E/flutter ( 4649): [ERROR:flutter/lib/ui/dart_runtime_hooks.cc(38)] Dart Error: ERROR: To access 'package:flutter_downloader_example/home_page.dart::_MyHomePageState' from native code, it must be annotated. E/flutter ( 4649): ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md D/DownloadWorker( 4649): Update notification: {notificationId: 6, title: http://enos.itcollege.ee/~jpoial/allalaadimised/reading/Android-Programming-Cookbook.pdf, status: RUNNING, progress: 0} E/flutter ( 4649): [ERROR:flutter/shell/common/shell.cc(115)] Dart Error: ERROR: To access 'package:flutter_downloader_example/home_page.dart::_MyHomePageState' from native code, it must be annotated. E/flutter ( 4649): ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md E/flutter ( 4649): [ERROR:flutter/shell/common/shell.cc(115)] Dart Error: ERROR: To access 'package:flutter_downloader_example/home_page.dart::_MyHomePageState' from native code, it must be annotated. E/flutter ( 4649): ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md D/DownloadWorker( 4649): Open connection to http://enos.itcollege.ee/~jpoial/allalaadimised/reading/Android-Programming-Cookbook.pdf D/DownloadWorker( 4649): Headers = {"auth":"test_for_sql_encoding"} D/TrafficStats( 4649): tagSocket(5) with statsTag=0xffffffff, statsUid=-1 D/DownloadWorker( 4649): Response with redirection code D/DownloadWorker( 4649): Location = https://enos.itcollege.ee/~jpoial/allalaadimised/reading/Android-Programming-Cookbook.pdf D/DownloadWorker( 4649): New url: https://enos.itcollege.ee/~jpoial/allalaadimised/reading/Android-Programming-Cookbook.pdf D/DownloadWorker( 4649): Open connection to https://enos.itcollege.ee/~jpoial/allalaadimised/reading/Android-Programming-Cookbook.pdf D/DownloadWorker( 4649): Headers = {"auth":"test_for_sql_encoding"} D/TrafficStats( 4649): tagSocket(150) with statsTag=0xffffffff, statsUid=-1 I/trustAllHosts( 4649): checkServerTrusted D/DownloadWorker( 4649): Content-Type = application/pdf D/DownloadWorker( 4649): Content-Length = 8620159 D/DownloadWorker( 4649): Charset = null D/DownloadWorker( 4649): Content-Disposition = null D/DownloadWorker( 4649): fileName = Android-Programming-Cookbook.pdf E/DownloadWorker( 4649): It looks like you are trying to save file in public storage but not setting 'saveInPublicStorage' to 'true' D/DownloadWorker( 4649): Update too frequently!!!!, but it is the final update, we should sleep a second to ensure the update call can be processed E/DartVM ( 4649): ERROR: To access 'package:flutter_downloader_example/home_page.dart::_MyHomePageState' from native code, it must be annotated. E/DartVM ( 4649): ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md E/flutter ( 4649): [ERROR:flutter/lib/ui/dart_runtime_hooks.cc(38)] Dart Error: ERROR: To access 'package:flutter_downloader_example/home_page.dart::_MyHomePageState' from native code, it must be annotated. E/flutter ( 4649): ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md E/flutter ( 4649): [ERROR:flutter/shell/common/shell.cc(115)] Dart Error: ERROR: To access 'package:flutter_downloader_example/home_page.dart::_MyHomePageState' from native code, it must be annotated. E/flutter ( 4649): ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md E/flutter ( 4649): [ERROR:flutter/shell/common/shell.cc(115)] Dart Error: ERROR: To access 'package:flutter_downloader_example/home_page.dart::_MyHomePageState' from native code, it must be annotated. E/flutter ( 4649): ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md D/DownloadWorker( 4649): Update notification: {notificationId: 6, title: http://enos.itcollege.ee/~jpoial/allalaadimised/reading/Android-Programming-Cookbook.pdf, status: FAILED, progress: -1} W/System.err( 4649): java.lang.NullPointerException W/System.err( 4649): at vn.hunghd.flutterdownloader.DownloadWorker.downloadFile(DownloadWorker.kt:395) W/System.err( 4649): at vn.hunghd.flutterdownloader.DownloadWorker.doWork(DownloadWorker.kt:206) W/System.err( 4649): at androidx.work.Worker$1.run(Worker.java:82) W/System.err( 4649): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) W/System.err( 4649): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644) W/System.err( 4649): at java.lang.Thread.run(Thread.java:1012) I/WM-WorkerWrapper( 4649): Worker result FAILURE for Work [ id=739e23b8-5c26-4e31-b0b4-a7a15605ea74, tags={ vn.hunghd.flutterdownloader.DownloadWorker, flutter_download_task } ]
Ah, the solution is to mark the whole class with the annotation
@pragma('vm:entry-point') // Add the annotation here
class _MyHomePageState extends State<MyHomePage> {
// ... your existing code ...
}
same issue here
Ah, the solution is to mark the whole class with the annotation
@pragma('vm:entry-point') // Add the annotation here class _MyHomePageState extends State<MyHomePage> { // ... your existing code ... }
did not work for me
same issue. it is not working with v3.29.0
Try it this way (works for me):
class MyClass extends StatefulWidget { const MyClass({super.key});
@override State<MyClass> createState() => _MyClassState(); }
@pragma("vm:entry-point"). <<<----- ADD IT HERE class _MyClassState extends State<MyClass> {
I got this working on Flutter 3.29.2 with flutter_downloader 1.12.0 by adding the provider block in all manifests and the res/xml/provider_paths.xml. The downloader documentation has the provider block, and the xml for provider_paths.xml should look something like this:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <root-path name="root" path="." /> <external-path name="external_files" path="." /> </paths>
Ah, the solution is to mark the whole class with the annotation
@pragma('vm:entry-point') // Add the annotation here class _MyHomePageState extends State<MyHomePage> { // ... your existing code ... }
did not work for me
Annotating the class (not just the callback method) worked for me.
Initially, from initiating one download I got these all error messages
ERROR: To access 'package:kencube/download_controller.dart::DownloadController' from native code, it must be annotated.
ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md
[ERROR:flutter/lib/ui/dart_runtime_hooks.cc(38)] Dart Error: ERROR: To access 'package:kencube/download_controller.dart::DownloadController' from native code, it must be annotated.
ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md
[ERROR:flutter/shell/common/shell.cc(115)] Dart Error: ERROR: To access 'package:kencube/download_controller.dart::DownloadController' from native code, it must be annotated.
ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md
[ERROR:flutter/shell/common/shell.cc(115)] Dart Error: ERROR: To access 'package:kencube/download_controller.dart::DownloadController' from native code, it must be annotated.
ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md
ERROR: To access 'package:kencube/download_controller.dart::DownloadController' from native code, it must be annotated.
ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md
[ERROR:flutter/lib/ui/dart_runtime_hooks.cc(38)] Dart Error: ERROR: To access 'package:kencube/download_controller.dart::DownloadController' from native code, it must be annotated.
ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md
[ERROR:flutter/shell/common/shell.cc(115)] Dart Error: ERROR: To access 'package:kencube/download_controller.dart::DownloadController' from native code, it must be annotated.
ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md
[ERROR:flutter/shell/common/shell.cc(115)] Dart Error: ERROR: To access 'package:kencube/download_controller.dart::DownloadController' from native code, it must be annotated.
ERROR: See https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/aot/entry_point_pragma.md
I did have the callback annotated with @pragma('vm:entry-point') - and it worked nicely before the Flutter upgrade to 3.29
Only after the upgrade I started to see these error messages.
The odd thing was that these errors also appeared when I did not register the callback (when I remarked the FlutterDownloader.registerCallback()!
I do not not understand what in my DownloadController FlutterDownloader was calling then and why, but it cannot have been the callback...
But in any case, once I added the annotation to the class itself, all was back to normal again and it worked without error messages.
@pragma('vm:entry-point') // Make sure optimizer does not think this is unused!
class DownloadController extends GetxController {
...
So bottom line: It fixed the issue for me.
I had to add the annotation to the class and the callback function. Adding it only to the class didn't help in my case.
Yes, sorry for the unprecise wording. I also in the end had it on both, the callback and the class.
@pragma('vm:entry-point') worked for
here is usage
`import 'dart:async'; import 'dart:io'; import 'dart:isolate'; import 'dart:ui'; import 'package:flutter_downloader/flutter_downloader.dart'; import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart';
@pragma('vm:entry-point') class AudioDownloadService { // Stream controller for download progress final StreamController<DownloadProgress> _downloadProgressController = StreamController<DownloadProgress>.broadcast();
Stream<DownloadProgress> get downloadProgressStream => _downloadProgressController.stream;
// Port for receiving download updates final ReceivePort _port = ReceivePort();
// Map to track download tasks final Map<String, String> _downloadTasks = {};
AudioDownloadService() { _init(); }
void _init() { // Register callback for download updates IsolateNameServer.registerPortWithName( _port.sendPort, 'downloader_send_port', );
_port.listen((dynamic data) {
final String id = data[0];
final int status = data[1];
final int progress = data[2];
_handleDownloadUpdate(id, status, progress);
});
// Set up the callback
FlutterDownloader.registerCallback(downloadCallback);
}
// Static callback function for download updates @pragma('vm:entry-point') static void downloadCallback(String id, int status, int progress) { final SendPort? send = IsolateNameServer.lookupPortByName( 'downloader_send_port', ); send?.send([id, status, progress]); }
void _handleDownloadUpdate(String taskId, int status, int progress) { final downloadStatus = _mapDownloadStatus(status);
_downloadProgressController.add(
DownloadProgress(
received: progress,
total: 100,
percentage: progress.toDouble(),
speed: 0.0, // flutter_downloader doesn't provide speed
status: downloadStatus,
taskId: taskId,
),
);
}
DownloadStatus _mapDownloadStatus(int status) { // Based on flutter_downloader status codes: // 0: undefined, 1: enqueued, 2: running, 3: complete, 4: failed, 5: canceled, 6: paused switch (status) { case 2: // running return DownloadStatus.downloading; case 3: // complete return DownloadStatus.completed; case 4: // failed return DownloadStatus.failed; case 5: // canceled return DownloadStatus.failed; case 6: // paused return DownloadStatus.downloading; default: return DownloadStatus.idle; } }
Future<String?> downloadMp3(String url, {String? fileName}) async { try { // Request permissions await _requestPermissions();
// Get download directory - using internal storage only
Directory directory = await getApplicationDocumentsDirectory();
final downloadPath = '${directory.path}/downloads';
// Create directory if it doesn't exist
await Directory(downloadPath).create(recursive: true);
// Generate filename
fileName ??= 'audio_${DateTime.now().millisecondsSinceEpoch}.mp3';
// Initialize progress
_downloadProgressController.add(
DownloadProgress(
received: 0,
total: 100,
percentage: 0.0,
speed: 0.0,
status: DownloadStatus.downloading,
),
);
// Start download
final taskId = await FlutterDownloader.enqueue(
url: url,
savedDir: downloadPath,
fileName: fileName,
headers: {}, // Optional headers
showNotification: false, // Disable notifications to avoid icon issues
openFileFromNotification: false,
saveInPublicStorage: false, // Set to false to avoid permission issues
);
if (taskId != null) {
_downloadTasks[taskId] = fileName;
// Wait for download completion
await _waitForDownloadCompletion(taskId);
final filePath = '$downloadPath/$fileName';
return filePath;
}
return null;
} catch (e) {
print('Download error: $e');
_downloadProgressController.add(
DownloadProgress(
received: 0,
total: 100,
percentage: 0.0,
speed: 0.0,
status: DownloadStatus.failed,
),
);
return null;
}
}
Future
late StreamSubscription subscription;
subscription = downloadProgressStream.listen((progress) {
if (progress.taskId == taskId) {
if (progress.status == DownloadStatus.completed ||
progress.status == DownloadStatus.failed) {
subscription.cancel();
completer.complete();
}
}
});
return completer.future;
}
Future
Future
Future
Future
Future<List<DownloadTask>?> getDownloadTasks() async { return await FlutterDownloader.loadTasks(); }
void dispose() { _downloadProgressController.close(); _port.close(); IsolateNameServer.removePortNameMapping('downloader_send_port'); }
Future
// For Android 10 and below
if (await Permission.storage.isDenied) {
await Permission.storage.request();
}
// For Android 11 and above
if (await Permission.manageExternalStorage.isDenied) {
await Permission.manageExternalStorage.request();
}
}
} }
// Download progress model class DownloadProgress { final int received; final int total; final double percentage; final double speed; // bytes per second final DownloadStatus status; final String? taskId;
DownloadProgress({ required this.received, required this.total, required this.percentage, required this.speed, required this.status, this.taskId, });
String get formattedSpeed { if (speed < 1024) { return '${speed.toStringAsFixed(1)} B/s'; } else if (speed < 1024 * 1024) { return '${(speed / 1024).toStringAsFixed(1)} KB/s'; } else { return '${(speed / (1024 * 1024)).toStringAsFixed(1)} MB/s'; } }
String get formattedSize { final totalMB = total / (1024 * 1024); final receivedMB = received / (1024 * 1024); return '${receivedMB.toStringAsFixed(1)} MB / ${totalMB.toStringAsFixed(1)} MB'; } }
enum DownloadStatus { downloading, completed, failed, idle } `
here is ui
import 'package:audio_background_download/service/audio_download_service.dart'; import 'package:flutter/material.dart';
class AudioDownloadScreen extends StatefulWidget { const AudioDownloadScreen({super.key});
@override State<AudioDownloadScreen> createState() => _AudioDownloadScreenState(); }
@pragma('vm:entry-point') class _AudioDownloadScreenState extends State<AudioDownloadScreen> { final String _audioUrl = "https://github.com/rafaelreis-hotmart/Audio-Sample-files/raw/master/sample.mp3"; bool _isDownloading = false;
final AudioDownloadService audioService = AudioDownloadService();
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('MP3 Background Downloader'), backgroundColor: Colors.blue, foregroundColor: Colors.white, ), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Card( elevation: 4, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Audio URL:', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16, ), ), const SizedBox(height: 8), Text( _audioUrl, style: const TextStyle(fontSize: 12, color: Colors.grey), ), ], ), ), ), const SizedBox(height: 20),
// Download Progress Section
StreamBuilder<DownloadProgress>(
stream: audioService.downloadProgressStream,
builder: (context, snapshot) {
final progress = snapshot.data;
if (progress != null &&
progress.status == DownloadStatus.downloading) {
return Card(
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Download Progress',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
Text(
'${progress.percentage.toStringAsFixed(1)}%',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: Colors.blue,
),
),
],
),
const SizedBox(height: 10),
LinearProgressIndicator(
value: progress.percentage / 100,
backgroundColor: Colors.grey[300],
valueColor: const AlwaysStoppedAnimation<Color>(
Colors.blue,
),
minHeight: 8,
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
progress.formattedSize,
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
Text(
progress.formattedSpeed,
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
],
),
],
),
),
);
}
return const SizedBox.shrink();
},
),
const SizedBox(height: 20),
// Download Button
ElevatedButton.icon(
onPressed: _isDownloading ? null : _downloadAudio,
icon:
_isDownloading
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: const Icon(Icons.download),
label: Text(_isDownloading ? 'Downloading...' : 'Download MP3'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 12),
),
),
const SizedBox(height: 10),
],
),
),
);
}
Future
try {
final filePath = await audioService.downloadMp3(
_audioUrl,
fileName: 'test_audio.mp3',
);
if (filePath != null) {
setState(() {});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Row(
children: [
Icon(Icons.check_circle, color: Colors.white),
SizedBox(width: 8),
Text('Download completed successfully!'),
],
),
backgroundColor: Colors.green,
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Row(
children: [
Icon(Icons.error, color: Colors.white),
SizedBox(width: 8),
Text('Download failed!'),
],
),
backgroundColor: Colors.red,
),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Row(
children: [
const Icon(Icons.error, color: Colors.white),
const SizedBox(width: 8),
Expanded(child: Text('Error: $e')),
],
),
backgroundColor: Colors.red,
),
);
} finally {
setState(() {
_isDownloading = false;
});
}
} }