Error consuming REST API using swift on iOS - ios

I'm new on iOS development, I was following this tutorial: https://grokswift.com/simple-rest-with-swift/ and I don't know why the following code always return "the placeholder" and I can't see errors on the console's output:
import Foundation
class Resolver{
func doSomething() -> String{
var result = "the placeholder"
print("inside doSomething")
let postEndpoint: String = "http://jsonplaceholder.typicode.com/posts/1"
guard let url = NSURL(string: postEndpoint) else {
print("Error: cannot create URL")
return "error here"
}
let urlRequest = NSURLRequest(URL: url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
print("another thing")
let task = session.dataTaskWithRequest(urlRequest, completionHandler: {
(data, response, error) in
guard let responseData = data else {
print("Error: did not receive data")
return
//return "error here"
}
print("hereeeeeee ############")
guard error == nil else {
print("error calling GET on /posts/1")
print(error)
return
//return "error here"
}
// parse the result as JSON, since that's what the API provides
let post: NSDictionary
do {
post = try NSJSONSerialization.JSONObjectWithData(responseData,
options: []) as! NSDictionary
} catch {
print("error trying to convert data to JSON")
return
//return "error here"
}
// now we have the post, let's just print it to prove we can access it
print("The post is: " + post.description)
result = post.description
// the post object is a dictionary
// so we just access the title using the "title" key
// so check for a title and print it if we have one
if let postTitle = post["title"] as? String {
print("The title is: " + postTitle)
}
})
task.resume()
return result
}
}
this is my info.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string></string>
<key>CFBundleExecutable</key>
<string></string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>LSApplicationCategoryType</key>
<string></string>
<key>CFBundleName</key>
<string></string>
<key>CFBundleDisplayName</key>
<string></string>
<key>CFBundleVersion</key>
<string></string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>httpbin.org</key>
<dict>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
<key>jsonplaceholder.typicode.com </key>
<dict>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>CFBundleShortVersionString</key>
<string></string>
<key>CFBundleGetInfoString</key>
<string></string>
</dict>
</plist>
When I run the test I see this output:
Test Suite 'RestTest' started at 2016-03-03 15:38:49.364
Test Case '-[FoodTrackerTests.RestTest testResolver]' started.
inside doSomething
another thing
// I want to see the result: the placeholder
Test Case '-[FoodTrackerTests.RestTest testResolver]' passed (0.061 seconds).
Test Suite 'RestTest' passed at 2016-03-03 15:38:49.425.
Executed 1 test, with 0 failures (0 unexpected) in 0.061 (0.062) seconds
Test Suite 'Selected tests' passed at 2016-03-03 15:38:49.426.
Executed 1 test, with 0 failures (0 unexpected) in 0.061 (0.063) seconds
Why the result variable doesn't contains the post.description value?

As suggested in the comments, it looks like tests are completing before the HTTP call is returned (because the HTTP request is asynchronous) and thus you aren't seeing the results of the API call before the test run ends.
Have a look at XCAsyncTestCase and set up your tests to wait for the async callback instead.

The doSomething() method returns "the placeholder" value before the asynchronous call is finished. That's why you see it.

Related

azure ad login is not working in ios app while microsoft authenticator app is installed

I have built an ios app which is using azure ad login and it was working fine but after install microsoft authenticator app the azure ad login is not working anymore
in fact the alert which does say " app wants to use 'microsoftonline.com' to sign in"
not coming
and uninstalling the authenticator my ios app can login via azure ad again
let kClientID = [clientid]
let kGraphEndpoint = "https://graph.microsoft.com/"
let kAuthority = "https://login.microsoftonline.com/xxxxxxxxx"
let kRedirectUri = [URI]
let kScopes: [String] = ["user.read"]
func initMSAL() throws {
guard let authorityURL = URL(string: kAuthority) else {
print("Unable to create authority URL")
return
}
let authority = try MSALAADAuthority(url: authorityURL)
let msalConfiguration = MSALPublicClientApplicationConfig(clientId: kClientID,
redirectUri: kRedirectUri,
authority: authority)
self.applicationContext = try MSALPublicClientApplication(configuration: msalConfiguration)
self.initWebViewParams()
}
func initWebViewParams() {
self.webViewParamaters = MSALWebviewParameters(authPresentationViewController: self)
}
func acquireTokenInteractively() {
guard let applicationContext = self.applicationContext else { return }
guard let webViewParameters = self.webViewParamaters else { return }
let parameters = MSALInteractiveTokenParameters(scopes: kScopes, webviewParameters: webViewParameters)
parameters.promptType = .selectAccount
applicationContext.acquireToken(with: parameters) { (result, error) in
if let error = error {
print("Could not acquire token: \(error)")
return
}
guard let result = result else {
print("Could not acquire token: No result returned")
return
}
self.accessToken = result.accessToken
let aduser=MicrososftUser.init(id: result.uniqueId ?? "", mail: result.account.username ?? "", givenName: result.account.username ?? "", surname: "");
self.adLoginRequest(aduser: aduser)
//self.getContentWithToken()
}
}
info.plist
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>msauth.$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.674973595907-gsm9poebb8u1vvb28rvt7osv</string>
</array>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>msalv2</string>
<string>msaalv3</string>
<string>msauthv2</string>
<string>msauthv3</string>
</array>
<key>UIAppFonts</key>
<array>
<string>Inter.ttf</string>
<string>Inter-Black.ttf</string>
<string>Inter-ExtraLight.ttf</string>
<string>Inter-Regular.ttf</string>
<string>Inter-Bold.ttf</string>
<string>Inter-Light.ttf</string>
<string>Inter-SemiBold.ttf</string>
<string>Inter-ExtraBold.ttf</string>
<string>Inter-Medium.ttf</string>
<string>Inter-Thin.ttf</string>
</array>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
<string>remote-notification</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
</dict>
</plist>
when i click on azure ad login button the following error is showing in debug window
Could not acquire token: Error Domain=MSALErrorDomain Code=-50000 "(null)" UserInfo={MSALErrorDescriptionKey=Failed to delete broker key with error: -34018, MSALInternalErrorCodeKey=-42708, MSALCorrelationIDKey=4A0C2756-0173-7068-AC4F-AFEC1C84BCB3}
could any one help me with this issue
sorry for my bad english
solving the issue by disabling the access from my app to authenticator.
Adding the following line in initMSAL function
MSALGlobalConfig.brokerAvailability = .none
got help from following links:
https://github.com/AzureAD/microsoft-authentication-library-for-objc/issues/845
https://github.com/AzureAD/microsoft-authentication-library-for-objc/blob/dev/MSAL/src/public/configuration/MSALGlobalConfig.h#L74

SWIFT - Https call to private restfull api is failing

I need to convert my SWIFT code to fit HTTPS requests on private API.
I just need to understand how to make the request in Swift, at the moment changed the URL from http://...:_port/... to https://...:_port/... but I am getting those errors:
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9814)
nw_coretls_callback_handshake_message_block_invoke_3 tls_handshake_continue: [-9814]
nw_coretls_callback_handshake_message_block_invoke_3 tls_handshake_continue: [-9814]
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9814)
I also update my info.plist to this, but still getting errors
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>domain.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
</plist>
And this is the code
let task = session.dataTask(with: requestType as URLRequest) { (data, response, error) in
guard let _: Data = data, let _: URLResponse = response, error == nil else {
return
}
self.list = try! JSONDecoder().decode(_myObj.self, from:data!)
}
task.resume()

