I\'m trying to embed a link preview in an iOS application in the same way that Facebook does:
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
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.