Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions MIGRATION-v3-to-v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,44 @@ This guide will help you migrate from `cached_video_player_plus` v3.x.x to v4.0.

Version 4.0.0 introduces a major API restructure that simplifies usage while maintaining all existing functionality. The package now uses a class-based approach instead of the previous controller-widget pattern.

## 💿 Storage Migration: get_storage → shared_preferences

Version 4.0.0 migrates from `get_storage` to `shared_preferences` for storing cached video metadata. This change improves compatibility and reduces dependencies.

### 🔄 Automatic Migration

The package includes an automatic migration utility that preserves your existing cached video data:

```dart
import 'package:cached_video_player_plus/util/migration_utils.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();

// Migrate cached video data from get_storage to shared_preferences
// This must be called before runApp() to ensure data is available
await migrateCachedVideoDataToSharedPreferences();

runApp(MyApp());
}
```

### ⚠️ Important Migration Notes

1. **Call migration before runApp()**: The migration function must be called and awaited before `runApp()` to ensure cached data is available.

2. **One-time migration**: The migration automatically tracks completion and won't run multiple times.

3. **Debug output**: In debug mode, you'll see console output indicating how many cache entries were migrated.

4. **Automatic cleanup**: After successful migration, the old get_storage data is automatically cleared.

### 🗂️ What Gets Migrated

- **Cache timestamps**: Integer timestamps for cache invalidation
- **Cache metadata**: All cached video metadata stored in get_storage
- **Migration completion flag**: Ensures migration only runs once

## 🚨 Breaking Changes

### 1. API Architecture Change
Expand Down
7 changes: 7 additions & 0 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ PODS:
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
Expand All @@ -13,6 +16,7 @@ PODS:
DEPENDENCIES:
- Flutter (from `Flutter`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)

Expand All @@ -21,6 +25,8 @@ EXTERNAL SOURCES:
:path: Flutter
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite_darwin:
:path: ".symlinks/plugins/sqflite_darwin/darwin"
video_player_avfoundation:
Expand All @@ -29,6 +35,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b

Expand Down
9 changes: 8 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ import 'package:flutter/material.dart';

// This Package
import 'package:cached_video_player_plus/cached_video_player_plus.dart';
import 'package:cached_video_player_plus/util/migration_utils.dart';

// Third Party Packages
import 'package:video_player/video_player.dart';

