Error retrieving profile picture from facebook swift FBSDK - swift

This is the code I use to retrieve picture in my code.
I call this function immediately after I send the graphRequest.
let upLoadData = try Data(contentsOf: URL(fileURLWithPath:
"https:/graph.facebook.com/(fbUID)/picture?type=large")) let
upLoadImage = UIImage(data: upLoadData)?.jpeg(.low)
However, this is the error I get
Error Domain=NSCocoaErrorDomain Code=260 "The file “picture?type=large” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/https:/graph.facebook.com/(my facebook user id)/picture?type=large, NSUnderlyingError=0x604001451df0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
I checked to see if I can access this url and when I type in the url I successfully download the image.
Is there any step that I am missing?

The result was due to the fact that I used URL(fileURLWithPath: , not URL(string:

Related

Catch Error Reading File From Disk - You Don't Have Permissions

I am using the following code in the AppDel. This is triggered when a user taps on a gpx file or uses the share option to share the file with my app. At this point it is the user that specified that they are allowing my app to access the file so I'm a little confused a to why this is still being denied. Any advice much appreciated.
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(url.lastPathComponent)
if FileManager.default.fileExists(atPath: fileURL.path) {
print("File already exists")
}
else {
do {
try FileManager.default.copyItem(at: url, to: fileURL)
print("Did write file to disk")
}
catch {
DispatchQueue.main.async(){
print("Catch error writing file to disk: \(error)")
}
}
}
}
return true
}
The error prints to the console as follows:
Error Domain=NSCocoaErrorDomain Code=257 "The file
“Beech_Hill_Long_Route.gpx” couldn’t be opened because you don’t have
permission to view it."
UserInfo={NSFilePath=/private/var/mobile/Library/Mobile
Documents/com~apple~CloudDocs/Desktop/Beech_Hill_Long_Route.gpx,
NSUnderlyingError=0x282c19a70 {Error Domain=NSPOSIXErrorDomain Code=1
"Operation not permitted"}}
I'm less knowledgeable about exactly how this works on iOS, but I do have some knowledge about how it works for macOS, and the two should be similar. For macOS sandboxed apps the user has to select the file outside of the sandbox specifically via NSOpenPanel or NSSavePanel. The equivalent on iOS would be UIDocumentPickerViewController, but I assume an explicit share would work too. Based on that, here's how I would think about it and what I would try, if I were faced with your problem:
You've got two URLs involved in your call to FileManager.default.copy(). It's not clear which one is producing the error, so I'll consider both.
First let's look at fileURL. You're constructing it to put a file in the user's Documents directory. On macOS at least, that directory is not in the app's sandbox, which means asking the user via NSSavePanel (which also means they might decide to put it somewhere else). You might have to do the UIKit equivalent, or just make sure you're picking a location that is in your sandbox.
To test that, instead of doing the copy, try writing to fileURL to isolate just that one. For example:
do { try "TestString".data(using: .utf8)?.write(url: fileURL) }
catch { print("Write failed: \(error.localizedDescription)") }
If that fails, then your problem is with fileURL, in which case you may need to use UIDocumentPickerViewController to save it, or pick a location that's definitely in the app's sandbox.
If the test succeeds, the problem must be with the incoming URL.
I'm going to assume that url is already security scoped, because I'm not sure how sharing would even work otherwise. What I think is most likely happening behind the scenes is that when the user shares a URL with your app, iOS creates a security-scoped bookmark from the URL and sends the bookmark rather than the URL to your app. Then on your app's end, that bookmark is used to reconstitute the URL before passing it on to your app's delegate. If I'm right about that you'll need to open and close a security scope to use it:
url.startAccessingSecurityScopedResource()
// access your file here
url.stopAccessingSecurityScopedResource()
Note that stopAccessingSecurityScopeResource() has to be called on the main thread, so if you're code is happening asynchronously you'll need to schedule it to run there:
url.startAccessingSecurityScopedResource()
// access your file here
DispatchQueue.main.async { url.stopAccessingSecurityScopedResource() }
If you need to save the URL itself to use in a future run of your program... you can't. Well, you can, but it won't be valid, so you'll be right back to permissions errors. Instead you have to save a bookmark, and then in that future run, reconstruct the URL from the bookmark.
let bookmark = try url.bookmarkData(
options: .withSecurityScope,
includingResourceValuesForKeys: nil,
relativeTo: nil
)
bookmark is an instance of Data, so you can write that to UserDefaults or wherever you might want to save it. To get a URL back from it later:
var isStale = false
let url = try URL(
resolvingBookmarkData: bookmark,
options: .withSecurityScope,
relativeTo: nil,
bookmarkDataIsStale: &isStale
)
if isStale
{
let newBookmark = try url.bookmarkData(
options: .withSecurityScope,
includingResourceValuesForKeys: nil,
relativeTo: nil
)
// Save the new bookmark
}
Note that if isStale is true after the initializer returns, then you need to remake and resave the bookmark.
It's a shame that we have to go through this much trouble, but we live in a world where some people insist on doing bad things to other people's devices and data, so it's what we have to deal with the protect users from malicious data breaches.

Cannot open PDF using xcode for my iphone app

