方法1: 安全な方法
JavaScriptのFullscreen APIを使って安全に閉じることができます。iOS 6以上で動作確認済みです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)exitFullScreenVideo | |
{ | |
// Works in iOS, not sure in OS X | |
[self.webView stringByEvaluatingJavaScriptFromString:@"Array.prototype.forEach.call(document.getElementsByTagName('video'),function(v){v.webkitExitFullscreen();});"]; | |
// Didn't work in iOS, works in OS X | |
[self.webView stringByEvaluatingJavaScriptFromString:@"if(document.webkitFullscreenElement){document.webkitExitFullscreen();}"]; | |
} |
Fullscreen APIについては以下の資料が詳しいです。
- http://d.hatena.ne.jp/azukinohiroki/20120113/1326469430
- http://qiita.com/sasaplus1/items/26fbc0fec0f4f7fa47e3
- https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode
方法2: animated, completionの制御もしたい場合
ここからがお待ちかねの黒魔法になります。先ほどのJavaScriptを使った方法ではフルスクリーン動画を閉じる際のアニメーションを制御できません(必ずアニメーションが発生します)。またフルスクリーン動画を閉じ終わったタイミングのcompletion handlerが存在しません(JavaScriptでハンドルしようにも、videoタグのonendedイベントは通常の再生終了時にもイベントが飛ぶ上にアニメーション終了時ではなく再生終了時にイベントが飛ぶため使いづらい)。
通常はこれらが問題になることはまずありませんし、万一あったとしても仕様のほうを変えるほうが適切ですが、何らかの止むに止まれぬ理由によりなんとかしなければならなくなる場合が稀によくあります。
そこで画面上にUIWebView経由で表示されている動画プレイヤーViewControllerをビュー階層をたどって見つけ出し無理矢理dismissViewController:completion:で消すという方法を取ります。iOS 6以上にて動作確認済みです。ただしiOS 7以下の場合とiOS 8の場合で全く構造が異なり、将来にわたって動作するか非常に怪しいです。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
WARNING: PRIVATE API CALLS | |
WARNING: FORCEFUL MEMORY MANAGEMENT | |
highly recommend to avoid using this code | |
*/ | |
- (void)exitFullScreenVideo:(BOOL)animated completion:(void (^)(void))completion | |
{ | |
/* | |
iOS 6~7の場合 | |
本ViewControllerの上にMPInlineVideoFullscreenViewControllerがfullscreen modalで表示されるような挙動になるので | |
それを通常通り閉じてやればよい | |
iOS 8の場合 | |
新しいUIWindowが生成され、生成されたUIWindowのrootViewController.presentedViewControllerがAVFullScreenViewControllerになる | |
まずAVFullScreenViewControllerを閉じて、それからUIWindowのrootViewControllerをnilにセットしてhiddenにすることでUIWindowを消す | |
*/ | |
if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 8.0) { | |
BOOL isFullScreenVideoContent = NO; | |
for (UIWindow *window in [UIApplication sharedApplication].windows) { | |
if ([window.rootViewController.presentedViewController isKindOfClass:NSClassFromString(@"AVFullScreenViewController")]) { | |
[window.rootViewController dismissViewControllerAnimated:animated completion:^{ | |
window.rootViewController = nil; | |
window.hidden = YES; | |
#pragma clang diagnostic push | |
#pragma clang diagnostic ignored "-Warc-performSelector-leaks" | |
[window performSelector:NSSelectorFromString(@"release")]; | |
#pragma clang diagnostic pop | |
completion(); | |
}]; | |
isFullScreenVideoContent = YES; | |
break; | |
} | |
} | |
if (!isFullScreenVideoContent) { | |
completion(); | |
} | |
} else { | |
if ([self.visibleViewController isKindOfClass:NSClassFromString(@"MPInlineVideoFullscreenViewController")]) { | |
[self dismissViewControllerAnimated:animated completion:completion]; | |
} else { | |
completion(); | |
} | |
} | |
} |
Private APIの名前がバリバリ含まれるコードになっておりますので審査に出すアプリには使用しないことを強くおすすめさせていただきます。