Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preview Embedded Links in iOS App Like Facebook

Tags:

ios

I'm trying to embed a link preview in an iOS application in the same way that Facebook does:

enter image description here

I'm trying to figure a way to grab the most suitable image (and return the url to it), the page title, and maybe even a meta description and pass it back to the application, but I'm unsure of the best way.

There are API's that do this, most for a price, but it seems like it should not be this difficult. Any thoughts?

like image 845
d2burke Avatar asked Sep 19 '12 14:09

d2burke


2 Answers

You can do this server-side or client-side.

Server-side, you can use a script (like the one you've built) to grab the <head> tag of the HTML page.

Client-side you can download the whole page as HTML (as an example, Mashable is ~180KB) with NSURLConnection or a library like AFNetworking and parse it with a XML parser to find the <head> tag.

I suggest you to create a server script, so you can reuse it in other projects or other platforms.

like image 95
Nicola Giancecchi Avatar answered Oct 02 '22 17:10

Nicola Giancecchi


I was going for the same target and I did it on the client side

I used these pods

pod 'HTMLReader'
pod 'AFNetworking'

Then I inherited from AFHTTPResponseSerializer and returned an object that contains link details

#import <UIKit/UIKit.h>

@interface LinkDetails : NSObject

@property (nonatomic,strong) NSString *linkURL;

@property (nonatomic,strong) NSString *linkHOST;

@property (nonatomic,strong) NSString *linkTitle;

@property (nonatomic,strong) NSString *linkDescription;

@property (nonatomic,strong) NSString *linkWebSiteName;

@property (nonatomic,strong) NSString *linkImageUrl;

@property (nonatomic,strong) UIImage *linkImage;

@end

This is the header for my responseSerializer

#import <AFNetworking/AFNetworking.h>

@interface HTMLResponseSerializer : AFHTTPResponseSerializer

@end

and this is the implementation for my responseSerializer

#import "HTMLResponseSerializer.h"
#import <HTMLReader/HTMLReader.h>
#import "LinkDetails.h"

@implementation HTMLResponseSerializer

-(id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing  _Nullable *)error{

    NSString *responseStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    LinkDetails *details = [[LinkDetails alloc] init];

    HTMLDocument *document = [HTMLDocument documentWithString:responseStr];

    NSArray *metaTags = [document nodesMatchingSelector:@"meta"];

    for (HTMLElement *metaTag in metaTags) {

        if ([[[metaTag attributes] objectForKey:@"property"] isEqualToString:@"og:url"] || [[[metaTag attributes] objectForKey:@"property"] isEqualToString:@"twitter:url"]) {
            NSLog(@"%@",[[metaTag attributes] objectForKey:@"content"]);
            details.linkURL = [[metaTag attributes] objectForKey:@"content"];
        }

        if ([[[metaTag attributes] objectForKey:@"property"] isEqualToString:@"og:title"]  || [[[metaTag attributes] objectForKey:@"property"] isEqualToString:@"twitter:title"]) {
            NSLog(@"%@",[[metaTag attributes] objectForKey:@"content"]);
            details.linkTitle = [[metaTag attributes] objectForKey:@"content"];
        }

        if ([[[metaTag attributes] objectForKey:@"property"] isEqualToString:@"og:description"] || [[[metaTag attributes] objectForKey:@"property"] isEqualToString:@"twitter:description"]) {
            NSLog(@"%@",[[metaTag attributes] objectForKey:@"content"]);
            details.linkDescription = [[metaTag attributes] objectForKey:@"content"];
        }

        if ([[[metaTag attributes] objectForKey:@"property"] isEqualToString:@"og:image"] || [[[metaTag attributes] objectForKey:@"property"] isEqualToString:@"twitter:image"]) {
            NSLog(@"%@",[[metaTag attributes] objectForKey:@"content"]);
            details.linkImageUrl = [[metaTag attributes] objectForKey:@"content"];
        }

        if ([[[metaTag attributes] objectForKey:@"property"] isEqualToString:@"og:site_name"] || [[[metaTag attributes] objectForKey:@"property"] isEqualToString:@"twitter:site_name"]) {
            NSLog(@"%@",[[metaTag attributes] objectForKey:@"content"]);
            details.linkWebSiteName = [[metaTag attributes] objectForKey:@"content"];
        }
    }

    if(!details.linkTitle){
        details.linkTitle = [document firstNodeMatchingSelector:@"title"].textContent;
    }

    if(!details.linkDescription){
        details.linkTitle = [document firstNodeMatchingSelector:@"description"].textContent;
    }

    if (!details.linkHOST) {
        details.linkHOST = [response.URL host];
    }

    if (!details.linkURL) {
        details.linkURL = [response.URL absoluteString];
    }

    return details;
}

@end

Don't forget to assign responseSerlializer to your custom one

This worked for me very well

like image 24
Mohamed Elkassas Avatar answered Oct 02 '22 18:10

Mohamed Elkassas