Hello I'm parsing html string into web view and here is how I check for youtube videos and add them to iframe:
- (NSString *)extendYouTubeSupportInHtml:(NSString *)html {
static dispatch_once_t onceToken;
static NSRegularExpression *youtubeEmbedRegex;
dispatch_once(&onceToken, ^{
youtubeEmbedRegex = [[NSRegularExpression alloc] initWithPattern:#"<object.*src.*/v/(.*?)['|\"].*object\\s*>" options:NSRegularExpressionCaseInsensitive error:nil];
});
NSArray *matchs;
if (html != nil) {
matchs = [youtubeEmbedRegex matchesInString:html options:0 range:NSMakeRange(0, html.length)];
}else{
matchs = nil;
}
NSInteger rangeOffset = 0;
for (NSTextCheckingResult *match in matchs) {
NSRange objectRange = NSMakeRange([match rangeAtIndex:0].location + rangeOffset, [match rangeAtIndex:0].length);
NSRange idRange = NSMakeRange([match rangeAtIndex:1].location + rangeOffset, [match rangeAtIndex:1].length);
NSString* youtubrId = [html substringWithRange:idRange];
// Add uniq id to img tag
NSString* iframe = [NSString stringWithFormat:#"<iframe src=\"http://www.youtube.com/embed/%#\" frameborder=\"0\" allowfullscreen></iframe>", youtubrId];
html = [html stringByReplacingCharactersInRange:objectRange withString:iframe];
rangeOffset += iframe.length - objectRange.length;
}
return html;
}
And here is how I'm displaying the web view:
- (id)initWithFrame:(CGRect)frame dict:(NSDictionary *)dict {
self = [super initWithFrame:frame];
if (self) {
self.webView = [[[UIWebView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)] autorelease];
self.webView.backgroundColor = [UIColor clearColor];
self.webView.opaque = NO;
self.webView.delegate = self;
self.webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.webView.scalesPageToFit = NO;
self.webView.allowsInlineMediaPlayback = YES;
self.webView.mediaPlaybackRequiresUserAction = NO;
[self removeBackgroundFromWebView:self.webView];
[self addSubview:self.webView];
self.dictionary = dict;
}
return self;
}
My issue is that when I start playing video - memory usage is going up to 30MB, video starts to stutter, audio/video doesn't match, and when i close it - the memory usage is still the same.
I have a couple of leaks in AudioToolbox, also.
I'm using iOS 6 SDK, and iOS 6.
iOS 6 sdk broke the code - now it's not displaying anything in iOS 5.
This is my way of play a youtube video inside a app.
I am using iFrame to load youtube video inside my app.
follow this steps and you will too.
create a uiwebview and connect it to your .h file. Mine is _webView.
Add this method to your .m file.
-(void)embedYouTube{
NSString *embedHTML = #"<iframe width=\"300\" height=\"250\" src=\"http://www.youtube.com/embed/rOPI5LDo7mg\" frameborder=\"0\" allowfullscreen></iframe>";
NSString *html = [NSString stringWithFormat:embedHTML];
[_webView loadHTMLString:html baseURL:nil];
[self.view addSubview:_webView];
}
I am using the embedded code in youtube video. (I hope you know what it is)
call this method inside your viewdidload
[self embedYouTube];
Run the app and you will see the video in your view. This way is perfectly working for me and i think this will help for your too.
Related
I'm trying to implement an embedded Youtube video in my application.
The only way I've managed to do this is with frameworks like LBYouTubeView or HCYotubeParser. From what I've read they are against the Youtube TOS because they basically strip the video link from the http getting something like this.
This indeed can be played inside a MPMoviePlayerController without any problems (and without leaving the application).
From what I've search there are two applications that managed to do this Vodio and Frequency so I'm wondering if there is a special sdk for developers or an affiliate program I might have missed.
From what I also read Youtube Engineers respond to this questions if they are tagged with youtube-api so I hope you could clear this up.
I've read about the UIWebView implementations but that scenario actually opens the an external video player which I have no control over.
I've looked around for a while and this is what I came up with:
It involves adding a youtube.html file to your project with the following code:
<html>
<head><style>body{margin:0px 0px 0px 0px;}</style></head>
<body>
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
<div id="player"></div>
<script>
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "http://www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubePlayerAPIReady()
{
player = new YT.Player('player',
{
width: '640',
height: '360',
videoId: '%#',
playerVars: {'autoplay' : 1, 'controls' : 0 , 'vq' : 'hd720', 'playsinline' : 1, 'showinfo' : 0, 'rel' : 0, 'enablejsapi' : 1, 'modestbranding' : 1},
events:
{
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event)
{
event.target.playVideo();
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event)
{
if (event.data == YT.PlayerState.ENDED)
{
window.location = "callback:anything";
};
}
function stopVideo()
{
player.stopVideo();
window.location = "callback:anything";
}
function getTime()
{
return player.getCurrentTime();
}
function getDuration()
{
return player.getDuration();
}
function pause()
{
player.pauseVideo();
}
function play()
{
player.playVideo();
}
</script>
</body>
</html>
Also you have to create a UiWebView subclass that is also a delegate for UIWebViewDelegate
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self == nil) return nil;
self.mediaPlaybackRequiresUserAction = NO;
self.delegate = self;
self.allowsInlineMediaPlayback = TRUE;
self.userInteractionEnabled = FALSE;
return self;
}
- (void)loadVideo:(NSString *)videoId
{
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"YouTube" ofType:#"html"];
// if (filePath == nil)
NSError *error;
NSString *string = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
// TODO: error check
string = [NSString stringWithFormat:string, videoId];
NSData *htmlData = [string dataUsingEncoding:NSUTF8StringEncoding];
// if (htmlData == nil)
NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *targetPath = [documentsDirectoryPath stringByAppendingPathComponent:#"youtube2.html"];
[htmlData writeToFile:targetPath atomically:YES];
[self loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:targetPath]]];
File = 0;
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if ([[[request URL] scheme] isEqualToString:#"callback"])
{
Playing = FALSE;
NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *targetPath = [documentsDirectoryPath stringByAppendingPathComponent:#"youtube2.html"];
NSError *error;
[[NSFileManager defaultManager] removeItemAtPath:targetPath error:&error];
}
return YES;
}
Basically it creates a UIWebView and loads the code in the youtube.html file. Because the youtube.html is static and I need to load a certain id I create a copy on the fly in the documents folder youtube2.html in which I add the string id.
The whole thing is that [self loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:targetPath]]]; works but loading a NSUrlRequest from a string doesn't.
The Javascript functions you see in the html file are for controlling the video. If you need access to time or full duration you can get them like this:
float VideoDuration = [[YT_WebView stringByEvaluatingJavaScriptFromString:#"getDuration()"] floatValue];
float VideoTime = [[YT_WebView stringByEvaluatingJavaScriptFromString:#"getTime()"] floatValue];
I have a problem, need help.
I have a table, on cell I have horizontal scroll with images. Images are downloaded from internet.
When i download the 6th image, my app crashes.
For async upload I use https://github.com/rs/SDWebImage
-(void) fastCreateImage
{
int tempID = self.currentPageNow;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.2f * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
if(tempID==self.currentPageNow)
{
NSUInteger objIdx = [self.imageViews indexOfObject: [NSNumber numberWithInt:tempID]];
if(objIdx != NSNotFound) {
NSLog(#"WAS CACHED!!!!!!");
}
else
{
UIImageView *myImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 193.5f)];
NSString *urlInString =[NSString stringWithFormat:#"%#/uploads/gallery/hotels/%#",webSite,[self.urlGarbage objectAtIndex:self.currentPageNow]];
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:[NSURL URLWithString:urlInString]
delegate:self
options:0
success:^(UIImage *image, BOOL cached)
{
myImageView.image = image;
[[self.views objectAtIndex:tempID] addSubview:myImageView];
[self.imageViews addObject:[NSNumber numberWithInt:tempID]];
NSLog(#"LOADED IMG");
}
failure:nil];
[myImageView release];
}
}
});
}
Since you're getting a memory warning, I guess your images are too large to fit in memory. An image uses a maximum of width*height*4 (depending on color depth) of your memory. Calculate this memory requirement for each of your images to see if this is the problem.
I have to reload the mainviewcontroller webview second time and reload the webview.
APPDELGATE:
- (void) webViewDidFinishLoad:(UIWebView*) theWebView
{
// only valid if FooBar.plist specifies a protocol to handle
if (self.invokeString)
{
// this is passed before the deviceready event is fired, so you can access it in js when you receive deviceready
NSString* jsString = [NSString stringWithFormat:#"var invokeString = \"%#\";", self.invokeString];
[theWebView stringByEvaluatingJavaScriptFromString:jsString];
}else {
if([loginComplete isEqualToString:#"1"] ){
NSString *page = #"intro.html";
NSString* jsString = [NSString stringWithFormat:#"loadParams('%#','%#','%#');", at,userfbid,page];
[theWebView stringByEvaluatingJavaScriptFromString:jsString];
}
else {
NSString *page = #"friends.html";
NSString* jsString = [NSString stringWithFormat:#"loadParams('%#','%#','%#');", at,userfbid,page];
[theWebView stringByEvaluatingJavaScriptFromString:jsString];
}
// Black base color for background matches the native apps
theWebView.backgroundColor = [UIColor grayColor];
return [self.viewController webViewDidFinishLoad:theWebView];
}
-(void)insert{
self.viewcontroller.webview.delegate=self;
}
Webdelegate is not firing in insert.
Thanks
Try this:
return [self webViewDidFinishLoad:theWebView];
instead of:
return [self.viewController webViewDidFinishLoad:theWebView];
Because your AppDelegate is the delegate for webView's webViewDidFinishLoaded, not webView itself.
I am working on displaying several Images in a scrollview loaded from a MapServer which returns an image of showing a map.
So what I did is I have created 4 UIImageViews, put them in a NSMutableDictionary.
Then when scrolling to the desirable Image it will initiate to load the data from the url asynchronous.
so first I display an UIActivityIndicatorView, then it will load the data and at the end hide the UIActivityIndicatorView and display the UIImageView.
everything is working more or less fine, apart that it takes sooo long until the image displays, allthough the image is not that big and I have a log text indicating that the end of the function arrived... this log message appears immediately but the image still does not show...
If I call the URL by the Webbrowser the image is shown immediately as well.
below you see my piece of code.
- (void) loadSRGImage:(int) page {
UIImageView *currentSRGMap = (UIImageView *)[srgMaps objectForKey:[NSString stringWithFormat:#"image_%i", page]];
UIActivityIndicatorView *currentLoading = (UIActivityIndicatorView *)[srgMaps objectForKey:[NSString stringWithFormat:#"loading_%i", page]];
// if the image has been loaded already, do not load again
if ( currentSRGMap.image != nil ) return;
if ( page > 1 ) {
MKCoordinateSpan currentSpan;
currentSpan.latitudeDelta = [[[srgMaps objectForKey:[NSString stringWithFormat:#"span_%i", page]] objectForKey:#"lat"] floatValue];
currentSpan.longitudeDelta = [[[srgMaps objectForKey:[NSString stringWithFormat:#"span_%i", page]] objectForKey:#"lon"] floatValue];
region.span = currentSpan;
region.center = mapV.region.center;
[mapV setRegion:region animated:TRUE];
//[mapV regionThatFits:region];
}
srgLegende.hidden = NO;
currentSRGMap.hidden = YES;
currentLoading.hidden = NO;
[currentLoading startAnimating];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage:)
object:[NSString stringWithFormat:#"%i", page]];
[queue addOperation:operation];
[operation release];
}
- (void) loadImage:(NSInvocationOperation *) operation {
NSString *imgStr = [#"image_" stringByAppendingString:(NSString *)operation];
NSString *loadStr = [#"loading_" stringByAppendingString:(NSString *)operation];
WGS84ToCH1903 *converter = [[WGS84ToCH1903 alloc] init];
CLLocationCoordinate2D coord1 = [mapV convertPoint:mapV.bounds.origin toCoordinateFromView:mapV];
CLLocationCoordinate2D coord2 = [mapV convertPoint:CGPointMake(mapV.bounds.size.width, mapV.bounds.size.height) toCoordinateFromView:mapV];
int x1 = [converter WGStoCHx:coord1.longitude withLat:coord1.latitude];
int y1 = [converter WGStoCHy:coord1.longitude withLat:coord1.latitude];
int x2 = [converter WGStoCHx:coord2.longitude withLat:coord2.latitude];
int y2 = [converter WGStoCHy:coord2.longitude withLat:coord2.latitude];
NSString *URL = [NSString stringWithFormat:#"http://map.ssatr.ch/mapserv?mode=map&map=import/dab/maps/dab_online.map&mapext=%i+%i+%i+%i&mapsize=320+372&layers=DAB_Radio_Top_Two", y1, x1, y2, x2];
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:URL]];
UIImage* image = [[UIImage alloc] initWithData:imageData];
[imageData release];
UIImageView *currentSRGMap = (UIImageView *)[srgMaps objectForKey:imgStr];
UIActivityIndicatorView *currentLoading = (UIActivityIndicatorView *)[srgMaps objectForKey:loadStr];
currentSRGMap.hidden = NO;
currentLoading.hidden = YES;
[currentLoading stopAnimating];
[currentSRGMap setImage:image]; //UIImageView
[image release];
NSLog(#"finished loading image: %#", URL);
}
I had a similar thing in my app, and i used the SDWebImage from https://github.com/rs/SDWebImage. This has a category written over UIImageView. You need to mention a placeholder image and a url to the UIImageView. It will display the image once it is downloaded and also maintains a cache of the downloaded images, hence avoiding multiple server calls.
My app consists of an image gallery. It is a scroll view which displays pics retrieved from the sqlite db. User can scroll the images, add or delete images etc. I can add a picture to the gallery dynamically. But the problem comes when I need to implement the delete functionality. I use the following code but even after calling removeFromSuperView the image is not getting removed from the scrollview.
-(void)deleteDeck{
if(selectedEditDeck!=0){
[deck deleteSelectedDeck:selectedEditDeck]; //deleting from database
//problem starts here ***
[(UIImageView*)[decksGallery viewWithTag:selectedEditDeck-1]removeFromSuperview];
[self loadGallery];
selectedEditDeck=0;
//Ends here*****
[tableData release];
tableData=[NSMutableArray array];
[self showCardNamesinTable];
[aTableView reloadData];
}
I have already created the uiscrollview in the loadview method. Then to refresh the view after every deletion and addition of images so that I can display the updated gallery, I use the following piece of code:
-(void)loadGallery{ //Reloading all for adding a single deck image.
//Database part****
NSString *sqlStr = [NSString stringWithFormat:#"select first_card from decksTable"];
char *sql = (char*)[sqlStr UTF8String];
kidsFlashCardAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSMutableArray *galleryImagesArray=[appDelegate.dbConnection fetchColumnFromTable:sql col:0];
NSArray *sysPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *docDirectory = [sysPaths objectAtIndex:0];
numberofImages = [galleryImagesArray count];
printf("number is %d",numberofImages);//Database part of code ends here
//In the following fragment of code I add images to UIscrollView
for (int i = 0; i < [galleryImagesArray count]; i++) {
CGFloat yOrigin = i * 65;
NSString *filePath = [NSString stringWithFormat:#"%#/%#", docDirectory,[galleryImagesArray objectAtIndex:i]];
galleryImage = [[UIImageView alloc] initWithFrame:CGRectMake(yOrigin+140, 15,50,50 )];
//galleryImage.tag=[galleryImagesArray count];
galleryImage.tag=i;
printf("THE TAG IS %d",galleryImage.tag);
galleryImage.clipsToBounds=YES;
galleryImage.layer.cornerRadius=11.0;
galleryImage.backgroundColor=[UIColor clearColor];
galleryImage.image =[UIImage imageWithContentsOfFile:filePath];
[decksGallery addSubview:galleryImage];
[galleryImage release];
}
decksGallery.contentSize = CGSizeMake(115*[galleryImagesArray count], 80);
//[decksGallery reloadInputViews];
Make sure your [decksGallery viewWithTag:selectedEditDeck-1] is not returning nil and the image was actually deleted from your db before the refresh code running.
In addition, you are setting imageView.tag = i; in your creation code, since the i would be 0 which is the tag's default value for every UIView, you'd better fix your creation code as well.
If you just want to remove the image from your imageView, you can also do imageView.image = nil;
UIImageView*imageView = (UIImageView*)[decksGallery viewWithTag:selectedEditDeck-1];
[imageView removeFromSuperview];
imageView = nil;