cache mp4 video file not played by VideoPlayer package on ios
🐛 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
same issue
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.
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
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;
}
We fixed this by setting the header on the server as video/mp4.
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.