Hello Everyone.
I finally got the time to write after a few months of being really busy. I hope everyone would be doing good.
So I was working on this FlickrKit a while back and at that time I decided to write about it, on how to use it with Swift.
Setting Up App on Flickr.com
In order to be able to use Flickr API you would need to get API credentials from their website. Open the link. Click on Request an API key.
It will take you to the following screen. Click on Request API key again.
Then we will have to specify Flickr if the app is for commercial use or for personal. Since its a demonstration I will select Apply for Non-Commercial Key.
Tell Flickr about the app, then Submit.
After that your keys will be generated, and you’ll be redirected to the following screen, then click on Edit auth flow for this app.
FlickrKit is a 3rd party library which uses Callback Url for authentication of user and providing token. So for that reason we will have to specify a Callback url and set Application type to Web Application. Callback url can be xyz://auth. then click save changes. After that you’re done setting up.
Setting up Flickr Kit in Project
Create a project and initiate a pod in it, and install. Since FlickrKit is written in Objective-C. You’ll have to import it in your bridging-header as well.
1 |
pod 'FlickrKit' |
Now in your AppDelegate. import FlickrKit and initialize your Flickr app with the following code in didFinishLaunchingWithOptions:
1 |
FlickrKit.shared().initialize(withAPIKey: 'API-Key', sharedSecret: 'Secret-Key') |
After that open your Info.plist file and add the following keys.
Open your Storyboard and add a View Controller and in your View Controller add a WebView and make the delegate self to the View Controller and create and outlet, conform to protocol UIWebViewDelegate.
We’ll write a method which will open Flickr inside of our webview. Call this method in viewDidLoad or viewWillAppear.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
private func auth(){ let callbackURLString = "flickrPhotoViewer://auth" let url = URL(string: callbackURLString) FlickrKit.shared().beginAuth(withCallbackURL: url!, permission: FKPermission.delete, completion: { (url, error) -> Void in DispatchQueue.main.async(execute: { () -> Void in if ((error == nil)) { let urlRequest = NSMutableURLRequest(url: url!, cachePolicy: NSURLRequest.CachePolicy.useProtocolCachePolicy, timeoutInterval: 30) self.webView.loadRequest(urlRequest as URLRequest) } else { guard let message = error?.localizedDescription else{ return } Util.showAlert(sender: self, title: "Error", message: message) } }); }) } |
And in your UIWebViewDelegate method shouldStartLoadWith do the following. Don’t forget to change the string ‘flickrphotoviewer’ to the prefix of your callback url.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool { let url = request.url let scheme = url?.scheme //If URL scheme matches then try to do the Auth process if "flickrphotoviewer" == scheme{ if let token = url{ User.shared().saveAccessToken(url: token) self.flickrHelper = FlickrHelper() self.flickrHelper?.checkAuthentication(callBackURL: token, sender: self, { () -> Void? in _ = self.navigationController?.popToRootViewController(animated: true) }) } }//else navigate to login else if url?.absoluteString == "https://m.flickr.com/#/home" { DispatchQueue.main.asyncAfter(deadline: .now() + 0.3 , execute: { _ = self.navigationController?.popToRootViewController(animated: true) }) } return true } |
What this does is get User’s token if user allows the permission and returns to main screen otherwise. Once you get the token, save it in UserDefaults.
I have created a class called FlickrHelper, with the reusable helper functions in it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
// // FlickrHelper.swift // Flickr PhotoViewer // // Created by Aaqib Hussain on 2/4/17. // Copyright © 2017 Aaqib Hussain. All rights reserved. // import UIKit import FlickrKit class FlickrHelper { var completeAuthOp: FKDUNetworkOperation! var checkAuthOp: FKDUNetworkOperation! //For Authenticating User func checkAuthentication(callBackURL: URL, sender: UIViewController, _ completionHandler : (()->Void?)?) { self.completeAuthOp = FlickrKit.shared().completeAuth(with: callBackURL, completion: { (userName, userId, fullName, error) -> Void in DispatchQueue.main.async(execute: { () -> Void in if ((error == nil)) { User.shared().getProfileInfo(userName: userName, fullName: fullName, userId: userId) } else { guard let message = error?.localizedDescription else{ return } Util.showAlert(sender: sender, title: "Sorry", message: message) } completionHandler?() }); }) } //Called once the User is logged in after Authentication func login(sender: UIViewController, _ completionHandler : @escaping ((_ error: NSError?)->Void)){ self.checkAuthOp = FlickrKit.shared().checkAuthorization { (userName, userId, fullName, error) -> Void in DispatchQueue.main.async(execute: { () -> Void in if ((error == nil)) { User.shared().getProfileInfo(userName: userName, fullName: fullName, userId: userId) completionHandler(nil) } else { guard let message = error?.localizedDescription else{ return } if message.contains("There isn\'t a stored token to check. Login first."){ User.userDefaults.removeObject(forKey: User.tokenKey) } Util.showAlert(sender: sender, title: "Error", message: message) completionHandler(error as? NSError) } }); } } } |
The function checkAuthentication takes in user token and provides their info in return. Where as the login function gets the user login if token is present.
We will have to save the userId because it will be required in order to get user’s pictures from their profile.
Getting Photos
From User Profile
In order to get photos from user’s picture. Copy and paste the following code in your View Controller where you want the pictures to be displayed. FlickrKit returns photo URLs.
We can use any 3rd party image library like SDWebImage or MapleBacon to download the images from.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
func getPhotos(completionHandler:@escaping (_ photoURLs: [URL?]?, _ error : NSError?)->Void){ var photoURLs = [URL?]() if FlickrKit.shared().isAuthorized { guard let userId = User.shared().userId else{ return } FlickrKit.shared().call("flickr.photos.search", args: ["user_id": userId] , maxCacheAge: FKDUMaxAge.neverCache, completion: { (response, error) -> Void in if error == nil{ DispatchQueue.main.async(execute: { () -> Void in if let response = response, let photoArray = FlickrKit.shared().photoArray(fromResponse: response) { for photoDictionary in photoArray { let photoURL = FlickrKit.shared().photoURL(for: FKPhotoSize.small320, fromPhotoDictionary: photoDictionary) photoURLs.append(photoURL) } completionHandler(photoURLs,nil) } }) } else{ completionHandler(nil,error as? NSError) } }) } else { } } |
From Photos Stream
This function is hardcoded to get only first 30 photo URLs. You can further change it and use pagination and get photos per page.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
func getExplore(completionHandler:@escaping (_ photoURLs: [URL?]?, _ error : NSError?)->Void){ var photoURLs = [URL?]() let flickrInteresting = FKFlickrInterestingnessGetList() flickrInteresting.per_page = "30" FlickrKit.shared().call(flickrInteresting) { (response, error) -> Void in DispatchQueue.main.async(execute: { () -> Void in if let response = response, let photoArray = FlickrKit.shared().photoArray(fromResponse: response) { for photoDictionary in photoArray { let photoURL = FlickrKit.shared().photoURL(for: FKPhotoSize.small320 , fromPhotoDictionary: photoDictionary) photoURLs.append(photoURL) } completionHandler(photoURLs,nil) } else { // Iterating over specific errors for each service if let error = error as? NSError { switch error.code { case FKFlickrInterestingnessGetListError.serviceCurrentlyUnavailable.rawValue: break; default: break; } completionHandler(nil,error) } } }) } } |
Build and runs your app and make sure everything is working.
I have created a sample project incase if you people find any difficulties. You can find the project here.
If you guys have any questions please leave a comment. 🙂