downloadFromUrlStream static method

Future<DownloadResult> downloadFromUrlStream({
  1. required String url,
  2. required String filename,
  3. ProgressCallback? onProgress,
  4. CompleteCallback? onComplete,
  5. ErrorCallback? onError,
  6. bool allowSelfSignedCertificate = false,
})

Downloads a file from URL using stream method with progress tracking. Works on all platforms and provides better memory efficiency.

Implementation

static Future<DownloadResult> downloadFromUrlStream({
  required String url,
  required String filename,
  ProgressCallback? onProgress,
  CompleteCallback? onComplete,
  ErrorCallback? onError,
  bool allowSelfSignedCertificate = false,
}) async {
  try {
    // Check storage permission for mobile platforms
    if (!kIsWeb && (io.Platform.isAndroid || io.Platform.isIOS)) {
      final hasPermission = await PermissionUtils.requestStoragePermission();
      if (!hasPermission) {
        throw PermissionDownloadException(
          PermissionUtils.getPermissionErrorMessage(),
          url: url,
        );
      }
    }

    // For web platform, use the existing optimized download method
    if (kIsWeb) {
      return await _downloadForWeb(
        url: url,
        fileName: filename,
        onProgress: onProgress,
        onComplete: onComplete,
        onError: onError,
      );
    }

    // For native platforms, use stream-based approach
    // Create HTTP client
    final client = _createHttpClient(allowSelfSignedCertificate);

    try {
      // Make HTTP request to get stream
      final request = http.Request('GET', Uri.parse(url));
      request.headers.addAll({
        'User-Agent': 'UniversalDownloader/1.0.0 (Flutter Stream)',
        'Accept': '*/*',
      });

      final streamedResponse = await client.send(request);

      if (streamedResponse.statusCode != 200) {
        throw NetworkDownloadException(
          'Failed to download file: HTTP ${streamedResponse.statusCode}',
          url: url,
        );
      }

      final totalBytes = streamedResponse.contentLength ?? 0;
      var downloadedBytes = 0;

      // Convert HTTP stream to Stream<int> and track progress
      final streamController = StreamController<int>();

      streamedResponse.stream.listen(
        (chunk) {
          for (final byte in chunk) {
            streamController.add(byte);
            downloadedBytes++;
          }

          // Report progress
          if (totalBytes > 0 && onProgress != null) {
            onProgress(DownloadProgress.fromBytes(
              totalBytes: totalBytes,
              downloadedBytes: downloadedBytes,
            ));
          }
        },
        onDone: () {
          streamController.close();
        },
        onError: (error) {
          streamController.addError(error);
        },
      );

      // Use downloadStream to save the file
      final dir =
          await _getDownloadDirectory(false); // Use Downloads directory
      final fullPath = path.join(dir.path, filename);

      await downloadStream(
        stream: streamController.stream,
        filename: filename,
      );

      onComplete?.call(fullPath);

      return DownloadResult.success(
        filePath: fullPath,
        url: url,
        fileName: filename,
        totalBytes: downloadedBytes,
      );
    } finally {
      client.close();
    }
  } catch (e) {
    final errorMessage = e.toString();
    onError?.call(errorMessage);
    return DownloadResult.failure(
      url: url,
      fileName: filename,
      errorMessage: errorMessage,
    );
  }
}