I am building an application where I want to play video from url like Youtube, Vimeo, Direct url. I am making custom player using AVPlayer to play a video from a direct url of video clip(like www.abc/play.mp4). But later I faced a huge issue to play youtube & vimeo video. And after searching a lot I found these link where it says without using UIWebview I can't play a Youtube link:
Play YouTube videos with MPMoviePlayerController instead of UIWebView
Playing video from youtube link without UIWebView
So I just used this code:
NSString *youTubeVideoHTML = #"<html><head><style>body{margin:0;}</style></head> <body> <div id=\"player\"></div> <script> var tag = document.createElement('script'); tag.src = 'http://www.youtube.com/player_api'; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); var player; function onYouTubePlayerAPIReady() { player = new YT.Player('player', { width:\'100%%\', height:'200px', videoId:\'%#\', events: { 'onReady': onPlayerReady } }); } function onPlayerReady(event) { event.target.playVideo(); } </script> </body> </html>";
NSString *html = [NSString stringWithFormat:youTubeVideoHTML, videoId];
self.embedded_player_view.mediaPlaybackRequiresUserAction = NO;
[self.embedded_player_view loadHTMLString:html baseURL:[[NSBundle mainBundle] resourceURL]];
Now when I click on youtube/Vimeo video link from tableview its playing the video with the default player i.e. quicktime player. Its not running the video within the UIWebview frame itself.
But I want to show the video in the 1st half of the screen i.e my UIWebview frame. Is that possible?
In my app I can see this:
when clicking on red play button I can see the video in full screen in quicktime player like this:
But I want to show the video within the same webView frame not via quick time player. It should play like this:
Same does in MusicTube and PlayTube.
Or is there any other way to achieve the same? Any help will be appreciated. Thanks in advance.
I've used this class just for that.
The video you see inside the UIViewController is playable in its current size.
That's the only code I've used:
UIView *videoContainerView = [[UIView alloc]initWithFrame:CGRectMake(0, 50, 320, 200)];
[self.view addSubview:videoContainerView];
XCDYouTubeVideoPlayerViewController *videoPlayerViewController = [[XCDYouTubeVideoPlayerViewController alloc] initWithVideoIdentifier:#"_OBlgSz8sSM"];
[videoPlayerViewController presentInView:videoContainerView];
[videoPlayerViewController.moviePlayer play];
For Vimeo player you can check this link https://github.com/lilfaf/YTVimeoExtractor it plays the video in real player and if you want to run the video in uiwebview,here is the code for that https://stackoverflow.com/a/15918011/1865424.
Pass you URL of YouTube Video in “urlStr”.
//In .h file
UIWebView *videoView;
// In .m file
videoView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 385)];
[self embedYouTube :urlStr frame:CGRectMake(0, 0, 320, 385)];
[self.view addSubview:videoView];
// methos to embed URL in HTML & load it to UIWebView
- (void)embedYouTube:(NSString*)url frame:(CGRect)frame
{
NSString* embedHTML = #”\
<html><head>\
<style type=\”text/css\”>\
body {\
background-color: transparent;\
color: white;\
}\
</style>\
</head><body style=\”margin:0\”>\
<embed id=\”yt\” src=\”%#\” type=\”application/x-shockwave-flash\” \
width=\”%0.0f\” height=\”%0.0f\”></embed>\
</body></html>”;
NSString* html = [NSString stringWithFormat:embedHTML, url, frame.size.width, frame.size.height];
if(videoView == nil) {
videoView = [[UIWebView alloc] initWithFrame:frame];
[self.view addSubview:videoView];
}
[videoView loadHTMLString:html baseURL:nil];
}
Courtsey :- http://nanostuffs.com/Blog/?p=641
Hope This Will Help You Out.
If this doesn't help you out please check out these links:-
http://blog.softwareispoetry.com/2010/03/how-to-play-youtube-videos-in-your.html
https://gist.github.com/darkredz/5334409
http://maniacdev.com/2012/02/open-source-library-for-easily-playing-a-youtube-video-in-an-mpmovieplayer
If you wanna play youtube, here's a link to youtube player project on github, It's really helpful. and yes it is possible to play it in your uiwebview, just give the webview the url and tell it to load, it shouldn't open in the default player, as far as i believe at least.
I don't know about the Vimeo but for youtube videos you can use HCYouTubeParser to fetch mp4 urls for the youtube videos which can be later played on AVPlayer or MpMoviePlayerVC as per requirements.
I used youtube and vimeo in my Project, I share my codings for you it will very hopeful for you
in my view controller.m
//Button action
- (IBAction)importAudioClip:(id)sender
{
flag = 0;
customActionSheet = [[UIActionSheet alloc]initWithTitle:#"Select Audio/Video from:" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"YouTube",#"Vimeo", nil];
[customActionSheet showInView:self.view];
}
#pragma ActionSheet Delegate Methods
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(#"CLiekc button is %i",buttonIndex);
if([actionSheet.title isEqualToString:#"Select Audio/Video from:"])
{
if (buttonIndex == 0)
{
videoStatus=0;
webView.hidden = NO;
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.youtube.com"]]];
NSLog(#"Taking from Youtube");
}
else if (buttonIndex == 1)
{
videoStatus=1;
UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:#"Vimeo" message:#"Please enter Vimeo Username" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
alertView.tag=123;
alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
[alertView show];
}
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (alertView.tag==123)
{
if (buttonIndex==1)
{
templateText=[[UITextField alloc]init];
templateText = [alertView textFieldAtIndex:0];
templateText.autocapitalizationType=UITextAutocapitalizationTypeWords;
templateText.delegate=self;
if ([templateText.text length]!=0)
{
NSString *str=[templateText.text capitalizedString];
NSLog(#"Str== %#",str);
[self getVimeoDetails:str];
}
}
}
}
-(void)getVimeoDetails:(NSString*)userName
{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://vimeo.com/api/v2/%#/videos.json",userName]]];
[request setHTTPMethod:#"GET"];
NSError *err;
NSURLResponse *response;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSString *resSrt = [[NSString alloc]initWithData:responseData encoding:NSASCIIStringEncoding];
NSLog(#"The value is==%#",resSrt);
vimeoDetailsArray =(NSArray*) [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&err];
NSLog(#"jsonObject== %i",[vimeoDetailsArray count]);
NSString *theReply = [[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSASCIIStringEncoding];
NSLog(#"the reply == %#",theReply);
if(response)
{
if (vimeoDetailsArray==NULL)
{
NSLog(#"its Null");
NSLog(#"null response== %#",response);
// UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Alert!!!" message:[NSString stringWithFormat:#"%#",theReply] delegate:self
// cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
// [alert show];
// [self performSelector:#selector(showAlertMessage:theReply withTitle:#"Alert!!!") withObject:nil afterDelay:5];
vimeoVideoTable.hidden=YES;
[self showAlertMessage:[NSString stringWithFormat:#"%#",theReply] withTitle:#"Alert!!!"];
}
else
{
[self createTableView];
vimeoVideoTable.hidden=NO;
[vimeoVideoTable reloadData];
NSLog(#"got response== %#",response);
}
}
else
{
NSLog(#"faield to connect");
}
if ([responseData length] == 0 && err == nil)
{
NSLog(#"Nothing was downloaded.");
}
else if (err != nil){
if ([[err description] rangeOfString:#"The Internet connection appears to be offline"].location != NSNotFound)
{
NSLog(#"string does not contain ");
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Alert!!!" message:#"Please Check your Internet Connection" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
NSLog(#"Error = %#", err);
}
}
-(void)createTableView
{
if (vimeoVideoTable !=nil)
{
[vimeoVideoTable removeFromSuperview];
vimeoVideoTable=nil;
}
vimeoVideoTable=[[UITableView alloc]initWithFrame:CGRectMake(10, 20, 300, self.view.bounds.size.height-100)];
[vimeoVideoTable setDelegate:self];
[vimeoVideoTable setHidden:YES];
[vimeoVideoTable setDataSource:self];
[self.view addSubview:vimeoVideoTable];
//[vimeoVideoTable reloadData];
}
I definitely suggest youtube_ios_player_helper, "sponsored by" Google.
import youtube_ios_player_helper
class YTViewController: YTPlayerViewDelegate {
#IBOutlet weak var player: YTPlayerView!
// MARK: - Public properties -
var videoID = "k_okcNVZqqI"
// MARK: - View life cycle -
override func viewDidLoad() {
super.viewDidLoad()
self.player.delegate = self
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.load()
self.player.fadeOut()
}
/**
Play video with the relative youtube identifier.
*/
func load() {
Utils.showHUD(self.view)
let options = ["playsinline" : 1]
self.player.loadWithVideoId(self.videoID, playerVars: options)
}
/**
Stop video playing.
*/
func stop() {
}
// MARK: - YOUTUBE video player delegate -
func playerViewDidBecomeReady(playerView: YTPlayerView) {
self.player.playVideo()
}
func playerView(playerView: YTPlayerView, didChangeToState state: YTPlayerState) {
switch state {
case .Playing:
self.player.fadeIn(duration: 0.5)
Utils.hideHUD(self.view)
print("Started playback")
break;
case .Paused:
print("Paused playback")
break;
default:
break;
}
}
}
Use this
NSMutableString *html = [[NSMutableString alloc] initWithCapacity:1] ;
[html appendString:#"<html><head>"];
[html appendString:#"<style type=\"text/css\">"];
[html appendString:#"body {"];
[html appendString:#"background-color: transparent;"];
[html appendString:#"color: white;"];
[html appendString:#"}"];
[html appendString:#"</style>"];
[html appendString:#"</head><body style=\"margin:0\">"];
[html appendString:#"<iframe src=\"//player.vimeo.com/video/84403700?autoplay=1&loop=1\" width=\"1024\" height=\"768\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>"];
[html appendString:#"</body></html>"];
[viewWeb loadHTMLString:html baseURL:urlMovie];
I used the following method to solve the same problem successfully.
Use youtube-ios-player-helper and add the code:
[_playerView loadWithVideoId:#"DmTzboEqfNk" playerVars:#{
#"playsinline" : #1
}];
You can find more vars in Youtube > IFrame API.
I have used WKWebView in storyboard with constraints and added code :
func playVideo() {
if yourLink.lowercased().contains("youtu.be"){
getVideo(videoCode: yourVideoCode)
if let range = yourLink.range(of: "be/"){
let videoId = yourLink[range.upperBound...].trimmingCharacters(in: .whitespaces)
getVideo(videoCode: videoId)
}
} else if yourLink.lowercased().contains("youtube.com"){
if let range = yourLink.range(of: "?v="){
let videoId = yourLink[range.upperBound...].trimmingCharacters(in: .whitespaces)
getVideo(videoCode: videoId)
}
} else if yourLink.lowercased().contains("vimeo.com") {
let url: NSURL = NSURL(string: yourLink)
webKitView.contentMode = UIViewContentMode.scaleAspectFit
webKitView.load(URLRequest(url: url as URL))
}
}
func getVideo(videoCode: String) {
guard
let url = URL(string: "https://www.youtube.com/embed/\(videoCode)")
else { return }
webKitView.load(URLRequest(url: url))
}
To get videoId from youtube/Vimeo links, please refer to :
Youtube Video Id from URL - Swift3
Regex to get vimeo video id in swift 2
Hope will help! :)
Related
My code looks like this:
_player = [AVPlayer playerWithURL:destination];
_playerVC = [AVPlayerViewController new];
_playerVC.player = _player;
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:_playerVC animated:YES completion:^{
[_player play];
}];
});
_player represents AVPlayer and _playerVC represents AVPlayerViewController. I have strong global references to these objects.
Using terminal, I played the file located at the destination (open -a quicktime\ player destinationURLAbsoluteString) and saw the file is properly loaded since it was playing.
It is a m4v file. I have played a m4a file and it properly gave me audio. I have also substituted the url I have for destination to some remote url and that worked for video. This leads me to believe it has something to do with my video. What's weird is that my AVPlayerViewController does show a black screen with all the normal controls, and even shows the video is 2 minutes and 23 seconds. Upon opening the video file manually, I can see that it is also 2 minutes and 23 seconds.
I can forward through the video properly by dragging the white dot indicative of the video's position, but I never hear anything, nor do I see anything but the black screen and controls.
TL;DR
NSLog(#"Destination: %#",destination);
prints: file:///Users/MyLogin/Library/Developer/CoreSimulator/Devices/694F4C94-F785-4931-A312-4C3E7DE8673A/data/Containers/Data/Application/76C923BE-5B25-41F7-9145-63414657FDF6/Documents/mzvf_5914002519860647075.640x352.h264lc.D2.p.m4v
All in all, it looks like I'm properly retrieving the video, but for some reason my player controller is completely black and void of audio. Any help is much appreciated.
Source Code:
.m file:
#import "ViewController.h"
#import "View2ViewController.h"
#import <AVKit/AVKit.h>
#import <AVFoundation/AVFoundation.h>
#interface ViewController ()
#property NSDictionary *requestedSong;
#property (strong) AVPlayer *player; //Declare Globally
#property (strong) AVPlayerViewController *playerVC;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor yellowColor];
UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 200, 50)];
button.center = self.view.center;
button.backgroundColor = [UIColor blueColor];
[button setTitle:#"Query Songs" forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonClicked) forControlEvents:UIControlEventTouchDown];
[self.view addSubview:button];
UIButton *button2 = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 200, 50)];
button2.center = CGPointMake(button.center.x, button.center.y + 200);
button2.backgroundColor = [UIColor blueColor];
[button2 setTitle:#"Listen to the first song" forState:UIControlStateNormal];
[button2 addTarget:self action:#selector(button2Clicked) forControlEvents:UIControlEventTouchDown];
[self.view addSubview:button2];
}
-(void)button2Clicked{
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc]init]];
NSURL *url = [NSURL URLWithString:[_requestedSong objectForKey:#"previewUrl"]];
NSMutableURLRequest *req = [[NSMutableURLRequest alloc]initWithURL:url];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:req];
[task resume];
}
-(void)buttonClicked{
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc]init]];
NSURL *url = [NSURL URLWithString:#"https://itunes.apple.com/search?media=movie&entity=movie&term=Mad"];
NSMutableURLRequest *req = [[NSMutableURLRequest alloc]initWithURL:url];
NSURLSessionDataTask *task = [session dataTaskWithRequest:req];
[task resume];
}
-(NSURL*)localFilePathForURL:(NSURL *) previewUrl{
//get the directory to use
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true) objectAtIndex:0];
//create the full path
NSString *fullPath = [documentsPath stringByAppendingPathComponent:previewUrl.lastPathComponent];
//append the filename and append to document path url
return [NSURL fileURLWithPath:fullPath];
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location{
NSURL* originalURL = downloadTask.originalRequest.URL;
NSURL *destination = [self localFilePathForURL:originalURL];
NSLog(#"Destination: %#",destination);
NSFileManager *defaultFileManager = [NSFileManager defaultManager];
if([defaultFileManager fileExistsAtPath:destination.absoluteString]){
[defaultFileManager removeItemAtURL:destination error:nil];
}
NSError *error;
#try {
[defaultFileManager copyItemAtURL:location toURL:destination error:&error];
} #catch (NSException *exception) {
NSLog(#"copy caught with exception: %#",exception);
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
_player = [AVPlayer playerWithURL:destination];
_playerVC = [AVPlayerViewController new];
_playerVC.player = _player;
[self presentViewController:_playerVC animated:YES completion:^{
[_player play];
}];
});
NSLog(#"Hello");
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data{
NSError *error2;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:1 error:&error2];
_requestedSong = [[dict valueForKey:#"results"] objectAtIndex:0];
NSLog(#"Searched: %#",[_requestedSong objectForKey:#"trackName"]);
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
completionHandler(NSURLSessionResponseAllow);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
.h file:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
#end
UPDATE:
Upon using the actual URL endpoint for mad max instead of downloading the video, it also displays a blank video. This must mean there's something weird about the format of the video or how it interacts with the AVPlayer.
You should setup observer for AVPlayer status to call play only when it will be ready to play.
How to do it - check answers here: AVPlayer And Local Files
check the following
if ((_playerVC.player.rate != 0) && (_playerVC.player.error == nil)) {
// player is playing
} else {
// Something wrong
}
also you can observe the rate property of the player. More info here
I'm in the progress of migrating my app from UIWebView to WKWebView. All is going well and working as I tinker more with it. However, I notice now that I can't download forum attachments.
I'm using HCDownload, and thus far has always worked perfect for me, so I know it's not on that end. I believe its the request, but I cant figure it out.
I know the following:
UIWebView => WKWebView Equivalent
--------------------------------------------------------------
didFailLoadWithError => didFailNavigation
webViewDidFinishLoad => didFinishNavigation
webViewDidStartLoad => didStartProvisionalNavigation
shouldStartLoadWithRequest => decidePolicyForNavigationAction
So with that known I am trying below:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURLRequest *request = navigationAction.request;
NSURL *fileURl = [request URL];
NSString *externalFileExtension = [fileURl pathExtension];
NSString *internalFileExtension = [[fileURl absoluteString] pathExtension];
HCDownloadViewController *dlvc = [[HCDownloadViewController alloc] init];
UINavigationController *vc = [[UINavigationController alloc] initWithRootViewController:dlvc];
dlvc.delegate = self;
vc.transitioningDelegate = self;
if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {
//External file extensions
if ([fileExtensions containsObject:[externalFileExtension lowercaseString]]) {
[dlvc downloadURL:fileURl userInfo:nil];
[self presentViewController:vc animated:YES completion:nil];
[vc release];
NSLog(#"externalURL is %#", fileURl);
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
//Internal file links
if ([fileExtensions containsObject:[internalFileExtension lowercaseString]]) {
[self presentViewController:vc animated:YES completion:nil];
[dlvc downloadURL:fileURl userInfo:nil];
[vc release];
NSLog(#"internalURL is %#", fileURl);
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
It will fire my download controller by finding the file extension, but instead it downloads the index.php, not the file.
Example url:
https://example.com/index.php?app=core&module=attach§ion=attach&attach_id=1234=example.zip;
What am I doing wrong. It worked fine before in UIWebView and I know things are done differently. But how can it download something from say dropbox just fine, but an attached file on a forum gets goofed up.
Any help would be appreciated
Well heres what I ended up with, and all seems to be working fine.
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
for (NSHTTPCookie *cookie in cookies) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
}
decisionHandler(WKNavigationResponsePolicyAllow);
//NSLog(#"decidePolicyForNavigationResponse");
}
//Download manager
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURLRequest *request = navigationAction.request;
fileURL = request.URL;
HCDownloadViewController *dlvc = [[HCDownloadViewController alloc] init];
UINavigationController *vc = [[UINavigationController alloc] initWithRootViewController:dlvc];
vc.transitioningDelegate = self;
dlvc.delegate = self;
if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {
//Internal file links
NSString *internalFileExtension = fileURL.absoluteString.pathExtension;
if ([fileExtensions containsObject:[internalFileExtension lowercaseString]]) {
//Fire download
[dlvc downloadURL:fileURL userInfo:nil];
[self presentViewController:vc animated:YES completion:nil];
[vc release];
NSLog(#"internalURL is %#", fileURL);
if (decisionHandler) {
decisionHandler(WKNavigationActionPolicyCancel);
}
return;
}
//External file extensions
NSString *externalFileExtension = fileURL.pathExtension;
if ([fileExtensions containsObject:[externalFileExtension lowercaseString]]) {
//Fire download
[dlvc downloadURL:fileURL userInfo:nil];
[self presentViewController:vc animated:YES completion:nil];
[vc release];
NSLog(#"externalURL is %#", fileURL);
if (decisionHandler) {
decisionHandler(WKNavigationActionPolicyCancel);
}
return;
}
}
if (decisionHandler) {
decisionHandler(WKNavigationActionPolicyAllow);
}
}
You are probably downloading a not-authorized page because your WKWebView and HCDownload instances don't share cookie sessions like UIWebView could. That's a necessary trade-off for the WK2 process model's speed & security improvements.
I added downloading to my WKWebKit-based OSX/Swift mini-browser by implementing _WKDownloadDelegate. Its a totally undocumented private protocol as of El Cap and iOS9. It lets your navigation delegate call decisionHandler(_WKNavigationResponsePolicyBecomeDownload) whereby WebKit will download in the background after giving you the chance to pick/change a file name. I haven't the foggiest idea on how to implement a file picker in iOS yet, nor if using that protocol would be allowed by the App Store reviewers. But my app now does correctly handle downloading from session-authentication sites like your PHP forum.
Swift 4:
ChrisOSX's sollution also solved my issue. I'm trying to download a document from a link on a site after logging to that site. I've used WKZombie to scrape the link, and then I wanted to download the file using Alamofire. I added this
if let httpResponse = navigationResponse.response as? HTTPURLResponse, let url = httpResponse.url {
let allHeaders = httpResponse.allHeaderFields.reduce([String : String](), { (result, next) -> [String : String] in
guard let stringKey = next.key as? String, let stringValue = next.value as? String else { return result }
var buffer = result
buffer[stringKey] = stringValue
return buffer
})
let cookies = HTTPCookie.cookies(withResponseHeaderFields: allHeaders, for: url)
for cookie in cookies {
HTTPCookieStorage.shared.setCookie(cookie)
}
}
to:
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: #escaping (WKNavigationResponsePolicy) -> Void)
After this, the cookies are stored in the shared cookies, and I was able to download the file with Alamofire without and changes to the download methods..
If I click on the mp3 url in a UIWebView, It pops the media player to play the mp3 automatically.
But here what I am need is just ask confirmation from the user to play the song in UIWebview media player.Is it possible to access UIWebview media player? If it is how?
Please help me
Yes, it is possible to ask confirmation from the user.
User UIWebView delegate method :
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
self.URL = [request URL];
if (navigationType == UIWebViewNavigationTypeLinkClicked)
{
AVURLAsset* asset;
self.songURL = [NSString stringWithFormat:#"%#",self.URL];
//Check for supported song formatted
if([self.songURL hasSuffix:#".mp3"] ||
[self.songURL hasSuffix:#".wav"] ||
[self.songURL hasSuffix:#".aiff"] ||
[self.songURL hasSuffix:#".aac"] ||
[self.songURL hasSuffix:#".m4a"] ||
[self.songURL hasSuffix:#".m4p"] ||
[self.songURL hasSuffix:#".caf"])
{
asset = [[AVURLAsset alloc]initWithURL:self.URL options:nil];
if(asset != nil)
{
UIActionSheet *actSheet = [[UIActionSheet alloc]
initWithTitle:#"Songs"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:#"Download"
otherButtonTitles:#"Listen Online", nil];
[actSheet showInView:self.view];
}
[asset release];
return NO;
}
}
return YES;
}
And on UIActionSheetDelegate method:
-(void) actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == 1)
{
[self.webView loadRequest:[NSURLRequest requestWithURL:self.URL]];
}
}
I have used a UIWebView to show an url over that. It works fine but client said to download video and save it into photo gallery.i have written code for downloading video from UIWebView and saving it to photo gallery. But i have written a condition, if user clicked on a video that is already downloaded and saved to photo gallery,to show an alert that file is already saved.then i see on that when this message is shown in the same time there is black screen appears on the view same as media player . so my question is that- How to Control or remove that black screen from web view i have removed black screen by reloading same UIWebView but this is not fulfilling my requirement so please help me... Please.. Please
Here is my code for showing url on UIWebView and saving video file
#import "WebViewController.h"
#import "AppDelegate.h"
#interface WebViewController ()
{
NSURL *theRessourcesURL;
}
#property (nonatomic, strong) NSString *lastURL;
#property(nonatomic,strong)MBProgressHUD *hud;
#end
#implementation WebViewController
#synthesize webView;
- (void)viewDidLoad
{
[super viewDidLoad];
BOOL isLandscape = UIDeviceOrientationIsLandscape(self.interfaceOrientation);
BOOL isPortrait = UIDeviceOrientationIsPortrait(self.interfaceOrientation);
if(isLandscape)
{
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
if (screenRect.size.height > 500)
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 568, 300)];
}
else
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 480, 300)];
}
}
else
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 1004, 748)];
}
NSLog(#"isLandscape");
}
else if (isPortrait)
{
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
if (screenRect.size.height > 500)
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 320, 548)];
}
else
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 320, 460)];
}
}
else
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 768, 984)];
}
}
[webView setDelegate:self];
webView.tag = 999;
for (UIView* subView in webView.subviews) {
if ([subView isKindOfClass:[UIScrollView class]]) {
currentScrollView = (UIScrollView *)subView;
currentScrollView.delegate = (id) self;
}
}
//demo url
NSString *fullURL = #"http://demo.php.anuj.com/videoapp-t/home";
NSURL *url = [NSURL URLWithString:fullURL];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webView loadRequest:requestObj];
pull = [[PullToRefreshView alloc] initWithScrollView:currentScrollView];
[pull setDelegate:self];
pull.tag = 998;
[currentScrollView addSubview:pull];
[self.view addSubview:webView];
}
-(void)pullToRefreshViewShouldRefresh:(PullToRefreshView *)view {
[(UIWebView *)[self.view viewWithTag:999] reload];
}
- (void)willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
BOOL isLandscape = UIDeviceOrientationIsLandscape(self.interfaceOrientation);
BOOL isPortrait = UIDeviceOrientationIsPortrait(self.interfaceOrientation);
if(isLandscape)
{
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
if (screenRect.size.height > 500)
{
webView.frame =CGRectMake(0, 20, 568, 300);
}
else
{
webView.frame =CGRectMake(0, 20, 480, 300);
}
}
else
{
webView.frame =CGRectMake(0, 20, 1004, 748);
}
NSLog(#"isLandscape");
}
else if (isPortrait)
{
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
if (screenRect.size.height > 500)
{
webView.frame = CGRectMake(0, 20, 320, 548);
}
else
{
webView.frame =CGRectMake(0, 20, 320, 460);
}
}
else
{
webView.frame =CGRectMake(0, 20, 768, 984);
}
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - webview
- (void)webViewDidStartLoad:(UIWebView *)webView {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeIndeterminate;
hud.labelText = #"Loading...";
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[MBProgressHUD hideHUDForView:self.view animated:YES];
[(PullToRefreshView *)[self.view viewWithTag:998] finishedLoading];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
AppDelegate *appdel=[[UIApplication sharedApplication]delegate];
NetworkStatus remoteHostStatus = [appdel.reachability currentReachabilityStatus];
if (remoteHostStatus == NotReachable)
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Anuj Demo" message:#"Internet connection required. Please check connectivity to internet." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
else
{
// UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Anuj Demo" message:#"Internet connection required. Please pull to refresh." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
// [alert show];
}
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[MBProgressHUD hideHUDForView:self.view animated:YES];
[(PullToRefreshView *)[self.view viewWithTag:998] finishedLoading];
}
-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType
{
if ( inType == UIWebViewNavigationTypeLinkClicked )
{
theRessourcesURL = [inRequest URL];
NSString *fileExtension = [theRessourcesURL pathExtension];
if ([fileExtension isEqualToString:#"mp4"] || [fileExtension isEqualToString:#"mov"] || [fileExtension isEqualToString:#"m4v"])
{
// Get the filename of the loaded ressource form the UIWebView's request URL
NSString *filename = [theRessourcesURL lastPathComponent];
NSLog(#"Filename: %#", filename);
NSFileManager *filemanager=[NSFileManager defaultManager];
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory= [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:filename];
BOOL success =[filemanager fileExistsAtPath:path];
if (success ==TRUE) {
UIAlertView *filenameAlert = [[UIAlertView alloc] initWithTitle:#"Reel Africa" message:[NSString stringWithFormat:#"The file %# already exists.", filename] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[filenameAlert show];
// Here if i reload webview then it works otherwise giving black screen on webview like media player( [webview reload])
}
else
{
[self performSelector:#selector(saveVideoTOPhotoAlbum) withObject:nil afterDelay:0.2];
}
}
else if([fileExtension isEqualToString:#"wmv"] || [fileExtension isEqualToString:#"3gp"] || [fileExtension isEqualToString:#"3G2"])
{
UIAlertView *filenameAlert = [[UIAlertView alloc] initWithTitle:#"Anuj Demo" message:#"iPhone does not support this vedio format." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[filenameAlert show];
}
NSString *tempString = [NSString stringWithFormat:#"%#",[inRequest URL]];
if ([tempString rangeOfString:#"?ultima"].location != NSNotFound) {
[[UIApplication sharedApplication] openURL:[inRequest URL]];
return NO;
}
}
return YES;
}
-(void)saveVideoTOPhotoAlbum
{
NSString *filename = [theRessourcesURL lastPathComponent];
NSLog(#"Filename: %#", filename);
// Get the path to the App's Documents directory
NSString *docPath = [self documentsDirectoryPath];
// Combine the filename and the path to the documents dir into the full path
NSString *pathToDownloadTo = [NSString stringWithFormat:#"%#/%#", docPath, filename];
// Load the file from the remote server
NSData *tmp = [NSData dataWithContentsOfURL:theRessourcesURL];
// Save the loaded data if loaded successfully
if (tmp != nil) {
NSError *error = nil;
[tmp writeToFile:pathToDownloadTo options:NSDataWritingAtomic error:&error];
// Write the contents of our tmp object into a file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSString *getImagePath = [basePath stringByAppendingPathComponent:filename];
printf(" \n\n\n-Video file == %s",[getImagePath UTF8String]);
UISaveVideoAtPathToSavedPhotosAlbum ( getImagePath,self, #selector(video:didFinishSavingWithError: contextInfo:), nil);
if (error != nil) {
NSLog(#"Failed to save the file: %#", [error description]);
} else {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[MBProgressHUD hideHUDForView:self.view animated:YES];
// Display an UIAlertView that shows the users we saved the file :)
UIAlertView *filenameAlert = [[UIAlertView alloc] initWithTitle:#"Anuj Demo" message:[NSString stringWithFormat:#"The file %# has been saved.", filename] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[filenameAlert show];
}
}
}
- (void) video: (NSString *) videoPath didFinishSavingWithError: (NSError *) error contextInfo: (void *) contextInfo
{
NSLog(#"Finished saving video with error: %#", error);
//Anuj here ****
}
- (NSString *)documentsDirectoryPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
return documentsDirectoryPath;
}
#end
If file exist, you should return NO. try it.
I am using HCYoutubeParser(https://github.com/hellozimi/HCYoutubeParser) to play some videos in my ios app. When I am trying to play some video, it doesn't seem to play it.
The code looks like this:
- (void)playVideo:(id)sender
{
if (_urlToLoad)
{
MPMoviePlayerViewController *player = [[MPMoviePlayerViewController alloc]initWithContentURL:_urlToLoad];
_mp = player;
[self presentViewController:_mp animated:YES completion:nil];
}
}
- (void)submitYouTubeURL:(id)sender {
[playButton setImage:nil forState:UIControlStateNormal];
NSURL *url = [NSURL URLWithString:_urlOfYoutube];
activityIndicator.hidden = NO;
[HCYoutubeParser thumbnailForYoutubeURL:url thumbnailSize:YouTubeThumbnailDefaultHighQuality completeBlock:^(UIImage *image, NSError *error) {
if (!error) {
[playButton setBackgroundImage:image forState:UIControlStateNormal];
playButton.hidden = NO;
NSDictionary *qualities = [HCYoutubeParser h264videosWithYoutubeURL:url];
_urlToLoad = nil;
_urlToLoad = [NSURL URLWithString:[qualities objectForKey:#"medium"]];
NSLog(#"%#",[NSURL URLWithString:[qualities objectForKey:#"medium"]]);
activityIndicator.hidden = YES;
[playButton setImage:[UIImage imageNamed:#"play_button"] forState:UIControlStateNormal];
}
else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[alert show];
}
}];
}
The line that gives the problem is _urlToLoad = [NSURL URLWithString:[qualities objectForKey:#"medium"]];
[NSURL URLWithString:[qualities objectForKey:#"medium"]] returns null..
How do I solve this?
In my case , I was getting 0 key value pair for
NSDictionary *qualities = [HCYoutubeParser h264videosWithYoutubeURL:url];
Ie , I was getting qualities having 0 key value pair.
I found that code in HCYoutubeParser.m , in method + (NSDictionary *)h264videosWithYoutubeID:(NSString *)youtubeID a variable signature variable was not getting initialized , so I replaced NSString *signature = nil; with NSString *signature = #"";