Twitter Kit RestAPI does not support IPv6? - Rejected from Apple - ios

My app is rejected due to not supporting IPv6 network support.
Here is message from Apple:
We discovered one or more bugs in your app when reviewed on iPhone
running iOS 11 on Wi-Fi connected to an IPv6 network.
Submitting a Tweet through the app does not post it on the feed or on
the Twitter web-site.
My app is very simple and posts text using RestAPI call. Here is code snippet.
let client = TWTRAPIClient(userID: userid)
let url = "https://api.twitter.com/1.1/statuses/update.json";
let message:[String:Any] = ["status": text]
var error: NSError?
let request = client.urlRequest(withMethod: "POST", url: url, parameters: message, error: &error)
DispatchQueue.main.async {
client.sendTwitterRequest(request) { (response, data, ConnectionError) -> Void in
if let error = connectionError {
print("Error: \(error.localizedDescription)")
DispatchQueue.main.async {
completion(error)
}
} else {
DispatchQueue.main.async {
completion(nil)
}
}
}
}
Did anyone experience this?

Removing AFNetworking from Podfile fixed the issue

Related

Unable to call some API's in Xcode

I'm dealing with a strange issue where I'm not able to hit some API's through iOS simulator in XCode.
Version: Xcode 10.3
I've tried using the following:
https://finnhub.io/api/v1/stock/profile2?symbol=GOOGL&token=
https://www.alphavantage.co/query?function=OVERVIEW&symbol=IBM&apikey=demo
I'm able to hit both endpoints through the browser, replacing both with a completely unrelated api: https://cat-fact.herokuapp.com/facts works, I'm able to see the response immediately as expected.
I've added the following to my Info.plist:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Code:
let apiBaseUrl = "https://www.alphavantage.co/query?function=OVERVIEW&symbol=IBM&apikey=demo"
func getStock(symbol: String) {
if let url = URL(string: apiBaseUrl) {
let task = URLSession.shared.dataTask(with: url, completionHandler: {
data, res, err in
if let error = err {
print(error)
} else {
var result: Any! = nil
do
{
result = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments)
}
catch{
print("exception: ")
}
print(result)
}
})
task.resume()
}
}
In my console I see the following:
HTTP load failed (error code: -999 [1:89])
PAC result block not invoked
Received XPC error Connection invalid for message type 3 kCFNetworkAgentXPCMessageTypePACQuery
I solved this issue as below :
I went into
System Preferences > Network > Advanced > Proxies
and unticked "Auto Proxy Discovery"
My calls now work.

Super long wifi request travel time on iPhone 8 / iPhone X

Not sure if it's ok to ask this here but I'm now confronting this frustrating problem and would like to ask for opinion on how to deal with this.
From some of the forum and discussions, looks like iPhone 8 and iPhone X has super slow internet issue when using wifi and running on iOS 11.4 / 11.4.1, and this results to the request travel time rediculously increases to almost 55 seconds (e.g. Hello world pinging test API) for a very simple request in my app. If I turn the wifi off and use 4G instead, the same request travel time is only 2 seconds(the API server is in the US while the app is oversea, so generally bearable), and the same request only travels 2 - 3 seconds on iPhone 6 plus running on iOS 11.2 / 11.4.1 in wifi mode.
I guess this is more a hardware or system side bug and on the app side we may not be able to do anything about this. However, as our client users who use iPhone 8 are unhappy about the waiting time and insist on solving it, and I also found that if I call the hello world API from safari browser of the iPhone, things are not that bad. Therefore, I would like to know if there is anything the app side can do (ex. detect this issue and do the workaround) to fix this or sooth the awful user experiences?
P.S. My app is written in Swift and I don't use third party library such as Alamofire to manage requests, simply use the build-in functionalities in Foundation. I would like to post some code on my sending request here, even if this may not help much.
func sendRequest(request: URLRequest, completion: #escaping (Int, Data?, Error?) -> Void) {
let task = URLSession.shared.dataTask(with: request) {data, response, error in
guard let data = data, error == nil else {
print("HTTP request error=\(String(describing: error))")
// use 999 to represend unknown error
completion(HTTPHelper.DEFAULT_STATUS_CODE, nil, error)
return
}
guard let httpStatus = response as? HTTPURLResponse else { // check for http errors
return
}
if(httpStatus.statusCode != 200) {
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(String(describing: response))")
}
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
} catch {
print("error serializing JSON: \(error)")
}
let responseString = String(data: data, encoding: .utf8) ?? ""
print(responseString)
completion(httpStatus.statusCode, data, nil)
}
task.resume()
}
And this is the function where the above request is called, the request travel time is the time elapsed between two [TIME FLAG]:
func test(completion: #escaping (Bool) -> Void) {
let url = httpHelper.myUrlBuilder()
let request = httpHelper.wrapGetRequest(url: url, withToken: .none)
NSLog("[TIME FLAG] Test request sent")
httpHelper.sendRequest(request: request as URLRequest) { statusCode, data, error in
NSLog("[TIME FLAG] Test response get")
guard error == nil && self.httpHelper.validateStatusCode(statusCode: statusCode) else {
completion(false)
return
}
completion(true)
}
}
Thanks for any kind of answers and feedbacks.

