I am using MPMoviePlayerController as an embedded video player, but the fullscreen icon from iOS 10+ has changed.
Original image in iOS 8, 9
Image in iOS 10+
I made the change earlier in an Objective-C project. Referring to this StackOverflow post. WorkaroundInlinePlayerFullScreenButtonBug.m
@import MediaPlayer;
@import ObjectiveC;
static void (*configureAuxiliaryButtonsIMP)(id, SEL, BOOL);
static void ConfigureAuxiliaryButtons(id self, SEL _cmd, BOOL flag)
{
configureAuxiliaryButtonsIMP(self, _cmd, flag);
@try
{
id delegate = [self delegate]; // Either nil or MPInlineVideoController (responds to `isFullscreen`) or MPInlineVideoFullscreenViewController (does not respond to `isFullscreen`)
BOOL isFullscreen = [delegate respondsToSelector:@selector(isFullscreen)] ? [delegate isFullscreen] : YES;
NSString *imageName = [@[ @"Video", @"Player", @"_", isFullscreen ? @"Exit" : @"Enter", @"Fullscreen" ] componentsJoinedByString:@""];
SEL imageNamedForControlState = NSSelectorFromString([@[ @"_", @"image", @"Named", @":", @"for", @"Control", @"State", @":" ] componentsJoinedByString:@""]);
UIImage *normalImage = ((UIImage *(*)(id, SEL, NSString *, UIControlState))objc_msgSend)(self, imageNamedForControlState, imageName, UIControlStateNormal);
UIImage *highlightedImage = ((UIImage *(*)(id, SEL, NSString *, UIControlState))objc_msgSend)(self, imageNamedForControlState, imageName, UIControlStateHighlighted);
UIButton *fullscreenButton = [self valueForKey:[@[ @"fullscreen", @"Button" ] componentsJoinedByString:@""]];
[fullscreenButton setImage:normalImage forState:UIControlStateNormal];
[fullscreenButton setImage:highlightedImage forState:UIControlStateHighlighted];
}
@catch (NSException *exception)
{
NSLog(@"Failed to workaround inline player fullscreen button bug: %@", exception);
}
}
void WorkaroundInlinePlayerFullScreenButtonBug(void)
{
if (![NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 0, 0}])
return;
Class MPVideoPlaybackOverlayView = NSClassFromString([@[ @"M", @"P", @"Video", @"Playback", @"Overlay", @"View" ] componentsJoinedByString:@""]);
SEL configureAuxiliaryButtonsSEL = NSSelectorFromString([@[ @"_", @"configure", @"Auxiliary", @"Buttons", @":" ] componentsJoinedByString:@""]);
NSMethodSignature *methodSignature = [MPVideoPlaybackOverlayView instanceMethodSignatureForSelector:configureAuxiliaryButtonsSEL];
if (methodSignature.numberOfArguments != 3)
{
NSLog(@"Failed to workaround inline player fullscreen button bug (method not found)");
return;
}
const char *returnType = methodSignature.methodReturnType;
const char *argType = [methodSignature getArgumentTypeAtIndex:2];
if (strcmp(returnType, @encode(void)) != 0 || strcmp(argType, @encode(BOOL)) != 0)
{
NSLog(@"Failed to workaround inline player fullscreen button bug (type mismatch)");
return;
}
Method configureAuxiliaryButtons = class_getInstanceMethod(MPVideoPlaybackOverlayView, configureAuxiliaryButtonsSEL);
configureAuxiliaryButtonsIMP = (__typeof__(configureAuxiliaryButtonsIMP))method_getImplementation(configureAuxiliaryButtons);
method_setImplementation(configureAuxiliaryButtons, (IMP)ConfigureAuxiliaryButtons);
}
And then calling it from the main.m
function as
#import "AppDelegate.h"
extern void WorkaroundInlinePlayerFullScreenButtonBug(void);
int main(int argc, char *argv[])
{
@autoreleasepool
{
WorkaroundInlinePlayerFullScreenButtonBug();
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
The above solution worked fine, but in Swift, I am not sure how to achieve this functionality.
The solution to this problem has multiple stages. First, we need to add a main.m to our Swift so that the code in the original solution can be injected. In Swift projects the main file is abstracted. Refer to this post.
So the first step is to remove @UIApplicationMain
keyword from AppDelegate
class.
Then we add a main.m by adding an Objective-C.m file and naming it as main
.
Add the following code as below in the main.m
file
#import <UIKit/UIKit.h>
#import "MoviePlayerDemo-Swift.h"
extern void WorkaroundInlinePlayerFullScreenButtonBug(void);
int main(int argc, char *argv[])
{
@autoreleasepool
{
WorkaroundInlinePlayerFullScreenButtonBug();
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
The original icon changing code remains the same as in the original answer:
@import MediaPlayer;
@import ObjectiveC;
static void (*configureAuxiliaryButtonsIMP)(id, SEL, BOOL);
static void ConfigureAuxiliaryButtons(id self, SEL _cmd, BOOL flag)
{
configureAuxiliaryButtonsIMP(self, _cmd, flag);
@try
{
id delegate = [self delegate]; // Either nil or MPInlineVideoController (responds to `isFullscreen`) or MPInlineVideoFullscreenViewController (does not respond to `isFullscreen`)
BOOL isFullscreen = [delegate respondsToSelector:@selector(isFullscreen)] ? [delegate isFullscreen] : YES;
NSString *imageName = [@[ @"Video", @"Player", @"_", isFullscreen ? @"Exit" : @"Enter", @"Fullscreen" ] componentsJoinedByString:@""];
SEL imageNamedForControlState = NSSelectorFromString([@[ @"_", @"image", @"Named", @":", @"for", @"Control", @"State", @":" ] componentsJoinedByString:@""]);
UIImage *normalImage = ((UIImage *(*)(id, SEL, NSString *, UIControlState))objc_msgSend)(self, imageNamedForControlState, imageName, UIControlStateNormal);
UIImage *highlightedImage = ((UIImage *(*)(id, SEL, NSString *, UIControlState))objc_msgSend)(self, imageNamedForControlState, imageName, UIControlStateHighlighted);
UIButton *fullscreenButton = [self valueForKey:[@[ @"fullscreen", @"Button" ] componentsJoinedByString:@""]];
[fullscreenButton setImage:normalImage forState:UIControlStateNormal];
[fullscreenButton setImage:highlightedImage forState:UIControlStateHighlighted];
}
@catch (NSException *exception)
{
NSLog(@"Failed to workaround inline player fullscreen button bug: %@", exception);
}
}
void WorkaroundInlinePlayerFullScreenButtonBug(void)
{
if (![NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 0, 0}])
return;
Class MPVideoPlaybackOverlayView = NSClassFromString([@[ @"M", @"P", @"Video", @"Playback", @"Overlay", @"View" ] componentsJoinedByString:@""]);
SEL configureAuxiliaryButtonsSEL = NSSelectorFromString([@[ @"_", @"configure", @"Auxiliary", @"Buttons", @":" ] componentsJoinedByString:@""]);
NSMethodSignature *methodSignature = [MPVideoPlaybackOverlayView instanceMethodSignatureForSelector:configureAuxiliaryButtonsSEL];
if (methodSignature.numberOfArguments != 3)
{
NSLog(@"Failed to workaround inline player fullscreen button bug (method not found)");
return;
}
const char *returnType = methodSignature.methodReturnType;
const char *argType = [methodSignature getArgumentTypeAtIndex:2];
if (strcmp(returnType, @encode(void)) != 0 || strcmp(argType, @encode(BOOL)) != 0)
{
NSLog(@"Failed to workaround inline player fullscreen button bug (type mismatch)");
return;
}
Method configureAuxiliaryButtons = class_getInstanceMethod(MPVideoPlaybackOverlayView, configureAuxiliaryButtonsSEL);
configureAuxiliaryButtonsIMP = (__typeof__(configureAuxiliaryButtonsIMP))method_getImplementation(configureAuxiliaryButtons);
method_setImplementation(configureAuxiliaryButtons, (IMP)ConfigureAuxiliaryButtons);
}