Categories: iOSSwiftTutorials

Using FlickrKit in iOS

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.

pod 'FlickrKit'

Now in your AppDelegate. import FlickrKit and initialize your Flickr app with the following code in didFinishLaunchingWithOptions:

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.

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.

 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.

//
//  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.

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.

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. 🙂

Aaqib Hussain

Aaqib is an enthusiastic programmer with the love of Swift and anything that looks like Swift i.e Kotlin. He loves writing code in Swift, and exploring new technology and platforms. He likes to listen to old music. When he is not writing code, he's probably spend his time watching movies, tv-shows or anime, or either doing some research for writing the next article. He started Kode Snippets in 2015.

Recent Posts

Things to know when moving to Germany

This article covers some important things you must know when you are considering a move…

3 years ago

Unit Testing in Android for Dummies

What is Unit Testing? In its simplest term, unit testing is testing a small piece…

4 years ago

Factory Design Pattern

In this article, you will learn about a type of Creational Design Pattern which is…

5 years ago

Creating Target specific Theme in iOS

In this tutorial, you will go through the use of targets to achieve two separate…

5 years ago

Facade Design Pattern

In this article, you will learn about a type of Structural Design Pattern which is…

5 years ago

Singleton Design Pattern

In this article you will learn about a type of Creational Design Pattern which is…

5 years ago