From 971516c7e96953faa47e784dad2a0180d494901e Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 9 Jun 2025 07:43:33 -0400 Subject: [PATCH 1/5] Roll Flutter master to 8b22f67c85114 Rolls the Flutter master pin to 8b22f67c85114def3f090286c386627efdf59614 https://github.com/flutter/flutter/compare/d8baa77b3846...8b22f67c8511 --- .ci/flutter_master.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/flutter_master.version b/.ci/flutter_master.version index b4f6a3a62af..b1282ca8bd6 100644 --- a/.ci/flutter_master.version +++ b/.ci/flutter_master.version @@ -1 +1 @@ -d8baa77b38461e7061e06e72c6bf50d64d302b8c +8b22f67c85114def3f090286c386627efdf59614 From 198eab9cb073399df5a57bd27bbe2f7740842102 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 9 Jun 2025 13:23:20 -0400 Subject: [PATCH 2/5] Temp workaround for channel registration in Pigeon example --- .../example/app/ios/Runner/AppDelegate.swift | 18 +++++++++++++----- .../app/ios/Runner/Base.lproj/Main.storyboard | 16 +++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/packages/pigeon/example/app/ios/Runner/AppDelegate.swift b/packages/pigeon/example/app/ios/Runner/AppDelegate.swift index 7948edfdd15..fbe3d7ce08c 100644 --- a/packages/pigeon/example/app/ios/Runner/AppDelegate.swift +++ b/packages/pigeon/example/app/ios/Runner/AppDelegate.swift @@ -100,18 +100,26 @@ func sendEvents(_ eventListener: EventListener) { didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} + +// TODO(stuartmorgan): Once 3.33+ reaches stable, remove this subclass and move the setup to +// AppDelegate.register(...). This approach is only used because this example needs to support +// both stable and master, and 3.32 doesn't have FlutterPluginRegistrant, while 3.33+ can't use +// the older application(didFinishLaunchingWithOptions) approach. +@objc class ExampleViewController: FlutterViewController { + override func awakeFromNib() { + super.awakeFromNib() - let controller = window?.rootViewController as! FlutterViewController let api = PigeonApiImplementation() - ExampleHostApiSetup.setUp(binaryMessenger: controller.binaryMessenger, api: api) + ExampleHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: api) + let controller = self // #docregion swift-init-event let eventListener = EventListener() StreamEventsStreamHandler.register( with: controller.binaryMessenger, streamHandler: eventListener) // #enddocregion swift-init-event sendEvents(eventListener) - - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } } diff --git a/packages/pigeon/example/app/ios/Runner/Base.lproj/Main.storyboard b/packages/pigeon/example/app/ios/Runner/Base.lproj/Main.storyboard index f3c28516fb3..5c266a12dd9 100644 --- a/packages/pigeon/example/app/ios/Runner/Base.lproj/Main.storyboard +++ b/packages/pigeon/example/app/ios/Runner/Base.lproj/Main.storyboard @@ -1,22 +1,24 @@ - - + + + - + + - + - + - + - + From db36cfaa18ba31bdeb337f90d72a342266c25771 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 9 Jun 2025 13:53:15 -0400 Subject: [PATCH 3/5] Skip quick_actions XCUITests --- .../example/ios/RunnerUITests/RunnerUITests.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift b/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift index 3bc0d2109be..7f8c410da59 100644 --- a/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift +++ b/packages/quick_actions/quick_actions_ios/example/ios/RunnerUITests/RunnerUITests.swift @@ -36,7 +36,10 @@ class RunnerUITests: XCTestCase { exampleApp = nil } - func testQuickActionWithFreshStart() { + func testQuickActionWithFreshStart() throws { + // See https://github.com/flutter/flutter/issues/169928 + throw XCTSkip("Temporarily disabled") + let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let quickActionsAppIcon = springboard.icons["quick_actions_example"] @@ -53,7 +56,10 @@ class RunnerUITests: XCTestCase { XCTAssert(actionTwoConfirmation.exists) } - func testQuickActionWhenAppIsInBackground() { + func testQuickActionWhenAppIsInBackground() throws { + // See https://github.com/flutter/flutter/issues/169928 + throw XCTSkip("Temporarily disabled") + exampleApp.launch() let actionsReady = exampleApp.otherElements["actions ready"] From 60ce03a5d8d832eccbdcb4821f3c2afba50ed557 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 9 Jun 2025 14:37:47 -0400 Subject: [PATCH 4/5] Decouple video_player XCTests from real app registry --- .../darwin/RunnerTests/VideoPlayerTests.m | 139 ++++++------------ 1 file changed, 46 insertions(+), 93 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m index 4bb06d7d970..8de2e71eebd 100644 --- a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m +++ b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m @@ -16,15 +16,6 @@ #import #endif -// TODO(stuartmorgan): Convert to using mock registrars instead. -NSObject *GetPluginRegistry(void) { -#if TARGET_OS_IOS - return (NSObject *)[[UIApplication sharedApplication] delegate]; -#else - return (FlutterViewController *)NSApplication.sharedApplication.windows[0].contentViewController; -#endif -} - #if TARGET_OS_IOS @interface FakeAVAssetTrack : AVAssetTrack @property(readonly, nonatomic) CGAffineTransform preferredTransform; @@ -168,8 +159,8 @@ - (FVPDisplayLink *)displayLinkWithRegistrar:(id)registr @implementation VideoPlayerTests - (void)testCreateWithOptionsReturnsErrorForInvalidAssetPath { - NSObject *registrar = [GetPluginRegistry() - registrarForPlugin:@"testCreateWithOptionsReturnsErrorForInvalidAssetPath"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + OCMStub([registrar lookupKeyForAsset:[OCMArg any]]).andReturn(nil); FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; @@ -177,9 +168,6 @@ - (void)testCreateWithOptionsReturnsErrorForInvalidAssetPath { [videoPlayerPlugin initialize:&initializationError]; XCTAssertNil(initializationError); - id mockRegistrar = OCMPartialMock(registrar); - OCMStub([mockRegistrar lookupKeyForAsset:[OCMArg any]]).andReturn(nil); - FVPCreationOptions *create = [FVPCreationOptions makeWithAsset:@"invalid/path/to/asset" uri:nil @@ -202,8 +190,7 @@ - (void)testBlankVideoBugWithEncryptedVideoStreamAndInvertedAspectRatioBugForSom // video streams (not just iOS 16). (https://github.com/flutter/flutter/issues/109116). An // invisible AVPlayerLayer is used to overwrite the protection of pixel buffers in those streams // for issue #1, and restore the correct width and height for issue #2. - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"testPlayerLayerWorkaround"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; @@ -232,10 +219,8 @@ - (void)testBlankVideoBugWithEncryptedVideoStreamAndInvertedAspectRatioBugForSom - (void)testPlayerForPlatformViewDoesNotRegisterTexture { NSObject *mockTextureRegistry = OCMProtocolMock(@protocol(FlutterTextureRegistry)); - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"testPlayerForPlatformViewDoesNotRegisterTexture"]; - NSObject *partialRegistrar = OCMPartialMock(registrar); - OCMStub([partialRegistrar textures]).andReturn(mockTextureRegistry); + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + OCMStub([registrar textures]).andReturn(mockTextureRegistry); FVPDisplayLink *mockDisplayLink = OCMPartialMock([[FVPDisplayLink alloc] initWithRegistrar:registrar callback:^(){ @@ -246,7 +231,7 @@ - (void)testPlayerForPlatformViewDoesNotRegisterTexture { FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory - registrar:partialRegistrar]; + registrar:registrar]; FlutterError *initalizationError; [videoPlayerPlugin initialize:&initalizationError]; @@ -267,10 +252,8 @@ - (void)testPlayerForPlatformViewDoesNotRegisterTexture { - (void)testSeekToWhilePausedStartsDisplayLinkTemporarily { NSObject *mockTextureRegistry = OCMProtocolMock(@protocol(FlutterTextureRegistry)); - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"SeekToWhilePausedStartsDisplayLinkTemporarily"]; - NSObject *partialRegistrar = OCMPartialMock(registrar); - OCMStub([partialRegistrar textures]).andReturn(mockTextureRegistry); + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + OCMStub([registrar textures]).andReturn(mockTextureRegistry); FVPDisplayLink *mockDisplayLink = OCMPartialMock([[FVPDisplayLink alloc] initWithRegistrar:registrar callback:^(){ @@ -281,7 +264,7 @@ - (void)testSeekToWhilePausedStartsDisplayLinkTemporarily { FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory - registrar:partialRegistrar]; + registrar:registrar]; FlutterError *initalizationError; [videoPlayerPlugin initialize:&initalizationError]; @@ -338,10 +321,8 @@ - (void)testSeekToWhilePausedStartsDisplayLinkTemporarily { - (void)testInitStartsDisplayLinkTemporarily { NSObject *mockTextureRegistry = OCMProtocolMock(@protocol(FlutterTextureRegistry)); - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"InitStartsDisplayLinkTemporarily"]; - NSObject *partialRegistrar = OCMPartialMock(registrar); - OCMStub([partialRegistrar textures]).andReturn(mockTextureRegistry); + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + OCMStub([registrar textures]).andReturn(mockTextureRegistry); FVPDisplayLink *mockDisplayLink = OCMPartialMock([[FVPDisplayLink alloc] initWithRegistrar:registrar callback:^(){ @@ -354,7 +335,7 @@ - (void)testInitStartsDisplayLinkTemporarily { initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:stubAVPlayer output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory - registrar:partialRegistrar]; + registrar:registrar]; FlutterError *initalizationError; [videoPlayerPlugin initialize:&initalizationError]; @@ -393,10 +374,8 @@ - (void)testInitStartsDisplayLinkTemporarily { - (void)testSeekToWhilePlayingDoesNotStopDisplayLink { NSObject *mockTextureRegistry = OCMProtocolMock(@protocol(FlutterTextureRegistry)); - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"SeekToWhilePlayingDoesNotStopDisplayLink"]; - NSObject *partialRegistrar = OCMPartialMock(registrar); - OCMStub([partialRegistrar textures]).andReturn(mockTextureRegistry); + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + OCMStub([registrar textures]).andReturn(mockTextureRegistry); FVPDisplayLink *mockDisplayLink = OCMPartialMock([[FVPDisplayLink alloc] initWithRegistrar:registrar callback:^(){ @@ -407,7 +386,7 @@ - (void)testSeekToWhilePlayingDoesNotStopDisplayLink { FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory - registrar:partialRegistrar]; + registrar:registrar]; FlutterError *initalizationError; [videoPlayerPlugin initialize:&initalizationError]; @@ -463,10 +442,8 @@ - (void)testSeekToWhilePlayingDoesNotStopDisplayLink { - (void)testPauseWhileWaitingForFrameDoesNotStopDisplayLink { NSObject *mockTextureRegistry = OCMProtocolMock(@protocol(FlutterTextureRegistry)); - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"PauseWhileWaitingForFrameDoesNotStopDisplayLink"]; - NSObject *partialRegistrar = OCMPartialMock(registrar); - OCMStub([partialRegistrar textures]).andReturn(mockTextureRegistry); + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + OCMStub([registrar textures]).andReturn(mockTextureRegistry); FVPDisplayLink *mockDisplayLink = OCMPartialMock([[FVPDisplayLink alloc] initWithRegistrar:registrar callback:^(){ @@ -477,7 +454,7 @@ - (void)testPauseWhileWaitingForFrameDoesNotStopDisplayLink { FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory - registrar:partialRegistrar]; + registrar:registrar]; FlutterError *initalizationError; [videoPlayerPlugin initialize:&initalizationError]; @@ -502,8 +479,7 @@ - (void)testPauseWhileWaitingForFrameDoesNotStopDisplayLink { } - (void)testDeregistersFromPlayer { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"testDeregistersFromPlayer"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); FVPVideoPlayerPlugin *videoPlayerPlugin = (FVPVideoPlayerPlugin *)[[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; @@ -535,8 +511,7 @@ - (void)testDeregistersFromPlayer { } - (void)testBufferingStateFromPlayer { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"testLiveStreamBufferEndFromPlayer"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); FVPVideoPlayerPlugin *videoPlayerPlugin = (FVPVideoPlayerPlugin *)[[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; @@ -580,8 +555,7 @@ - (void)testBufferingStateFromPlayer { } - (void)testVideoControls { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"TestVideoControls"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); FVPVideoPlayerPlugin *videoPlayerPlugin = (FVPVideoPlayerPlugin *)[[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; @@ -595,8 +569,7 @@ - (void)testVideoControls { } - (void)testAudioControls { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"TestAudioControls"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); FVPVideoPlayerPlugin *videoPlayerPlugin = (FVPVideoPlayerPlugin *)[[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; @@ -611,8 +584,7 @@ - (void)testAudioControls { } - (void)testHLSControls { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"TestHLSControls"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); FVPVideoPlayerPlugin *videoPlayerPlugin = (FVPVideoPlayerPlugin *)[[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; @@ -627,8 +599,7 @@ - (void)testHLSControls { - (void)testAudioOnlyHLSControls { XCTSkip(@"Flaky; see https://github.com/flutter/flutter/issues/164381"); - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"TestAudioOnlyHLSControls"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); FVPVideoPlayerPlugin *videoPlayerPlugin = (FVPVideoPlayerPlugin *)[[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; @@ -656,8 +627,7 @@ - (void)testTransformFix { #endif - (void)testSeekToleranceWhenNotSeekingToEnd { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"TestSeekTolerance"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); StubAVPlayer *stubAVPlayer = [[StubAVPlayer alloc] init]; StubFVPAVFactory *stubAVFactory = [[StubFVPAVFactory alloc] initWithPlayer:stubAVPlayer @@ -695,8 +665,7 @@ - (void)testSeekToleranceWhenNotSeekingToEnd { } - (void)testSeekToleranceWhenSeekingToEnd { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"TestSeekToEndTolerance"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); StubAVPlayer *stubAVPlayer = [[StubAVPlayer alloc] init]; StubFVPAVFactory *stubAVFactory = [[StubFVPAVFactory alloc] initWithPlayer:stubAVPlayer @@ -792,8 +761,7 @@ - (void)testSeekToleranceWhenSeekingToEnd { // // Failing to de-register results in a crash in [AVPlayer willChangeValueForKey:]. - (void)testDoesNotCrashOnRateObservationAfterDisposal { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"testDoesNotCrashOnRateObservationAfterDisposal"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); AVPlayer *avPlayer = nil; __weak FVPVideoPlayer *weakPlayer = nil; @@ -848,8 +816,7 @@ - (void)testDoesNotCrashOnRateObservationAfterDisposal { // Both of these methods dispatch [FVPVideoPlayer dispose] on the main thread // leading to a possible crash when de-registering observers twice. - (void)testHotReloadDoesNotCrash { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"testHotReloadDoesNotCrash"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); __weak FVPVideoPlayer *weakPlayer = nil; @@ -900,42 +867,32 @@ - (void)testHotReloadDoesNotCrash { #if TARGET_OS_IOS - (void)testNativeVideoViewFactoryRegistration { - NSObject *registry = GetPluginRegistry(); - NSObject *registrar = - [registry registrarForPlugin:@"testNativeVideoViewFactoryRegistration"]; - id mockRegistrar = OCMPartialMock(registrar); + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); - OCMExpect([mockRegistrar - registerViewFactory:[OCMArg isKindOfClass:[FVPNativeVideoViewFactory class]] - withId:@"plugins.flutter.dev/video_player_ios"]); - [FVPVideoPlayerPlugin registerWithRegistrar:mockRegistrar]; + OCMExpect([registrar registerViewFactory:[OCMArg isKindOfClass:[FVPNativeVideoViewFactory class]] + withId:@"plugins.flutter.dev/video_player_ios"]); + [FVPVideoPlayerPlugin registerWithRegistrar:registrar]; - OCMVerifyAll(mockRegistrar); + OCMVerifyAll(registrar); } #endif - (void)testPublishesInRegistration { - NSString *pluginKey = @"TestRegistration"; - NSObject *registry = GetPluginRegistry(); - NSObject *registrar = [registry registrarForPlugin:pluginKey]; - id mockRegistrar = OCMPartialMock(registrar); - // Empty stub to pass a check in Flutter's engine (double factory registration). - // registerWithRegistrar gets called at the beginning of the test, and factory is registered - // there. Additional call would try to register the same factory another time, which would fail a - // check in the engine. - OCMStub([mockRegistrar registerViewFactory:[OCMArg any] withId:[OCMArg any]]); - - [FVPVideoPlayerPlugin registerWithRegistrar:mockRegistrar]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + __block NSObject *publishedValue; + OCMStub([registrar publish:[OCMArg checkWithBlock:^BOOL(id value) { + publishedValue = value; + return YES; + }]]); - id publishedValue = [registry valuePublishedByPlugin:pluginKey]; + [FVPVideoPlayerPlugin registerWithRegistrar:registrar]; XCTAssertNotNil(publishedValue); XCTAssertTrue([publishedValue isKindOfClass:[FVPVideoPlayerPlugin class]]); } - (void)testFailedToLoadVideoEventShouldBeAlwaysSent { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"testFailedToLoadVideoEventShouldBeAlwaysSent"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; FlutterError *error; @@ -969,8 +926,7 @@ - (void)testFailedToLoadVideoEventShouldBeAlwaysSent { } - (void)testUpdatePlayingStateShouldNotResetRate { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"testUpdatePlayingStateShouldNotResetRate"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:nil] @@ -1005,12 +961,10 @@ - (void)testUpdatePlayingStateShouldNotResetRate { } - (void)testPlayerShouldNotDropEverySecondFrame { - NSObject *registrar = - [GetPluginRegistry() registrarForPlugin:@"testPlayerShouldNotDropEverySecondFrame"]; - NSObject *partialRegistrar = OCMPartialMock(registrar); + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); NSObject *mockTextureRegistry = OCMProtocolMock(@protocol(FlutterTextureRegistry)); - OCMStub([partialRegistrar textures]).andReturn(mockTextureRegistry); + OCMStub([registrar textures]).andReturn(mockTextureRegistry); FVPDisplayLink *displayLink = [[FVPDisplayLink alloc] initWithRegistrar:registrar callback:^(){ @@ -1021,7 +975,7 @@ - (void)testPlayerShouldNotDropEverySecondFrame { FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory - registrar:partialRegistrar]; + registrar:registrar]; FlutterError *error; [videoPlayerPlugin initialize:&error]; @@ -1084,8 +1038,7 @@ - (void)testPlayerShouldNotDropEverySecondFrame { #if TARGET_OS_IOS - (void)testVideoPlayerShouldNotOverwritePlayAndRecordNorDefaultToSpeaker { - NSObject *registrar = [GetPluginRegistry() - registrarForPlugin:@"testVideoPlayerShouldNotOverwritePlayAndRecordNorDefaultToSpeaker"]; + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; FlutterError *error; From 994df11353111e05fec1e21f5970db557b0c9b3f Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 9 Jun 2025 20:44:30 -0400 Subject: [PATCH 5/5] Inject view provider for video_player_avfoundation --- .../video_player_avfoundation/CHANGELOG.md | 1 + .../darwin/RunnerTests/VideoPlayerTests.m | 45 +++++++++++++++++-- .../FVPTextureBasedVideoPlayer.m | 32 +++---------- .../FVPVideoPlayer.m | 12 ++--- .../FVPVideoPlayerPlugin.m | 21 +++++---- .../FVPViewProvider.m | 42 +++++++++++++++++ .../FVPTextureBasedVideoPlayer.h | 4 +- .../FVPVideoPlayer.h | 10 +++-- .../FVPVideoPlayerPlugin_Test.h | 1 + .../FVPVideoPlayer_Internal.h | 9 ++-- .../FVPViewProvider.h | 35 +++++++++++++++ 11 files changed, 160 insertions(+), 52 deletions(-) create mode 100644 packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPViewProvider.m create mode 100644 packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPViewProvider.h diff --git a/packages/video_player/video_player_avfoundation/CHANGELOG.md b/packages/video_player/video_player_avfoundation/CHANGELOG.md index 3deff466e60..935a6eabe93 100644 --- a/packages/video_player/video_player_avfoundation/CHANGELOG.md +++ b/packages/video_player/video_player_avfoundation/CHANGELOG.md @@ -1,6 +1,7 @@ ## NEXT * Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. +* Refactors native code for improved testing. ## 2.7.1 diff --git a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m index 8de2e71eebd..221991c19eb 100644 --- a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m +++ b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m @@ -82,6 +82,26 @@ - (void)seekToTime:(CMTime)time @end +// Convience to avoid having two copies of the StubViewProvider code. +#if TARGET_OS_OSX +#define PROVIDED_VIEW_TYPE NSView +#else +#define PROVIDED_VIEW_TYPE UIView +#endif + +@interface StubViewProvider : NSObject +- (instancetype)initWithView:(PROVIDED_VIEW_TYPE *)view; +@property(nonatomic, nullable) PROVIDED_VIEW_TYPE *view; +@end + +@implementation StubViewProvider +- (instancetype)initWithView:(PROVIDED_VIEW_TYPE *)view { + self = [super init]; + _view = view; + return self; +} +@end + @interface StubFVPAVFactory : NSObject @property(nonatomic, strong) StubAVPlayer *stubAVPlayer; @@ -190,9 +210,18 @@ - (void)testBlankVideoBugWithEncryptedVideoStreamAndInvertedAspectRatioBugForSom // video streams (not just iOS 16). (https://github.com/flutter/flutter/issues/109116). An // invisible AVPlayerLayer is used to overwrite the protection of pixel buffers in those streams // for issue #1, and restore the correct width and height for issue #2. +#if TARGET_OS_OSX + NSView *view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 10, 10)]; + view.wantsLayer = true; +#else + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)]; +#endif NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); - FVPVideoPlayerPlugin *videoPlayerPlugin = - [[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; + FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] + initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:nil] + displayLinkFactory:nil + viewProvider:[[StubViewProvider alloc] initWithView:view] + registrar:registrar]; FlutterError *error; [videoPlayerPlugin initialize:&error]; @@ -213,7 +242,8 @@ - (void)testBlankVideoBugWithEncryptedVideoStreamAndInvertedAspectRatioBugForSom XCTAssertNotNil(player); XCTAssertNotNil(player.playerLayer, @"AVPlayerLayer should be present."); - XCTAssertNotNil(player.playerLayer.superlayer, @"AVPlayerLayer should be added on screen."); + XCTAssertEqual(player.playerLayer.superlayer, view.layer, + @"AVPlayerLayer should be added on screen."); } - (void)testPlayerForPlatformViewDoesNotRegisterTexture { @@ -231,6 +261,7 @@ - (void)testPlayerForPlatformViewDoesNotRegisterTexture { FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory + viewProvider:[[StubViewProvider alloc] initWithView:nil] registrar:registrar]; FlutterError *initalizationError; @@ -264,6 +295,7 @@ - (void)testSeekToWhilePausedStartsDisplayLinkTemporarily { FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory + viewProvider:[[StubViewProvider alloc] initWithView:nil] registrar:registrar]; FlutterError *initalizationError; @@ -335,6 +367,7 @@ - (void)testInitStartsDisplayLinkTemporarily { initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:stubAVPlayer output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory + viewProvider:[[StubViewProvider alloc] initWithView:nil] registrar:registrar]; FlutterError *initalizationError; @@ -386,6 +419,7 @@ - (void)testSeekToWhilePlayingDoesNotStopDisplayLink { FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory + viewProvider:[[StubViewProvider alloc] initWithView:nil] registrar:registrar]; FlutterError *initalizationError; @@ -454,6 +488,7 @@ - (void)testPauseWhileWaitingForFrameDoesNotStopDisplayLink { FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory + viewProvider:[[StubViewProvider alloc] initWithView:nil] registrar:registrar]; FlutterError *initalizationError; @@ -635,6 +670,7 @@ - (void)testSeekToleranceWhenNotSeekingToEnd { FVPVideoPlayerPlugin *pluginWithMockAVPlayer = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:stubAVFactory displayLinkFactory:nil + viewProvider:[[StubViewProvider alloc] initWithView:nil] registrar:registrar]; FlutterError *initializationError; @@ -673,6 +709,7 @@ - (void)testSeekToleranceWhenSeekingToEnd { FVPVideoPlayerPlugin *pluginWithMockAVPlayer = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:stubAVFactory displayLinkFactory:nil + viewProvider:[[StubViewProvider alloc] initWithView:nil] registrar:registrar]; FlutterError *initializationError; @@ -931,6 +968,7 @@ - (void)testUpdatePlayingStateShouldNotResetRate { FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:nil] displayLinkFactory:nil + viewProvider:[[StubViewProvider alloc] initWithView:nil] registrar:registrar]; FlutterError *error; @@ -975,6 +1013,7 @@ - (void)testPlayerShouldNotDropEverySecondFrame { FVPVideoPlayerPlugin *videoPlayerPlugin = [[FVPVideoPlayerPlugin alloc] initWithAVFactory:[[StubFVPAVFactory alloc] initWithPlayer:nil output:mockVideoOutput] displayLinkFactory:stubDisplayLinkFactory + viewProvider:[[StubViewProvider alloc] initWithView:nil] registrar:registrar]; FlutterError *error; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m index 68f8a4673c6..0fd1ca77f07 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPTextureBasedVideoPlayer.m @@ -6,8 +6,6 @@ #import "./include/video_player_avfoundation/FVPTextureBasedVideoPlayer_Test.h" @interface FVPTextureBasedVideoPlayer () -// The CALayer associated with the Flutter view this plugin is associated with, if any. -@property(nonatomic, readonly) CALayer *flutterViewLayer; // The updater that drives callbacks to the engine to indicate that a new frame is ready. @property(nonatomic) FVPFrameUpdater *frameUpdater; // The display link that drives frameUpdater. @@ -38,14 +36,14 @@ - (instancetype)initWithAsset:(NSString *)asset frameUpdater:(FVPFrameUpdater *)frameUpdater displayLink:(FVPDisplayLink *)displayLink avFactory:(id)avFactory - registrar:(NSObject *)registrar + viewProvider:(NSObject *)viewProvider onDisposed:(void (^)(int64_t))onDisposed { return [self initWithURL:[NSURL fileURLWithPath:[FVPVideoPlayer absolutePathForAssetName:asset]] frameUpdater:frameUpdater displayLink:displayLink httpHeaders:@{} avFactory:avFactory - registrar:registrar + viewProvider:viewProvider onDisposed:onDisposed]; } @@ -54,7 +52,7 @@ - (instancetype)initWithURL:(NSURL *)url displayLink:(FVPDisplayLink *)displayLink httpHeaders:(nonnull NSDictionary *)headers avFactory:(id)avFactory - registrar:(NSObject *)registrar + viewProvider:(NSObject *)viewProvider onDisposed:(void (^)(int64_t))onDisposed { NSDictionary *options = nil; if ([headers count] != 0) { @@ -66,7 +64,7 @@ - (instancetype)initWithURL:(NSURL *)url frameUpdater:frameUpdater displayLink:displayLink avFactory:avFactory - registrar:registrar + viewProvider:viewProvider onDisposed:onDisposed]; } @@ -74,9 +72,9 @@ - (instancetype)initWithPlayerItem:(AVPlayerItem *)item frameUpdater:(FVPFrameUpdater *)frameUpdater displayLink:(FVPDisplayLink *)displayLink avFactory:(id)avFactory - registrar:(NSObject *)registrar + viewProvider:(NSObject *)viewProvider onDisposed:(void (^)(int64_t))onDisposed { - self = [super initWithPlayerItem:item avFactory:avFactory registrar:registrar]; + self = [super initWithPlayerItem:item avFactory:avFactory viewProvider:viewProvider]; if (self) { _frameUpdater = frameUpdater; @@ -91,7 +89,7 @@ - (instancetype)initWithPlayerItem:(AVPlayerItem *)item // invisible AVPlayerLayer is used to overwrite the protection of pixel buffers in those streams // for issue #1, and restore the correct width and height for issue #2. _playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; - [self.flutterViewLayer addSublayer:self.playerLayer]; + [viewProvider.view.layer addSublayer:self.playerLayer]; } return self; } @@ -110,22 +108,6 @@ - (void)expectFrame { _displayLink.running = YES; } -#pragma mark - Private methods - -- (CALayer *)flutterViewLayer { -#if TARGET_OS_OSX - return self.registrar.view.layer; -#else -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - // TODO(hellohuanlin): Provide a non-deprecated codepath. See - // https://github.com/flutter/flutter/issues/104117 - UIViewController *root = UIApplication.sharedApplication.keyWindow.rootViewController; -#pragma clang diagnostic pop - return root.view.layer; -#endif -} - #pragma mark - Overrides - (void)updatePlayingState { diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m index 04d6d21cb2e..59e82934e16 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayer.m @@ -20,33 +20,33 @@ @implementation FVPVideoPlayer - (instancetype)initWithAsset:(NSString *)asset avFactory:(id)avFactory - registrar:(NSObject *)registrar { + viewProvider:(NSObject *)viewProvider { return [self initWithURL:[NSURL fileURLWithPath:[FVPVideoPlayer absolutePathForAssetName:asset]] httpHeaders:@{} avFactory:avFactory - registrar:registrar]; + viewProvider:viewProvider]; } - (instancetype)initWithURL:(NSURL *)url httpHeaders:(nonnull NSDictionary *)headers avFactory:(id)avFactory - registrar:(NSObject *)registrar { + viewProvider:(NSObject *)viewProvider { NSDictionary *options = nil; if ([headers count] != 0) { options = @{@"AVURLAssetHTTPHeaderFieldsKey" : headers}; } AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:url options:options]; AVPlayerItem *item = [AVPlayerItem playerItemWithAsset:urlAsset]; - return [self initWithPlayerItem:item avFactory:avFactory registrar:registrar]; + return [self initWithPlayerItem:item avFactory:avFactory viewProvider:viewProvider]; } - (instancetype)initWithPlayerItem:(AVPlayerItem *)item avFactory:(id)avFactory - registrar:(NSObject *)registrar { + viewProvider:(NSObject *)viewProvider { self = [super init]; NSAssert(self, @"super init cannot be nil"); - _registrar = registrar; + _viewProvider = viewProvider; AVAsset *asset = [item asset]; void (^assetCompletionHandler)(void) = ^{ diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index 1936435ffd0..6292422f935 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -45,6 +45,7 @@ @interface FVPVideoPlayerPlugin () @property(readonly, strong, nonatomic) NSObject *registrar; @property(nonatomic, strong) id displayLinkFactory; @property(nonatomic, strong) id avFactory; +@property(nonatomic, strong) NSObject *viewProvider; // TODO(stuartmorgan): Decouple identifiers for platform views and texture views. @property(nonatomic, assign) int64_t nextNonTexturePlayerIdentifier; @end @@ -68,19 +69,23 @@ + (void)registerWithRegistrar:(NSObject *)registrar { - (instancetype)initWithRegistrar:(NSObject *)registrar { return [self initWithAVFactory:[[FVPDefaultAVFactory alloc] init] displayLinkFactory:[[FVPDefaultDisplayLinkFactory alloc] init] + viewProvider:[[FVPDefaultViewProvider alloc] initWithRegistrar:registrar] registrar:registrar]; } - (instancetype)initWithAVFactory:(id)avFactory displayLinkFactory:(id)displayLinkFactory + viewProvider:(NSObject *)viewProvider registrar:(NSObject *)registrar { self = [super init]; NSAssert(self, @"super init cannot be nil"); _registry = [registrar textures]; _messenger = [registrar messenger]; _registrar = registrar; + _viewProvider = viewProvider; _displayLinkFactory = displayLinkFactory ?: [[FVPDefaultDisplayLinkFactory alloc] init]; _avFactory = avFactory ?: [[FVPDefaultAVFactory alloc] init]; + _viewProvider = viewProvider ?: [[FVPDefaultViewProvider alloc] initWithRegistrar:registrar]; _playersByIdentifier = [NSMutableDictionary dictionaryWithCapacity:1]; // Initialized to a high number to avoid collisions with texture identifiers (which are generated // separately). @@ -209,16 +214,16 @@ - (nullable FVPTextureBasedVideoPlayer *)texturePlayerWithOptions: return [[FVPTextureBasedVideoPlayer alloc] initWithAsset:assetPath frameUpdater:frameUpdater displayLink:displayLink - avFactory:_avFactory - registrar:self.registrar + avFactory:self.avFactory + viewProvider:self.viewProvider onDisposed:onDisposed]; } else if (options.uri) { return [[FVPTextureBasedVideoPlayer alloc] initWithURL:[NSURL URLWithString:options.uri] frameUpdater:frameUpdater displayLink:displayLink httpHeaders:options.httpHeaders - avFactory:_avFactory - registrar:self.registrar + avFactory:self.avFactory + viewProvider:self.viewProvider onDisposed:onDisposed]; } @@ -230,13 +235,13 @@ - (nullable FVPVideoPlayer *)platformViewPlayerWithOptions:(nonnull FVPCreationO if (options.asset) { NSString *assetPath = [self assetPathFromCreationOptions:options]; return [[FVPVideoPlayer alloc] initWithAsset:assetPath - avFactory:_avFactory - registrar:self.registrar]; + avFactory:self.avFactory + viewProvider:self.viewProvider]; } else if (options.uri) { return [[FVPVideoPlayer alloc] initWithURL:[NSURL URLWithString:options.uri] httpHeaders:options.httpHeaders - avFactory:_avFactory - registrar:self.registrar]; + avFactory:self.avFactory + viewProvider:self.viewProvider]; } return nil; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPViewProvider.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPViewProvider.m new file mode 100644 index 00000000000..a90d0de7ce6 --- /dev/null +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPViewProvider.m @@ -0,0 +1,42 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "./include/video_player_avfoundation/FVPViewProvider.h" + +#if TARGET_OS_OSX +@import Cocoa; +#else +@import UIKit; +#endif + +@interface FVPDefaultViewProvider () +/// The backing registrar. +@property(nonatomic) NSObject *registrar; +@end + +@implementation FVPDefaultViewProvider +- (instancetype)initWithRegistrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _registrar = registrar; + } + return self; +} + +#if TARGET_OS_OSX +- (NSView *)view { + return self.registrar.view; +} +#else +- (UIView *)view { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + // TODO(hellohuanlin): Provide a non-deprecated codepath. See + // https://github.com/flutter/flutter/issues/104117 + UIViewController *root = UIApplication.sharedApplication.keyWindow.rootViewController; +#pragma clang diagnostic pop + return root.view; +} +#endif +@end diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h index 281438efe8d..23005841d48 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPTextureBasedVideoPlayer.h @@ -21,7 +21,7 @@ NS_ASSUME_NONNULL_BEGIN displayLink:(FVPDisplayLink *)displayLink httpHeaders:(nonnull NSDictionary *)headers avFactory:(id)avFactory - registrar:(NSObject *)registrar + viewProvider:(NSObject *)viewProvider onDisposed:(void (^)(int64_t))onDisposed; /// Initializes a new instance of FVPTextureBasedVideoPlayer with the given asset, frame updater, @@ -30,7 +30,7 @@ NS_ASSUME_NONNULL_BEGIN frameUpdater:(FVPFrameUpdater *)frameUpdater displayLink:(FVPDisplayLink *)displayLink avFactory:(id)avFactory - registrar:(NSObject *)registrar + viewProvider:(NSObject *)viewProvider onDisposed:(void (^)(int64_t))onDisposed; /// Sets the texture Identifier for the frame updater. This method should be called once the texture diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h index d668c820065..9c980fac23f 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer.h @@ -5,6 +5,7 @@ #import #import "FVPAVFactory.h" +#import "FVPViewProvider.h" #if TARGET_OS_OSX #import @@ -31,17 +32,18 @@ NS_ASSUME_NONNULL_BEGIN /// The current playback position of the video, in milliseconds. @property(nonatomic, readonly) int64_t position; -/// Initializes a new instance of FVPVideoPlayer with the given asset, AV factory, and registrar. +/// Initializes a new instance of FVPVideoPlayer with the given asset, AV factory, and view +/// provider. - (instancetype)initWithAsset:(NSString *)asset avFactory:(id)avFactory - registrar:(NSObject *)registrar; + viewProvider:(NSObject *)viewProvider; /// Initializes a new instance of FVPVideoPlayer with the given URL, HTTP headers, AV factory, and -/// registrar. +/// view provider. - (instancetype)initWithURL:(NSURL *)url httpHeaders:(nonnull NSDictionary *)headers avFactory:(id)avFactory - registrar:(NSObject *)registrar; + viewProvider:(NSObject *)viewProvider; /// Disposes the video player and releases any resources it holds. - (void)dispose; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayerPlugin_Test.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayerPlugin_Test.h index 0c35429d026..30c36fe50f0 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayerPlugin_Test.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayerPlugin_Test.h @@ -23,6 +23,7 @@ - (instancetype)initWithAVFactory:(id)avFactory displayLinkFactory:(id)displayLinkFactory + viewProvider:(NSObject *)viewProvider registrar:(NSObject *)registrar; @end diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer_Internal.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer_Internal.h index 995952de17e..7b282be4c06 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer_Internal.h +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPVideoPlayer_Internal.h @@ -5,6 +5,7 @@ #import #import "FVPAVFactory.h" #import "FVPVideoPlayer.h" +#import "FVPViewProvider.h" #if TARGET_OS_OSX #import @@ -18,8 +19,8 @@ NS_ASSUME_NONNULL_BEGIN @interface FVPVideoPlayer () /// The AVPlayerItemVideoOutput associated with this video player. @property(nonatomic, readonly) AVPlayerItemVideoOutput *videoOutput; -/// The plugin registrar, to obtain view information from. -@property(nonatomic, readonly) NSObject *registrar; +/// The view provider, to obtain view information from. +@property(nonatomic, readonly, nullable) NSObject *viewProvider; /// The Flutter event sink used to send events to the Flutter engine. @property(nonatomic) FlutterEventSink eventSink; /// The preferred transform for the video. It can be used to handle the rotation of the video. @@ -32,10 +33,10 @@ NS_ASSUME_NONNULL_BEGIN @property(nonatomic, readonly) BOOL isInitialized; /// Initializes a new instance of FVPVideoPlayer with the given AVPlayerItem, frame updater, display -/// link, AV factory, and registrar. +/// link, AV factory, and view provider. - (instancetype)initWithPlayerItem:(AVPlayerItem *)item avFactory:(id)avFactory - registrar:(NSObject *)registrar; + viewProvider:(NSObject *)viewProvider; /// Updates the playing state of the video player. - (void)updatePlayingState; diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPViewProvider.h b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPViewProvider.h new file mode 100644 index 00000000000..53dd2030b94 --- /dev/null +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/include/video_player_avfoundation/FVPViewProvider.h @@ -0,0 +1,35 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#if TARGET_OS_OSX +@import Cocoa; +@import FlutterMacOS; +#else +@import Flutter; +@import UIKit; +#endif + +NS_ASSUME_NONNULL_BEGIN + +/// Protocol for obtaining the view containing the Flutter content. +@protocol FVPViewProvider +@required +#if TARGET_OS_OSX +/// The view containing the Flutter content. +@property(nonatomic, readonly, nullable) NSView *view; +#else +/// The view containing the Flutter content. +@property(nonatomic, readonly, nullable) UIView *view; +#endif +@end + +/// A default implementation of the FVPAVFactory protocol. +@interface FVPDefaultViewProvider : NSObject +/// Returns a provider backed by the given registrar. +- (instancetype)initWithRegistrar:(NSObject *)registrar + NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_UNAVAILABLE; +@end + +NS_ASSUME_NONNULL_END