flutter_cache_manager icon indicating copy to clipboard operation
flutter_cache_manager copied to clipboard

cache mp4 video file not played by VideoPlayer package on ios

Open muhammadCodeSh opened this issue 2 years ago • 6 comments

🐛 Bug Report

I use flutter cache manager last version to cache images and videos it works well on android also on ios it cache and shows image files perfectly, but cached mp4 or .ts video files can not be played by the Video player package on ios, is it required any extra configuration or permission on ios?

Platform:

  • [x] :iphone: iOS

muhammadCodeSh avatar Mar 26 '23 12:03 muhammadCodeSh

same issue

osangma avatar Jul 18 '23 10:07 osangma

The file extension is .bin, so the iOS video player isn't playing it. I renamed the file with a .mp4 extension, and now it is working.

jerrypaulsam avatar Nov 13 '23 17:11 jerrypaulsam

use this // 1> fileinfo will provide name of the path in which video is stored in temporary directory var fileInfo = await DependencyInjection.kCacheManager .getFileFromCache("Your url");

// 2> using rename function will change the name of the path final name = await fileInfo!.file .rename(fileInfo.file.path.replaceAll(".bin", ".mp4"));

// 3> after that use the name on your link

controller = VideoPlayerController.file(name)

// work like a charm

voltzylex avatar Jan 15 '24 10:01 voltzylex

The file extension is set from the headers. If I hack it manually it works fine. Maybe this helps:

web_helper.dart:

  CacheObject _setDataFromHeaders(
      CacheObject cacheObject, FileServiceResponse response) {
    final fileExtension = response.fileExtension;
    ...

    if (!statusCodesFileNotChanged.contains(response.statusCode)) {
      ...
      // Store new file on different path
      // filePath = '${const Uuid().v1()}$fileExtension';
      filePath = '${const Uuid().v1()}.mp4';
    }
    ...
  }

Http getter is where it is actually set:

@override
String get fileExtension {
  var fileExtension = '';
  final contentTypeHeader = _header(HttpHeaders.contentTypeHeader);
  if (contentTypeHeader != null) {
    final contentType = ContentType.parse(contentTypeHeader);
    fileExtension = contentType.fileExtension;
  }
  return fileExtension;
}

guneyozsan avatar Jan 07 '25 03:01 guneyozsan

We fixed this by setting the header on the server as video/mp4.

guneyozsan avatar Feb 24 '25 11:02 guneyozsan

Here’s a quick fix using this extension function if you don’t want to override
the dependency in pubspec.yaml or if you don’t have access to set the content type in the header:

extension CacheManagerX on CacheManager {
  Future<File> getSingleFileFixedExtension(String url) async {
    final file = await getSingleFile(url);
    final localPath = file.path;

    if (!localPath.endsWith('.bin')) return file;

    final uri = Uri.tryParse(url);
    if (uri == null) return file;

    final ext = _getExtension(uri.path);
    if (ext.isEmpty) return file;

    final targetPath = localPath.substring(0, localPath.length - 4) + ext;
    if (targetPath == localPath) return file;

    final targetFile = File(targetPath);
    if (await targetFile.exists()) return targetFile;

    final cachedObject = await store.retrieveCacheData(url);
    final renamed = await file.rename(targetPath);

    if (cachedObject != null) {
      await store.putFile(cachedObject.copyWith(relativePath: targetPath));
    }

    return renamed;
  }

  String _getExtension(String path) {
    final dotIndex = path.lastIndexOf('.');
    if (dotIndex == -1 || dotIndex == path.length - 1) {
      return '';
    }
    return path.substring(dotIndex);
  }
}

This is just a quick fix. There might be better ways to achieve the same result by using a direct download method and writing the file with the correct extension upfront (avoiding the rename overhead). I only needed a pre-implemented download functionality along with cacheable object creation, so this worked for my use case.

AliAzizi avatar Sep 23 '25 22:09 AliAzizi