TIC SSL Trust Error while trying to read a txt file

I'm having this problem with reading from a txt file from a website without a certificate even though I have allowed it in Info.plist.
My Swift code looks like this:
let url = URL(string: "http://newskit.matsworld.io/domaci/text.txt")!
let task = URLSession.shared.downloadTask(with: url) { localURL, urlResponse, error in
if let localURL = localURL {
if let string = try? String(contentsOf: localURL) {
print(string)
}
}
}
task.resume()
And the Info.plist looks like this:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>http://newskit.matsworld.io</key>
<dict>
<key>ExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>IncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
I'm stuck with this and can't figure it out. Thanks for help!
The domain key is supposed to be just the domain without the scheme (http) and without subdomains if IncludesSubdomains is specified
<key>matsworld.io</key>

swift 3 awslambda invoker error [duplicate]

I am facing a strange issue with AWSS3.
Setup:
AWS Mobile HUB
Cognito
DynamoDB
S3
--> Cognito, Dynamo & even S3 (through cognito user data) work.
However I now tried to connect directly to AWS3 with the following code:"
let transferManager = AWSS3TransferManager.default()
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.bucket = "XXXXXXXXXXXX"
uploadRequest?.key = "user-data/" + awsId! + "/primary_profile_picture.png"
uploadRequest?.body = imgUrl as URL
transferManager.upload(uploadRequest!).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> Any? in
if let error = task.error as? NSError {
if error.domain == AWSS3TransferManagerErrorDomain, let code = AWSS3TransferManagerErrorType(rawValue: error.code) {
switch code {
case .cancelled, .paused:
break
default:
print("Error uploading: \(uploadRequest?.key) Error: \(error)")
}
} else {
print("Error uploading: \(uploadRequest?.key) Error: \(error)")
}
return nil
}
let uploadOutput = task.result
print("Upload complete for: \(uploadRequest?.key)")
return nil
})
and am getting the error:
AWSiOSSDK v2.5.1 [Debug] AWSInfo.m line:122 | -[AWSServiceInfo initWithInfoDictionary:checkRegion:] | Couldn't read the region configuration from Info.plist for the client. Please check your `Info.plist` if you are providing the SDK configuration values through `Info.plist`.
2017-02-20 19:29:21.748997 [2210:1152801] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The service configuration is `nil`. You need to configure `Info.plist` or set `defaultServiceConfiguration` before using this method.'
I am using the downloaded plist configuration from AWS Mobiel HUB and am therfore a bit surprised that it does not work (as all other components do).
Any ideas what the issue might be? The plist actually contains the bucket ID & region.
For me, I had to configure the credentials with the following code, before uploading:
let credentialsProvider = AWSCognitoCredentialsProvider(regionType:.USEast1,identityPoolId:PoolID)
let configuration = AWSServiceConfiguration(region:.USEast1, credentialsProvider:credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
Where PoolID is my Cognito identity. I hope this helps others.
Your info.plist needs to have S3TransferManager in it.
So, **AWS -> S3TransferManager -> Default -> Region -> ...**
You can find an example of one here
Swift 3 - Xcode 8.3.3
For people still having this issue, I just spent 3h fighting against this annoying setup issue.
I added both these chunks in my Info.plist (replace the variables between ** ** in the second bloc) and now it's working again.
Amazon's documentation isn't updated properly I think. I hope this can save some people some time.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>amazonaws.com</key>
<dict>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>amazonaws.com.cn</key>
<dict>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
and:
<key>AWS</key>
<dict>
<key>CredentialsProvider</key>
<dict>
<key>CognitoIdentity</key>
<dict>
<key>Default</key>
<dict>
<key>PoolId</key>
<string>**YourCognitoIdentityPoolId**</string>
<key>Region</key>
<string>**AWSRegionUnknown**</string>
</dict>
</dict>
</dict>
<key>S3TransferManager</key>
<dict>
<key>Default</key>
<dict>
<key>Region</key>
<string>**AWSRegionUnknown**</string>
</dict>
</dict>
</dict>
I had the same issue instead of S3TransferManager you should put DynamoDBObjectMapper
e.g..
<key>DynamoDBObjectMapper</key>
<dict>
<key>Default</key>
<dict>
<key>Region</key>
<string>us-east-1</string>
</dict>
</dict>
The problem was, region should be:
us-east-1
Instead of; US_EAST_1
Add Service configuration file with the data
If the above marked solution is not working for some cases. Try the below solution.
As the error says, the service configuration file is nil. So, we need to add the awsconfiguration.json file with the below data.
{
"Version": "1.0",
"IdentityManager": {
"Default": {}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "REPLACE_ME",
"Region": "REPLACE_ME"
}
}
},
"S3TransferUtility": {
"Default": {
"Bucket": "REPLACE_ME",
"Region": "REPLACE_ME"
}
}
}
Replace the bucket, region, poolId of your project.

