how to import FaceBook profile pictures from album using Swift - facebook-graph-api

I am fetching the facebook profile picture like this
let params = ["height": 300, "width": 300, "redirect": false] as [String : Any]
let graphRequest = FBSDKGraphRequest(graphPath: "me/picture", parameters: params, httpMethod: "GET")
let connection = FBSDKGraphRequestConnection()
connection.add(graphRequest, completionHandler: { (connection, result, error) in
if error == nil {
print("profile pic ************\(result)")
}
})
connection.start()
Now I need to access the profile pictures from the ablum and set those in my collectionView . I tried to set the graphPath: "me/album/profile_picture" but no luck . Could anybody give me some hints please ?

You need to find the id of the "Profile Pictures" album and request the photos for that id.
Facebook.albums(user: "me").request({ albums in
albums.first(where: { ($0["name"] as? String) == "Profile Pictures" }).flatMap({
Facebook.photos(album: $0["id"] as! String).request({ photos in
print(photos)
})
})
})
I have made an enum below to make requesting graph api paths easier.
enum Facebook: Graphable {
case albums(user: String)
case photos(album: String)
var path: String {
switch self {
case let .albums(uid):
return "\(uid)/albums"
case let .photos(aid):
return "\(aid)/photos"
}
}
var method: String {
switch self {
case .albums, .photos:
return "GET"
}
}
var params: [String : Any] {
switch self {
case .albums:
return [:]
case .photos:
return [
"height": 300,
"width": 300,
"redirect": false
]
}
}
}
Here is the protocol and extension the enum must conform to.
protocol Graphable {
var path: String { get }
var method: String { get}
var params: [String : Any] { get }
}
extension Graphable {
typealias JSON = [String:Any]
func request(_ handler: #escaping ([JSON]!) -> (), failure: #escaping (Error) -> () = { print($0) }) {
let connection = FBSDKGraphRequestConnection()
let request = FBSDKGraphRequest(
graphPath: path,
parameters: params,
httpMethod: method
)
connection.add(request) {
_ = $0.1.map ({ handler(($0 as? JSON)?["data"] as? [JSON]) }) ??
$0.2.map ({ failure($0) })
}
connection.start()
}
}

I got my answer like this :
import FBSDKCoreKit
import SwiftyJSON
func getFBAlbumID() {
let graphRequest = FBSDKGraphRequest(graphPath: "me/albums", parameters: nil, httpMethod: "GET")
let connection = FBSDKGraphRequestConnection()
connection.add(graphRequest, completionHandler: { (connection, result, error) in
if error == nil
let dictionary = JSON(result)
// print("albums ID are **************\(dictionary)")
if let data = dictionary["data"].array {
print("data of profilePicture ******* \(data)")
if let dict = data.first(where: { ($0["name"].string ) == "Profile Pictures" }) {
let id = dict["id"].string
print("my desired id : ********* \(id)")
self.getFBAlbumPhoto(albumID: id!)
}
}
}
})
connection.start()
}
func getFBAlbumPhoto(albumID: String) {
let params = [ "height": 300, "width": 300, "redirect": false] as [String : Any]
let graphRequest = FBSDKGraphRequest(graphPath: "\(albumID)/photos?fields=source", parameters: params, httpMethod: "GET")
let connection = FBSDKGraphRequestConnection()
connection.add(graphRequest, completionHandler: { (connection, result, error) in
if error == nil {
//print(result)
let dictionary = JSON(result)
print("result are **************\(dictionary)")
}
})
connection.start()
}
Here I am grabbing the ID of the particular album I desire and then make another call to get the photos of that album. Here I am calling a function from inside another function. If someone can help me to write the code in more Swift way that would be helpful, like using closure. Thanks.

Related

How Can I Solve 'Notifications not accepted. You can turn them on later under your iOS settings' Issue?

