fluttercommunity / fluttercommunity/flutter_downloader

Download callbacks not firing in production for some users

Open
#1,000 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Kotlin
Stars
940
Forks
561
Avg merge
1h 18m
Merged PRs (30d)
1

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
```dart
// Called during app startup in main.dart
@pragma('vm:entry-point')
Future initializeBgDownloader() async {
await FlutterDownloader.initialize(debug: kDebugMode);
}
```

- This `BgDownloaderHost` is wrapper at the top level of App.

#### Callback Registration & Isolate Setup
```dart
class _BgDownloaderHostState extends State {
@override
void initState() {
super.initState();
bgDownloader = GetIt.I.get();

// 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
```dart
@pragma('vm:entry-point')
Future 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
```dart
Future _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()` returns `true` (callback handle exists)
- ✅ Port registration succeeds (`IsolateNameServer.registerPortWithName` returns `true`)
- ✅ 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`

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.