I'm having a scenario in which
1) I'm registering my mobile number using post request.
2) On successfull registration will get OTP on my registered mobile number.
3) After receiving the OTP, I have to verify this OTP on the server.
4) And then server will send me the pin on my registered mobile number,using this pin will able to login my app.
Now coming to the issue after on successfull registration I received an OTP but how to verify this otp and get the pin on my number?.
I have used below code for this. 0123456789 is my registered mobile number and 3588 is the code have received on successfull registration.
#IBAction func verifyotp(_ sender: Any) {
var request = URLRequest(url: URL(string: "myurl/verifyotp?mobileno=0123456789&otp=3588")!)
request.httpMethod = "POST"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
DispatchQueue.main.async {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
self.present(vc, animated: true)
}
}
task.resume()
}
But somehow It didnt match the scenario and m receiving the response like:
Optional("{\"Success\":\"No Active account found.\"}")
Looking for a help.Thanks in advance.
Related
I need to resume my WebService if my bearer token expire by http code 401 ,
below is my code.
When a 401 error occurs that means the Access Token has expired and I need to send a Refresh Token over to my server to obtain a new Access Token.
After getting a new Access Token I need to redo the previous request that got the 401 error.
Suppose I hit webservice1 and its give 401 http code , then new bearer token request will generate and the same API resume to work. How can I do it ?
import UIKit
import CryptoKit
class SharedWebService: NSObject {
static let sharedApiInstance = SharedWebService()
func generalApiMethod (parameter : NSDictionary ,completion: #escaping ((NSMutableArray?) -> Void))
{
var dashboarddata : NSMutableArray = NSMutableArray()
let urlString = String(format:"URL OF API HERE")
let url = URL(string: urlString)
guard let requestUrl = url else { fatalError() }
var request = URLRequest(url: requestUrl)
request.timeoutInterval = 60
let bearerToken = "current bearer token"
request.setValue(bearerToken, forHTTPHeaderField: "Authorization")
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Accept")
URLSession.shared.dataTask(with: request) {
(data, response, error) in
if let httpResponse = response as? HTTPURLResponse {
print(httpResponse.statusCode)
if httpResponse.statusCode == 401
{
// Refresh bearerToken get here
let bearerToken = self.getBearerTokenDevice() //fetch api to get new bearer token
return
}
}
guard error == nil else {
print(error!.localizedDescription);
DispatchQueue.main.async{
completion(dashboarddata)
}
return
}
guard let jsonData = data else { print("Empty data"); return }
if String(data: jsonData, encoding: String.Encoding.utf8) != nil
{
do {
let responseJSON = try? JSONSerialization.jsonObject(with: jsonData, options: [])
if let responseJSON = responseJSON as? [String: Any] {
//Success case do here reponse return
completion(dashboarddata)
}
}
}
}.resume()
}
func getBearerTokenDevice()-> String
{
//how to handle it
return "New bearer token from api fetch"
}
}
work arround is,
Always call Api at splah which fetches Bearer token from server, it will refresh the token every time user opens the app,
2.1 make Api call Queue to process Api calls (Use generics here)
2.2 if api is successfull, Ok. if not than call a special Api call yo get the token,
2.3 if after fetching the token, get last api from Api Queue and call it..
its just an idea, how i think, i think it will be done, might be different in your case
https://stevenpcurtis.medium.com/use-operationqueue-to-chain-api-calls-in-swift-71eefd6891ef
here is guide to make Api call chain
I'm trying to create a iOS app that processes credit card payments using the Square API.
I'm using a Heroku server as the backend.
My issue is when I try to process the credit card payment using the Card Entry view controller. I'm getting a NSCocoaErrorDomain issue code 3840 saying the "JSON text did not start with array or object and option to allow fragments not set."
Here is the snippet of code I used to set up the card entry form:
let theme = SQIPTheme()
theme.errorColor = .red
theme.tintColor = Color.primaryAction
theme.keyboardAppearance = .light
theme.messageColor = Color.descriptionFont
theme.saveButtonTitle = "Pay"
let cardEntryForm = SQIPCardEntryViewController(theme: theme)
return cardEntryForm
And here is the snippet of code I used to process the payment:
ChargeApi.processPayment(cardDetails.nonce) { (transactionID, errorDescription) in
guard let errorDescription = errorDescription else {
// No error occured, we successfully charged
completionHandler(nil)
return
}
}
Also here is the ChargeApi (code that is doing the processing of the payment):
class ChargeApi {
static public func processPayment(_ nonce: String, completion: #escaping (String?, String?) -> Void) {
let url = URL(string: Constants.Square.CHARGE_URL)!
var request = URLRequest(url: url)
request.httpMethod = "POST"
let json = ["nonce": nonce]
let httpBody = try? JSONSerialization.data(withJSONObject: json)
print(json)
request.addValue("Application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = httpBody
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error as NSError?{
if error.domain == NSURLErrorDomain {
DispatchQueue.main.async {
completion("", "Could not contact host")
}
} else {
DispatchQueue.main.async {
completion("", "Something went wrong")
}
}
} else if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 {
DispatchQueue.main.async {
completion("success", nil)
}
} else {
DispatchQueue.main.async {
completion("", json["errorMessage"] as? String)
}
}
} catch {
DispatchQueue.main.async {
completion("", "Failure")
}
}
}
}.resume()
}
I believe the way it works, is that after submission the credit card info is wrapped up in a value called a "nonce" and it is sent to the Sqaure API to be processed.
The API looks for this "nonce" in the following json format ["nonce": (some nonce value)].
However after successfully following the steps in the InAppPaymentsSample example:
https://developer.squareup.com/docs/in-app-payments-sdk/quick-start/step-2
I'm trying to something similar with my test app as far as talking to the Heroku server and sending test card information to the server, however I'm getting this NSCocoaErrorDomain issue.
Please help.
So when I send request without any cookies I get an error.
when trying to get request manually (in a browser) I first need to go to homepage, which loads 4 cookies, then the request can proceed without error. Some experimenting showed that I need only one of the cookies.
This is completely new to me and any snippets/guides on how this can be implemented are welcome. I understand that this question Is pretty vague but I am lost in where to start looking and would appreciate any help
let url = URL(string: "homepage")
var request = URLRequest(url: url!)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil, let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
print("response1")
print("error = \(error)")
print("response = \(response)")
return
}
if let json = try? JSONSerialization.jsonObject(with: data) {
print("responseObject = \(json)")
} else {
print("response2")
print("responseString = \(String(data: data, encoding: .utf8))")
}
let url2 = URL(string: "requestpage")
var request = URLRequest(url: url2!)
request.setValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil, let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
print("response2")
print("error = \(error)")
print("response = \(response)")
return
}
if let json = try? JSONSerialization.jsonObject(with: data) {
print("responseObject = \(json)")
} else {
print("response2")
print("responseString = \(String(data: data, encoding: .utf8))")
}
}
task.resume()
}
task.resume()
In your code, you should:
initiate URLSessionTask for the landing page that sets the cookies;
that will, with no intervention on your part, will set the cookies in your URLSession;
after that response is successfully received, you can then send the next request and the cookies should be there automatically with no extra code.
Unless you did something to explicitly interfere with this process, URLSession seamlessly receives the the cookies and includes them in subsequent requests for you.
If you're scraping a web site (and if so, please check the ToS to make sure it's permitted), you are well advised to request the pages in the same order that a web browser would. It might feel like you could bypass that landing page and set the cookies yourself, but often the cookie values are generated dynamically and you can have problems if you try to bypass that landing page.
You asked for an example, and there's really not much to show. Just initiate second request from the completion of the first request. There's not a single reference to cookies in the Swift code. URLSession takes care of everything:
let url = baseURL.appendingPathComponent("setcookie.php")
var request = URLRequest(url: url)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil, let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
print("error = \(error)")
print("response = \(response)")
return
}
let url = baseURL.appendingPathComponent("results.php")
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil, let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
print("error = \(error)")
print("response = \(response)")
return
}
if let json = try? JSONSerialization.jsonObject(with: data) {
print("responseObject = \(json)")
} else {
print("responseString = \(String(data: data, encoding: .utf8))")
}
}
task.resume()
}
task.resume()
My first page, setcookie, just set a cookie:
<?php
setcookie("foo", "bar", time()+3600);
$result = array("success" => true);
echo json_encode($result);
?>
And my second page retrieved the cookies:
<?php
$result = array("success" => true);
if (isset($_COOKIE))
$result["_COOKIE"] = $_COOKIE;
header("Content-Type: application/json");
echo json_encode($result);
?>
And the above Swift code output:
responseObject = {
"_COOKIE" = {
foo = bar;
};
success = 1;
}
I am searching for an hour for a way to do that(without Parse because it's going down this month).
I am trying to do in the app that one user can send push notification message to another specific user.
What are the options to implement that?(please be specific)
Thanks.
What you're looking for is not typically recommended, as it can very easily become problematic. Techincally, users should not be able to send direct push notifications to other users. All notifications should be handled through a central system that wouldn't be accessible to your individual users. However, if you feel that you'd still like to make this work, read on.
I have a mechanism like this in one of my apps, using FCM. Here's the function (with some modifications to take out my specific information) that I use to send messages from one user to another:
func push(message: String, toUser: String) {
var token: String?
for person in self.users {
if toUser == person.username && person.firebaseToken != nil {
token = person.firebaseToken
}
}
if token != nil {
var request = URLRequest(url: URL(string: "https://fcm.googleapis.com/fcm/send")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("key=[your FCM Server Key]", forHTTPHeaderField: "Authorization")
let json = [
"to" : token!,
"priority" : "high",
"notification" : [
"body" : message
]
] as [String : Any]
do {
let jsonData = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("Error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
// check for http errors
print("Status Code should be 200, but is \(httpStatus.statusCode)")
print("Response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
print("responseString = \(responseString)")
}
task.resume()
}
catch {
print(error)
}
}
}
I keep this method in my appDelegate, and call it whenever necessary. Basically, every user in my app has a Firebase messaging token assigned to them, and it's just another property of each user. You can get a user's FCM token with this call:
let token = FIRInstanceID.instanceID().token()
Usually, the token can be retrieved and saved when a user first creates an account. The token will remain the same as long as the user uses the same device.
Again, this can be very dangerous if it is implemented without proper security measures to prevent your users from having total control over sending push notifications.
I am not sure about this.
Although the status code is 200, I can't see any notification.
This is the return value.
{
\"multicast_id\":6666941437973455953,
\"success\":1,
\"failure\":0,
\"canonical_ids\":0,
\"results\":[{\"message_id\":\"0:1490256129594240%03b6b50f03b6b50f\"}]
}
I confuse by getting HTTP response in post method. when i check response on postman, then the required response is got and profile updated successfully. But in programmatically i got error notice. What was the problem? how to solve it? please, refer screenshots. Thanks in advance!
Code i have try
override func viewDidLoad() {
super.viewDidLoad()
self.updateDetails()
}
func updateDetails()
{
let postString = "api=update_people&user_id=18&email=rajesh#gmail.com&first_name=Raejsh&phone=456562&age=26&gender=male&blood_group=A"
print(postString)
// let alertMessage = alert()
let url = NSURL(string: "http://kuruthi.in/portal/api/register")
let request = NSMutableURLRequest(url: url as! URL)
request.httpBody = postString.data(using: String.Encoding.utf8)
request.httpMethod = "POST"
request.addValue("123456", forHTTPHeaderField: "X-API-KEY")
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request as URLRequest) { data,response,error in
guard error == nil && data != nil else
{
print("Error:\(error)")
return
}
let httpStatus = response as? HTTPURLResponse
if httpStatus!.statusCode == 200
{
if data?.count != 0
{
let responseString = String(data: data!, encoding: .utf8)
print(responseString)
}
else
{
print("No data got from url!")
}
}
else
{
print("error httpstatus code")
}
}
task.resume()
}
Response in Program output :
Response in postman:
The reason you are getting html code is that you are receiving some error from your web services look at the message "A PHP Error was encountered" in your output log.
The success in postman is because your request is in form-data. Compare the request from postman from Raw with the request you are generating.
You can refer this link for creating a request. But the code is in Objective-Cand you can use this link to convert the code, or you can use Alamofire to create requests and refer this link for creating multipart form-data requests using Alamofire