-
Notifications
You must be signed in to change notification settings - Fork 550
Open
Description
We're experiencing a critical issue where download callbacks are not being triggered on certain Android devices, specifically affecting multiple device brands including Redmi, Vivo, Oppo, and OnePlus etc... This appears to be a broader compatibility issue across these manufacturers rather than being specific to particular models.
Issue symptoms:
- ✅ Downloads enqueue successfully via
FlutterDownloader.enqueue() - ✅ Download tasks appear in database with correct status when queried
- ❌ Registered callback function (
downloadCallback) is never invoked - ❌ Progress updates and completion notifications are completely lost
- ❌ Users see downloads stuck at 0% progress indefinitely
Environment
-
flutter_downloader version:
^1.11.8 -
Calling this in the
main.dart
Initialization
// Called during app startup in main.dart
@pragma('vm:entry-point')
Future<void> initializeBgDownloader() async {
await FlutterDownloader.initialize(debug: kDebugMode);
}- This
BgDownloaderHostis wrapper at the top level of App.
Callback Registration & Isolate Setup
class _BgDownloaderHostState extends State<BgDownloaderHost> {
@override
void initState() {
super.initState();
bgDownloader = GetIt.I.get<BgDownloader>();
// First bind the background isolate
bgDownloader._startListening();
// Then register callback after isolate binding - recommended timing
FlutterDownloader.registerCallback(downloadCallback);
}
}
void _startListening({int attempt = 1}) {
// Prevent infinite retry loops - give up after 5 attempts
if (attempt > 5) {
logNonFatal("Port registration failed after 5 attempts");
return;
}
// Remove existing port mapping before registering
IsolateNameServer.removePortNameMapping('downloader_send_port');
// Register new port
final registrationSuccess = IsolateNameServer.registerPortWithName(
port.sendPort, 'downloader_send_port');
if (!registrationSuccess) {
_stopListening();
_startListening(attempt: attempt + 1); // Retry logic
return;
}
port.listen((dynamic data) async {
String id = data[0];
DownloadTaskStatus status = DownloadTaskStatus.fromInt(data[1]);
int progress = data[2];
_invokeListeners(id, status, progress);
});
}
bool isCallbackRegistered() {
return PluginUtilities.getCallbackHandle(downloadCallback) != null;
}Download Callback Function
@pragma('vm:entry-point')
Future<void> downloadCallback(String id, int status, int progress) async {
try {
final SendPort? send = IsolateNameServer.lookupPortByName('downloader_send_port');
if (send == null) {
developer.log("SendPort lookup failed - progress update lost for task $id");
return;
}
send.send([id, status, progress]);
} catch (e, st) {
developer.log("$e", name: "DownloadCallback", level: 1200, stackTrace: st);
}
}Additional Code
Future<Directory> _saveDirectory() async {
Directory directory;
if (Platform.isAndroid) {
final path = await AndroidDownloadPath.downloadPath();
directory = Directory(path);
} else {
directory = await getApplicationDocumentsDirectory();
}
return directory;
}
final taskId = await FlutterDownloader.enqueue(
url: url,
savedDir: savedDir.absolute.path,
showNotification: false,
openFileFromNotification: true,
saveInPublicStorage: true,
fileName: fileName,
requiresStorageNotLow: false,
);🔍 Diagnostic Information
Our comprehensive health checks reveal:
- ✅
isCallbackRegistered()returnstrue(callback handle exists) - ✅ Port registration succeeds (
IsolateNameServer.registerPortWithNamereturnstrue) - ✅ Downloads are enqueued successfully and appear in database
Any insights or potential fixes would be greatly appreciated. We're happy to provide additional debugging information or test potential solutions.
Labels: bug, android, callback, isolate-communication
Metadata
Metadata
Assignees
Labels
No labels