NSURLSession - DownloadTask doesn't work with some URL [duplicate]

This question already has answers here:
NSURLSession/NSURLConnection HTTP load failed on iOS 9
(13 answers)
Closed 6 years ago.
Here the code:
let url = NSURL(string: "http://a337.phobos.apple.com/us/r30/Music/d5/a8/6b/mzi.msfqeogi.aac.p.m4a")
let downloadTask = self.downloadSession.downloadTaskWithURL(url!)
downloadTask.resume()
-> OK
Replace the URL with:
http://s1mp3.r41s223.vcdn.vn/d3f549abeeef07b15efe/2937387453157939420?key=c2WuQChtsmR9yfdz9I-jnw&expires=1480695588&filename=Only%20Love%20-%20Trademark.mp3
-> it doesn't work; nothing happens
By default starting in iOS 9 all connections must be https. If the website for the second URL doesn't support https:// then the download would fail.
I suggest checking the error code you get back from the Download
If you want to use url with HTTP connection, then in your info.plist file add the following
App Transport Security Setting and in that add subsection Allow Arbitrary Loads and set the value to YES.
Please add in Plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>akamaihd.net</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>facebook.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>fbcdn.net</key>
<dict>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
<key>graph.facebook.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
</plist>
Then using Alamofire 4.0 Swift 3.0
Using below method, you can download any thing, ex. PDF
// Mark:- Download File
func DownloadFile(strFileUrl : String, strFileName : String, success:#escaping (_ strResultURL: String) -> Void , failure:#escaping (_ responseObject:AnyObject) -> Void) {
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileURL = documentsURL.appendingPathComponent("\(strFileName)")
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
Alamofire.download(strFileUrl, to: destination).response { response in
if SVProgressHUD.isVisible() {
SVProgressHUD.dismiss()
}
if response.error == nil {
success("\(response.destinationURL!)")
}
else {
failure(response.error as AnyObject)
}
}.downloadProgress { (progress) in
print("Download Progress: \(progress.fractionCompleted)")
SVProgressHUD.showProgress(Float(progress.fractionCompleted), status: AppAlertMsg.KDownloadingPDFs)
}
}

Resources