Integrate LinkedIn Authentication to Firebase Auth in iOS using Swift

I'm pretty much new here but I've been developing in swift (ver. 4) for approximately 3 months. So, I have this issue on implementing the LinkedIn authentication using a web view since I don't want to utilise the authentication with the need of a LinkedIn app -- UX stuff.
I used the following guides in order to accomplish this, but I was only able to get to the point of getting an access token with a bug of being stuck in the logging in process. When I debugged the application, I was able to get the access token but the view controller for the web view does not dismiss.
These are the guides I used:
LinkedIn Auth: https://www.appcoda.com/linkedin-sign-in/
Custom Firebase Auth: https://firebase.google.com/docs/auth/ios/custom-auth
Issues:
Unable to dismiss the view controller after getting the access
token.
Where to get the needed "custom token" using the access
token I have for the Firebase Custom Authentication.
Code snippet for Issue #1
// Initialize a NSURLSession object.
let session = URLSession(configuration: URLSessionConfiguration.default)
// Make the request.
let task: URLSessionDataTask = session.dataTask(with: request) { (data, response, error) -> Void in
// Get the HTTP status code of the request.
let statusCode = (response as! HTTPURLResponse).statusCode
if statusCode == 200 {
// Convert the received JSON data into a dictionary.
do {
let dataDictionary = try JSONSerialization.jsonObject(with: data!, options: []) as! [String : AnyObject]
let accessToken = dataDictionary["access_token"] as! String
UserDefaults.standard.set(accessToken, forKey: "LIAccessToken")
UserDefaults.standard.synchronize()
// Custom Firebase Auth
// Auth.auth().signIn(withCustomToken: UserDefaults.standard.string(forKey: "LIAccessToken")!) { (user, error) in
// if let error = error {
// print(error)
// return
// }
//
// }
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
}
} catch {
print("Could not convert JSON data into a dictionary.")
}
}
}
task.resume()
Thanks in advance to any help! I hope to be able to help those who have the same issues.

URLSessionUploadTask getting automatically cancelled instantly