I have an iPhone app and I implemented a UIDocumentPickerViewController. Once the user chooses a PDF I receive the URL of the PDF.
I'm trying to get the Data for that PDF so I could send it to my server, but I get the following response:
Error Domain=NSCocoaErrorDomain Code=257 "The file “aaa.pdf” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/9C57E7F1-0997-4F57-A3EF-A7EFC3EF6158/File Provider Storage/aaa.pdf, NSUnderlyingError=0x282b43600 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
This is how I try to convert it to Data:
var documentData = Data()
do {
documentData.append(try Data(contentsOf: documentURL))
} catch {
throw Error.Creation
}
I've read somewhere that sandboxed apps cannot read files, but when I'm looking into the target capabilities, I don't even see the Sandbox capability.
Any ideas why that happens?
Thanks
Updated to Swift 5 - Xcode 12:
In order to have read permission to the file you imported, add asCopy: true to the document picker:
let doc = UIDocumentPickerViewController(forOpeningContentTypes: types, asCopy: true)
Ok, the issue was I was using ".open" when creating the document picker instead of ".import". That did the trick.

Passwordless Email Auth Firebase, Dynamic Links (FDL)

I'm trying to setup password-less email authentication through firebase for my iOS app. I'm using the method send signInLink which require actionCodeSettings and in turn a url. I've discovered that this url has to be a dynamic link created on Firebase. I've gone to the firebase console and white-listed a domain, but when I try to create the dynamic link on the console, I get "An error occurred when creating new dynamic link".
I'm a little confused as to how I'm supposed to construct this dynamic link especially the deep link. I've been through Firebase's documentation, added a dummy App Store ID and App prefix (as I was told by Firebase support), but I can't seem to get a proper diagnosis behind this
If I try sending the sign-in email there is no issue, but when I click on the link I get a 400 error saying "The requested URL was not found on this server".
Can anyone help me out with this?
actionCodeSettings.handleCodeInApp = true
actionCodeSettings.url = URL(string: String(format: "my_dynamic_link", email.text!))
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
actionCodeSettings.setAndroidPackageName("", installIfNotAvailable: false, minimumVersion: "12")
Auth.auth().sendSignInLink(toEmail: email.text!, actionCodeSettings: actionCodeSettings, completion: { error in
if error != nil {
print("Link Error: " + (error?.localizedDescription)!)
let castedError = error as NSError?
let FBError = AuthErrorCode(rawValue: (castedError?.code)!)
switch FBError {
case .invalidEmail?:
print("invalid email")
case .emailAlreadyInUse?:
print("in use")
default:
print("Create User Error: \(error!)")
}
}
else {
print ("No Error")
}
})
You could try following the troubleshooting steps mentioned in the Firecasts video "Getting started with Firebase Dynamic Links on iOS - Pt.1 (Firecasts)" at 7:54 (https://youtu.be/KLBjAg6HvG0?t=474).
I was having the same issue and everything worked fine after:
deleting the app
restarting my phone
reinstalling the app
Currently the bug radar (http://www.openradar.me/radar?id=4999496467480576) is still open.

HTTP Get API call always fails "NSLocalizedDescription=A server with the specified hostname could not be found"

I've created an ASP.NET Core web api which I am running locally in visual studio, I am able to browse to this in Safari and tested the API using postman.
When I use the following swift code in my MacOS app:
let url = URL(string: "http://localhost:5000/api/values")
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
guard error == nil else {
print(error!)
return
}
guard let data = data else {
print("Data is empty")
return
}
let json = try! JSONSerialization.jsonObject(with: data, options: [])
print(json)
}
task.resume()
It always fails with error
NSLocalizedDescription=A server with the specified hostname could not
be found.
Do I have to change some settings so that my app can make Http requests to the API?
Thanks
You probably already figured out a solution or a way around the problem, but since I reached the same question when having this problem I will provide my answer anyway in case anyone else finds this question.
For me the problem was that the MacOS app was not allowed to connect to the internet since it was automatically running in an app sandbox. The solution was to add "Outgoing Connections" to the app capabilities. See screenshot below.

Get a PHAsset from ReferenceURL: fetchAssets(withALAssetURLs:options:) DEPRECATED

My goal is to upload original resolution device captured video files to S3 using AWSS3TransferUtility.
User selects a video using UIImagePickerController however, if I pass info[UIImagePickerControllerMEDIAURL] to the transferUtility it always reduces the video to 720p. If I pass the transferutility info[UIImagePickerControllerREFERENCEURL] I get an Error:
The operation couldn’t be completed.
(com.amazonaws.AWSS3TransferUtilityErrorDomain error 4.)
Cannot find an explanation of the error code so I am assuming it is a permissions error because I am not accessing the asset via the Photos framework or PHAsset.fetch
REFERNCE URL -
assets-library://asset/asset.mov?id=5B99DC8E-B94E-4CBF-AFB8-7F82BC72FEE2&ext=mov
MEDIA URL -
file:///private/var/mobile/Containers/Data/Application/76928AD7-F142-4CC9-9708-A58C8CAF8EE5/tmp/trim.82038B6A-222F-4B50-A937-A8C399B02A08.MOV
Now, I have the ReferenceURL, and am trying to get the PHAsset so that I can copy it the Documents Directory and pass the URL of it to TransferUtility from there to get around the AWSS3TransferUtilityErrorDomain error 4.
However, fetchAssets(withALAssetURLs:options:) is now deprecated so I cannot fetch the asset with the ReferenceURL; all the other methods are batch fetching via media type, etc. There is fetchAssets(withLocalIdentifiers:options:) but I am not sure how to get the local identifier of a PHAsset just from the URL.
If you need PHAsset of selected item, you can get it directly from info in UIImagePickerController callback
let asset = info[.phAsset] as? PHAsset
if it is not there, then you did not request authorization before using picker, so do this
let status = PHPhotoLibrary.authorizationStatus()
if status == .notDetermined {
PHPhotoLibrary.requestAuthorization({status in
})
}
Note: localIdentifier is a property of PHObject, and PHAsset is a subclass of PHObject.