void main() {
void main() async {
WidgetsFlutterBinding.ensureInitialized();

// Migrate cached video data from get_storage to shared_preferences
// This should be called ONCE before removing get_storage dependency
await migrateCachedVideoDataToSharedPreferences();

runApp(const MyApp());
}

Expand Down
2 changes: 2 additions & 0 deletions example/macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import FlutterMacOS
import Foundation

import path_provider_foundation
import shared_preferences_foundation
import sqflite_darwin
import video_player_avfoundation

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
}
7 changes: 7 additions & 0 deletions example/macos/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ PODS:
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
Expand All @@ -13,6 +16,7 @@ PODS:
DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
- video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`)

Expand All @@ -21,6 +25,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
sqflite_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin
video_player_avfoundation:
Expand All @@ -29,6 +35,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b

Expand Down
60 changes: 58 additions & 2 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,62 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.28.0"
shared_preferences:
dependency: transitive
description:
name: shared_preferences
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
url: "https://pub.dev"
source: hosted
version: "2.5.3"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
url: "https://pub.dev"
source: hosted
version: "2.4.10"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
sky_engine:
dependency: transitive
description: flutter
Expand Down Expand Up @@ -379,10 +435,10 @@ packages:
dependency: transitive
description:
name: video_player_avfoundation
sha256: "0d47db6cbf72db61d86369219efd35c7f9d93515e1319da941ece81b1f21c49c"
sha256: d22d83c5aa3b4fd11c2d8265178ff8cb7be9fd60908556ae3733cb58d270098e
url: "https://pub.dev"
source: hosted
version: "2.7.2"
version: "2.7.3"
video_player_platform_interface:
dependency: transitive
description:
Expand Down
16 changes: 3 additions & 13 deletions lib/src/cached_video_player_plus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:get_storage/get_storage.dart';
import 'package:video_player/video_player.dart';

import 'video_cache_manager.dart';
import 'video_player_storage.dart';

/// The default cache manager for video file caching operations.
final _defaultCacheManager = VideoCacheManager();

/// Global storage for cache metadata and expiration timestamps.
final _storage = GetStorage('cached_video_player_plus');
final _storage = VideoPlayerStorage();

/// Generates a storage key for the given [dataSource].
String _getCacheKey(String dataSource) {
Expand Down Expand Up @@ -289,8 +289,6 @@ class CachedVideoPlayerPlus {
return;
}

await _storage.initStorage;

late String realDataSource;
bool isCacheAvailable = false;

Expand All @@ -304,7 +302,7 @@ class CachedVideoPlayerPlus {
}

if (cachedFile != null) {
final cachedElapsedMillis = _storage.read(_cacheKey);
final cachedElapsedMillis = await _storage.read(_cacheKey);

if (cachedElapsedMillis != null) {
final now = DateTime.timestamp();
Expand Down Expand Up @@ -413,8 +411,6 @@ class CachedVideoPlayerPlus {
///
/// The cached video file and its metadata will be permanently deleted.
Future<void> removeFromCache() async {
await _storage.initStorage;

await Future.wait([
_cacheManager.removeFile(_cacheKey),
_storage.remove(_cacheKey),
Expand All @@ -436,8 +432,6 @@ class CachedVideoPlayerPlus {
Uri url, {
CacheManager? cacheManager,
}) async {
await _storage.initStorage;

final urlString = url.toString();
final cacheKey = _getCacheKey(urlString);

Expand All @@ -464,8 +458,6 @@ class CachedVideoPlayerPlus {
String cacheKey, {
CacheManager? cacheManager,
}) async {
await _storage.initStorage;

cacheKey = _getCustomCacheKey(cacheKey);

cacheManager ??= _defaultCacheManager;
Expand All @@ -488,8 +480,6 @@ class CachedVideoPlayerPlus {
/// This operation cannot be undone. All cached videos will need to be
/// re-downloaded from their original sources.
static Future<void> clearAllCache({CacheManager? cacheManager}) async {
await _storage.initStorage;

cacheManager ??= _defaultCacheManager;

await Future.wait([cacheManager.emptyCache(), _storage.erase()]);
Expand Down
55 changes: 55 additions & 0 deletions lib/src/video_player_storage.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import 'package:shared_preferences/shared_preferences.dart';

/// Storage abstraction for cached video metadata.
///
/// This class handles the storage of cache expiration timestamps and provides
/// migration functionality from get_storage to shared_preferences.
class VideoPlayerStorage {
/// SharedPreferences instance for storing cache metadata.
final _asyncPrefs = SharedPreferencesAsync();

/// Key prefix for all video player storage keys.
static const _keyPrefix = 'cached_video_player_plus_video_expiration_of_';

/// Singleton instance of VideoPlayerStorage.
static final _instance = VideoPlayerStorage._internal();

/// Private constructor for singleton pattern implementation.
VideoPlayerStorage._internal();

/// Factory constructor that returns the singleton instance.
factory VideoPlayerStorage() => _instance;

/// Reads a value from storage.
///
/// Returns the stored value for the given [key], or null if not found.
Future<int?> read(String key) {
return _asyncPrefs.getInt(key);
}

/// Writes a value to storage.
///
/// Stores the [value] with the given [key].
Future<void> write(String key, int value) async {
return _asyncPrefs.setInt(key, value);
}

/// Removes a value from storage.
///
/// Deletes the value associated with the given [key].
Future<void> remove(String key) async {
return _asyncPrefs.remove(key);
}

/// Clears all cached video player data from storage.
///
/// This removes all keys that start with the video player prefix.
Future<void> erase() async {
final keys = await _asyncPrefs.getKeys();
final videoPlayerKeys = keys.where((key) => key.startsWith(_keyPrefix));

for (final key in videoPlayerKeys) {
await _asyncPrefs.remove(key);
}
}
}
Loading