I'm having this weird issue in which a newly created URLSessionUploadTask gets cancelled instantly. I'm not sure if it's a bug with the current beta of Xcode 8.
I suspect it might be a bug because the code I'm about to post ran fine exactly once. No changes were made to it afterwards and then it simply stopped working. Yes, it literally ran once, and then it stopped working. I will post the error near the end.
I will post the code below, but first I will summarize how the logic here works.
My test, or user-exposed API (IE for use in Playgrounds or directly on apps), calls the authorize method. This authorize method will in turn call buildPOSTTask, which will construct a valid URL and return a URLSessionUploadTask to be used by the authorize method.
With that said, the code is below:
The session:
internal let urlSession = URLSession(configuration: .default)
Function to create an upload task:
internal func buildPOSTTask(onURLSession urlSession: URLSession, appendingPath path: String, withPostParameters postParams: [String : String]?, getParameters getParams: [String : String]?, httpHeaders: [String : String]?, completionHandler completion: URLSessionUploadTaskCompletionHandler) -> URLSessionUploadTask {
let fullURL: URL
if let gets = getParams {
fullURL = buildURL(appendingPath: path, withGetParameters: gets)
} else {
fullURL = URL(string: path, relativeTo: baseURL)!
}
var request = URLRequest(url: fullURL)
request.httpMethod = "POST"
var postParameters: Data? = nil
if let posts = postParams {
do {
postParameters = try JSONSerialization.data(withJSONObject: posts, options: [])
} catch let error as NSError {
fatalError("[\(#function) \(#line)]: Could not build POST task: \(error.localizedDescription)")
}
}
let postTask = urlSession.uploadTask(with: request, from: postParameters, completionHandler: completion)
return postTask
}
The authentication function, which uses a task created by the above function:
public func authorize(withCode code: String?, completion: AccessTokenExchangeCompletionHandler) {
// I have removed a lot of irrelevant code here, such as the dictionary building code, to make this snippet shorter.
let obtainTokenTask = buildPOSTTask(onURLSession: self.urlSession, appendingPath: "auth/access_token", withPostParameters: nil, getParameters: body, httpHeaders: nil) { (data, response, error) in
if let err = error {
completion(error: err)
} else {
print("Response is \(response)")
completion(error: nil)
}
}
obtainTokenTask.resume()
}
I caught this error in a test:
let testUser = Anilist(grantType: grant, name: "Test Session")
let exp = expectation(withDescription: "Waiting for authorization")
testUser.authorize(withCode: "a valid code") { (error) in
if let er = error {
XCTFail("Authentication error: \(er.localizedDescription)")
}
exp.fulfill()
}
self.waitForExpectations(withTimeout: 5) { (err) in
if let error = err {
XCTFail(error.localizedDescription)
}
}
It always fails instantly with this error:
Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldntexist.bo&client_id=ibanez-hod6w&code=REMOVED,
NSLocalizedDescription=cancelled,
NSErrorFailingURLStringKey=https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldntexist.bo&client_id=ibanez-hod6w&code=REMOVED}
Here's a few things to keep in mind:
The URL used by the session is valid.
All credentials are valid.
It fails instantly with a "cancelled" error, that simply did not happen before. I am not cancelling the task anywhere, so it's being cancelled by the system.
It also fails on Playgrounds with indefinite execution enabled. This is not limited to my tests.
Here's a list of things I have tried:
Because I suspect this is a bug, I first tried to clean my project, delete derived data, and reset all simulators. None of them worked.
Even went as far restarting my Mac...
Under the small suspicion that the upload task was getting deallocated due to it not having any strong pointers, and in turn calling cancel, I also rewrote authorize to return the task created by buildPOSTTask and assigned it to a variable in my test. The task was still getting cancelled.
Things I have yet to try (but I will accept any other ideas as I work through these):
Run it on a physical device. Currently downloading iOS 10 on an iPad as this is an iOS 10 project. EDIT: I just tried and it's not possible to do this.
I'm out of ideas of what to try. The generated logs don't seem to have any useful info.
EDIT:
I have decided to just post the entire project here. The thing will be open source anyway when it is finished, and the API credentials I got are for a test app.
ALCKit
After struggling non-stop with this for 6 days, and after googling non-stop for a solution, I'm really happy to say I have finally figured it out.
Turns out that, for whatever mysterious reason, the from: parameter in uploadTask(with:from:completionHandler) cannot be nil. Despite the fact that the parameter is marked as an optional Data, it gets cancelled instantly when it is missing. This is probably a bug on Apple's side, and I opened a bug when I couldn't get this to work, so I will update my bug report with this new information.
With that said, everything I had to do was to update my buildPOSTTask method to account for the possibility of the passed dictionary to be nil. With that in place, it works fine now:
internal func buildPOSTTask(onURLSession urlSession: URLSession, appendingPath path: String, withPostParameters postParams: [String : String]?, getParameters getParams: [String : String]?, httpHeaders: [String : String]?, completionHandler completion: URLSessionUploadTaskCompletionHandler) -> URLSessionUploadTask {
let fullURL: URL
if let gets = getParams {
fullURL = buildURL(appendingPath: path, withGetParameters: gets)
} else {
fullURL = URL(string: path, relativeTo: baseURL)!
}
var request = URLRequest(url: fullURL)
request.httpMethod = "POST"
var postParameters: Data
if let posts = postParams {
do {
postParameters = try JSONSerialization.data(withJSONObject: posts, options: [])
} catch let error as NSError {
fatalError("[\(#function) \(#line)]: Could not build POST task: \(error.localizedDescription)")
}
} else {
postParameters = Data()
}
let postTask = urlSession.uploadTask(with: request, from: postParameters, completionHandler: completion)
return postTask
}
Are you by any chance using a third party library such as Ensighten? I had the exact same problem in XCode 8 beta (works fine in XCode 7) and all of my blocks with nil parameters were causing crashes. Turns out it was the library doing some encoding causing the issue.
For me, this was a weak reference causing the issue, so I changed
completion: { [weak self] (response: Result<ResponseType, Error>)
to
completion: { [self] (response: Result<ResponseType, Error>)

How to deal with NSData contentsOfURL EXC_BREAKPOINT error

I am trying to obtain NSData from a server using contentsOfURL. When the iPhone is connected to wifi, it works fine. But when not connected to wifi, my app crashes with an EXC_BREAKPOINT message. How can I handle or circumvent this issue of crashing when not connected?
do {
let varOption = try NSData(contentsOfURL: NSURL(string: urlToRequest)!, options:NSDataReadingOptions.DataReadingMappedIfSafe)
} catch {
print("error encountered")
}
Is there a requirement to use NSData's contentsOfURL? Why not make an async web request using NSURLSession?
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlToRequest)!) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
// if data && !error, do the thing
}.resume()
You can use this tutorial to create a function to check if iPhone is connected to Internet.
http://www.brianjcoleman.com/tutorial-check-for-internet-connection-in-swift/
After implementing this function you can use it to validate the connection and then put your code inside an if statement block
if isConnectedToNetwork() { //<-- This is the function implemented in tutorial posted before.
//Here we put your code
do {
let varOption = try NSData(contentsOfURL: NSURL(string: urlToRequest)!, options:NSDataReadingOptions.DataReadingMappedIfSafe)
} catch {
print("error encountered")
}
}

Resources