I'm using onesignal for push notifications and it was working well until the ios 14 upgrade. When I build the same app without any changes on Xcode 12, I got this warning in the console.
Notifications not accepted. You can turn them on later under your iOS
settings
There was no problem on iOS 13, it happened when I update to iOS 14.
AppDelegate.swift
import UIKit
import CoreData
import Firebase
import GoogleMobileAds
import OneSignal
import UserNotifications
import SDWebImageWebPCoder
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, OSPermissionObserver, OSSubscriptionObserver {
var window: UIWindow?
var shortcutItemToProcess: UIApplicationShortcutItem?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
GADMobileAds.sharedInstance().start(completionHandler: nil)
let onesignalInitSettings = [kOSSettingsKeyAutoPrompt: false, kOSSettingsKeyInAppLaunchURL: false]
OneSignal.initWithLaunchOptions(launchOptions,
appId: "my key is here",
handleNotificationAction: nil,
settings: onesignalInitSettings)
OneSignal.inFocusDisplayType = OSNotificationDisplayType.notification
OneSignal.promptForPushNotifications(userResponse: { accepted in
print("User accepted notifications: \(accepted)")
})
// Add your AppDelegate as an obsserver
OneSignal.add(self as OSPermissionObserver)
OneSignal.add(self as OSSubscriptionObserver)
registerForPushNotifications()
let WebPCoder = SDImageWebPCoder.shared
SDImageCodersManager.shared.addCoder(WebPCoder)
return true
}
func registerForPushNotifications() {
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.delegate = self
let readAction = UNNotificationAction(identifier: "oku", title: "Haberi Oku", options: [.foreground])
let closeAction = UNNotificationAction(identifier: "kapat", title: "Kapat", options: [])
let category = UNNotificationCategory(identifier: "etkilesim", actions: [readAction, closeAction], intentIdentifiers: [], options: [])
notificationCenter.setNotificationCategories([category])
}
func onOSPermissionChanged(_ stateChanges: OSPermissionStateChanges!) {
if stateChanges.from.status == OSNotificationPermission.notDetermined {
if stateChanges.to.status == OSNotificationPermission.authorized {
print("Thanks for accepting notifications!")
} else if stateChanges.to.status == OSNotificationPermission.denied {
print("Notifications not accepted. You can turn them on later under your iOS settings.")
}
}
}
func onOSSubscriptionChanged(_ stateChanges: OSSubscriptionStateChanges!) {
if !stateChanges.from.subscribed && stateChanges.to.subscribed {
print("Subscribed for OneSignal push notifications!")
}
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
// Grab a reference to the shortcutItem to use in the scene
if let shortcutItem = options.shortcutItem {
shortcutItemToProcess = shortcutItem
}
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
var postId:String = ""
var postType:String = ""
if let custom = response.notification.request.content.userInfo["custom"] as? NSDictionary{
if let a = custom["a"] as? NSDictionary{
if let id = a["id"] as? String{
postId = id
}
if let type = a["rights"] as? String{
postType = type
}
}
}
if response.actionIdentifier == "oku" {
if postId != ""{
DispatchQueue.main.async(execute: {
NotificationCenter.default.post(name: NSNotification.Name("Detail"), object: nil, userInfo: ["id": postId, "type": postType])
})
completionHandler()
}
}else if response.actionIdentifier == "kapat" {
print("KAPAT")
completionHandler()
} else {
if postId != ""{
DispatchQueue.main.async(execute: {
NotificationCenter.default.post(name: NSNotification.Name("Detail"), object: nil, userInfo: ["id": postId, "type": postType])
})
completionHandler()
}
}
}
}
I solved it! :) If your app name contains non-English characters, change your Product Name under Build Settings and build it again, that's it :)
Settings
Then you can change 'Bundle display name' in info.plist.

Alamofire post request return 404 in Swift

I am going to post a request via alamofire. I can post request with Postman. Response return true (201 code). However when I am try with Alamofire returns 404 code. What's wrong?
My codes:
let headers: HTTPHeaders = [
"Authorization": "Basic xxxxxxxxxxxx",
"content-type": "application/json"
]
let parameters:[String:Any] = [
"xxx":123,
"yyy":"test",
"zzz":"iphone"
]
Alamofire.request(myUrl, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON { response -> Void in
switch response.result {
case .success:
print(response.response?.statusCode)
break
case .failure(let error):
print(error)
}
}
Return this message :
success {
message = "No HTTP resource was found that matches the request URI 'https://xxxxx/PostErrorFeedBack'.";
}
Try this one hope it may help you !!
let headers = [
"Authorization": "Basic xxxxxxxxxxxx"
]
let parameters = [
]
Alamofire.request(.POST, "url", parameters: parameters, headers: headers, encoding: .JSON)
.validate(contentType: ["application/json"])
.responseJSON { response in
if response.response?.statusCode == 200 {
print("Success with JSON: \(response.result.value)")
}
else {
let error = response.result.value as! NSDictionary
let errorMessage = error.objectForKey("message") as! String
print(errorMessage)
failure(errorMessage)
}
}
you can try this method for using Alamofire as this worked for me.
let headers = [
"Accept": "application/json",
"Authorization" : "Authorization: Bearer ", //if any
"Cookie" : "Cookie" //if any
]
let parameterDict: NSDictionary = NSDictionary.init(objects: [nameTextField.text!, reportTextView.text!], forKeys: ["Name" as NSCopying,"Message" as NSCopying])
Alamofire.request("API",method: .post, parameters: parameterDict as? [String : AnyObject] , encoding:JSONEncoding.default, headers:headers) .responseJSON { response in switch response.result {
case .success(let JSON):
print("Success with JSON: \(JSON)")
let response = JSON as! NSDictionary
case .failure(let error):
print("Request failed with error: \(error)")
}
}

RxAlamofire post multipart data

How to send Multipart data with RxAlamofire
For instance in Alamofire
let URL = try! URLRequest(url: "http://example.com", method: .post)
Alamofire.upload(multipartFormData: { formData in
// multiaprt
}, with: URL, encodingCompletion: {(result: SessionManager.MultipartFormDataEncodingResult) in
})
How to get same behaviour/function with RxAlamofire?
Or An way of wrapping this function in an Observable?
You can easily wrap that function like this:
func wrapper() -> Observable<SomeResponseType> {
return Observable.create { observer in
let URL = try! URLRequest(url: "http://example.com", method: .post)
Alamofire.upload(
multipartFormData: { formData in
// multiaprt
},
with: URL,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
// convert response in something of SomeResponseType
// ...
observer.onNext(response)
observer.onCompleted()
}
case .failure(let encodingError):
observer.onError(encodingError)
}
})
return Disposables.create()
}
}

Alamofire 4.0, Swift 3 Post params not being passed

When I upgraded to latest everything (Alamo 4, Swift 3 and XC 8) the following stopped posting parameters and I dont have a clue why...
let params = ["stripeToken": token.tokenId,
"name": name,
"email": email
]
Alamofire.request(requestString, method: .post, parameters: params, encoding: JSONEncoding.default)
.responseJSON { (response) in
if response.result.value is NSNull {
return
}
I had a similar issue, I changed encoding from JSONEncoding.default to URLEncoding.httpbody or encoding: URLEncoding.default
Alamofire.request(URL, method: .post, parameters: params, encoding: URLEncoding.httpBody).responseJSON { response in
if let data = response.data {
let json = String(data: data, encoding: String.Encoding.utf8)
print("Response: \(json)")
}
}
I have the same issue and finally fixed it. URLEncoding.httpBody didn't work for me... but URLEncoding.default did.
So I changed JSONEncoding.default to URLEncoding.default.
It's now passing the parameters to the backend.
Alamofire.request(loginURL, method: .post, parameters: params, encoding: URLEncoding.default, headers: nil)
Everything works exactly as it should. Here's a quick example demonstrating that fact.
func testPostingJSON() {
let urlString = "https://httpbin.org/post"
let params: Parameters = [
"stripeToken": "token_id",
"name": "cnoon",
"email": "cnoon#alamofire.org"
]
let expectation = self.expectation(description: "should work")
Alamofire.request(urlString, method: .post, parameters: params, encoding: JSONEncoding.default)
.responseJSON { response in
if let json = response.result.value {
print("JSON: \(json)")
} else {
print("Did not receive json")
}
expectation.fulfill()
}
waitForExpectations(timeout: 5.0, handler: nil)
}
Hopefully that example helps you pinpoint the issue. Cheers. 🍻

Cannot send aps to iOS using aws-sdk-js

I am trying to use aws-sdk-js to send push notification to iOS and Android device. It can send the notification message, but it is not the one I wanted. If i put badge and sound in the aps dictionary, the app should have a badge and play a sound. But it did not.
Xcode console output:
[aps: {
alert = "Test Message";
}]
javascript code:
var AWS = require('aws-sdk');
AWS.config.update({accessKeyId: '<key>', secretAccessKey: '<secrect>'});
AWS.config.update({region: 'ap-southeast-2'});
var sns = new AWS.SNS();
var payload = {
default: 'Test Message',
APNS: {
aps: {
alert: 'Test Message on iPhone',
badge: 1,
sound: "default"
},
}
};
payload.APNS = JSON.stringify(payload.APNS);
payload = JSON.stringify(payload);
var params = {
MessageStructure: 'json',
Message: payload,
Subject: 'Test push',
TargetArn: '<arn of the endpoint>'
};
sns.publish(params, function(err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
});
code in application:didfinishlaunch,
let acceptAction = UIMutableUserNotificationAction()
acceptAction.identifier = "ACCEPT_IDENTIFIER"
acceptAction.title = NSLocalizedString("Accept", comment: "Accept")
acceptAction.activationMode = .Foreground
acceptAction.destructive = false
acceptAction.authenticationRequired = false
let deleteAction = UIMutableUserNotificationAction()
deleteAction.identifier = "DELETE_IDENTIFIER"
deleteAction.title = NSLocalizedString("Delete", comment: "Delete")
deleteAction.activationMode = .Foreground
deleteAction.destructive = true
deleteAction.authenticationRequired = false
let ignoreAction = UIMutableUserNotificationAction()
ignoreAction.identifier = "IGNORE_IDENTIFIER"
ignoreAction.title = NSLocalizedString("Ignore", comment: "Ignore")
deleteAction.activationMode = .Foreground
deleteAction.destructive = false
deleteAction.authenticationRequired = false
let messageCategory = UIMutableUserNotificationCategory()
messageCategory.identifier = "MESSAGE_CATEGORY"
messageCategory.setActions([acceptAction, deleteAction], forContext: .Minimal)
messageCategory.setActions([acceptAction, deleteAction, ignoreAction], forContext: .Default)
let notificationSettings = UIUserNotificationSettings(forTypes: [.Badge, .Sound, .Alert], categories: (NSSet(array: [messageCategory])) as? Set<UIUserNotificationCategory>)
UIApplication.sharedApplication().registerForRemoteNotifications()
UIApplication.sharedApplication().registerUserNotificationSettings(notificationSettings)
and implement the protocol:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
print(userInfo)
}
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
print(identifier)
completionHandler()
}
If you are using a developer profile for apns you should write APNS_SANDBOX instead of APNS
var payload = {
default: 'Test Message',
APNS_SANDBOX: {
aps: {
alert: 'Test Message on iPhone',
badge: 1,
sound: "default"
},
}
};