How to do product search api in iOS swift? - ios

I am using amazon product advertising api for search product. Installed awscore and alamofire cocopods. Done functionality for getting signature and added parameters for item search to get product images, title and description in table view list.
Here is the code i tried for getting amazon search:
private func signedParametersForParameters(parameters: [String: String]) -> [String: String] {
let sortedKeys = Array(parameters.keys).sorted(by: <)
let query = sortedKeys.map { String(format: "%#=%#", $0, parameters[$0] ?? "") }.joined(separator: "&")
let stringToSign = "GET\nwebservices.amazon.in\n/onca/xml\n\(query)"
print("stringToSign::::\(stringToSign)")
let dataToSign = stringToSign.data(using: String.Encoding.utf8)
let signature = AWSSignatureSignerUtility.hmacSign(dataToSign, withKey: CameraViewController.kAmazonAccessSecretKey, usingAlgorithm: UInt32(kCCHmacAlgSHA256))!
var signedParams = parameters;
signedParams["Signature"] = urlEncode(signature)
print("urlencodesignature::\(urlEncode(signature))")
return signedParams
}
public func urlEncode(_ input: String) -> String {
let allowedCharacterSet = (CharacterSet(charactersIn: "!*'();:#&=+$,/?%#[] ").inverted)
if let escapedString = input.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) {
return escapedString
}
return ""
}
func send(url: String) -> String {
// activityIndicator.startAnimating()
guard let url = URL(string: url) else {
print("Error! Invalid URL!") //Do something else
// activityIndicator.stopAnimating()
return ""
}
print("send URL: \(url)")
let request = URLRequest(url: url)
let semaphore = DispatchSemaphore(value: 0)
var data: Data? = nil
URLSession.shared.dataTask(with: request) { (responseData, _, _) -> Void in
data = responseData
print("send URL session data: \(String(describing: data))")
let parser = XMLParser(data: data!)
parser.delegate = self as? XMLParserDelegate
if parser.parse() {
print(self.results ?? "No results")
}
semaphore.signal()
}.resume()
// activityIndicator.stopAnimating()
semaphore.wait(timeout: .distantFuture)
let reply = data.flatMap { String(data: $0, encoding: .utf8) } ?? ""
return reply
}
public func getSearchItem(searchKeyword: String) -> [String:AnyObject]{
let timestampFormatter: DateFormatter
timestampFormatter = DateFormatter()
timestampFormatter.timeZone = TimeZone(identifier: "GMT")
timestampFormatter.dateFormat = "YYYY-MM-dd'T'HH:mm:ss'Z'"
timestampFormatter.locale = Locale(identifier: "en_US_POSIX")
// let responsegroupitem: String = "ItemAttributes"
// let responsegroupImages:String = "Images"
// activityIndicator.startAnimating()
let operationParams: [String: String] = [
"Service": "AWSECommerceService",
"Operation": "ItemSearch",
"ResponseGroup": "Images,ItemAttributes",
"IdType": "ASIN",
"SearchIndex":"All",
"Keywords": searchKeyword,
"AWSAccessKeyId": urlEncode(CameraViewController.kAmazonAccessID),
"AssociateTag": urlEncode(CameraViewController.kAmazonAssociateTag),
"Timestamp": urlEncode(timestampFormatter.string(from: Date()))]
let signedParams = signedParametersForParameters(parameters: operationParams)
let query = signedParams.map { "\($0)=\($1)" }.joined(separator: "&")
let url = "http://webservices.amazon.in/onca/xml?" + query
print("querydata::::\(query)")
let reply = send(url: url)
print("reply::::\(reply)")
// activityIndicator.stopAnimating()
return [:]
}
Created bridging header file #import .
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
getSearchItem(searchKeyword: searchKeyword)
}
Here is my console output:
My issue is when tapping search button product searched was not listing. What mistake done i don't know. Can anyone help me out of this pls..

According to the documentation:
The HTTPRequestURI component is the HTTP absolute path component of the URI up to, but not including, the query string. If the HTTPRequestURI is empty, use a forward slash ( / ).
HTTPRequestURI is always "/onca/xml" for Product Advertising API. HTTPVerb is either GET or POST.
Try just setting requestURL to "/onca/xml" instead of the full URL you shouldn't be sending the full URL or the query string in this part.
Also you need to percent encode the values that you are sending. You are sending commas in the response group property which should be percent encoded
let operationParams: [String: String] = [
"Service": "AWSECommerceService",
"Operation": "ItemSearch",
"ResponseGroup": urlEncode("Images,ItemAttributes"),
"IdType": "ASIN",
"SearchIndex":"All",
"Keywords": urlEncode(searchKeyword),
"AWSAccessKeyId": urlEncode(CameraViewController.kAmazonAccessID),
"AssociateTag": urlEncode(CameraViewController.kAmazonAssociateTag),
"Timestamp": urlEncode(timestampFormatter.string(from: Date()))]
let stringToSign = "GET\n/onca/xml\n\(query)"
Note: You should be using https instead of http

Related

Send Barcode string to an API endpoint in Swift

I'm very new in programing, I have been learning swift5 for a few months now. I'm trying to make an APP that scan a 1D or 2D barcode, take the string and send it to an API endpoint which will give me back some info, for example, product number and batch number.
For the barcode part I'm using a really nice software from GitHub called BarcodeScanner. It is running without any issue and I'm able to get the string from the barcode it reads.
Once I have the string I'm able to send it to the API endpoint but then it gets stuck there.
If I run the same code in a playground it works without problems, it makes the request and I can see the answer in JSON from the server. If I run the code on the iPhone then it gets stuck. Of course I cannot use the scanning part when in playground, I use it to test the networking part and communication with the API.
Here is my Networking.swift file, it has some print() used for debug:
import Foundation
import UIKit
protocol NetworkManagerDelegate: class {
func didUpdatePharmo(pharmo: PharmoModel)
func didUpdateBarcode(barcode: BarcodeModel)
}
public struct NetworkManager {
var delegate: NetworkManagerDelegate?
let pharmoURL = "https://someurl.com/api"
let pharmoEndpoint = "https://someendpoint.com/api"
func fetchData(productNumber: String) {
let urlString = "\(pharmoURL)&number=\(productNumber)"
performRequestProductInfo(urlString: urlString)
print(urlString)
}
func fetchEndpoint(dataMatrix: String) {
let urlString = "\(pharmoEndpoint)&datamatrix=\(dataMatrix)"
performRequestEndpoint(urlString: urlString)
print(urlString)
}
func performRequestEndpoint(urlString: String) {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
var request = URLRequest(url: url)
request.httpMethod = "GET"
let task = session.dataTask(with: request) { (data, response, error) in
if error != nil {
print(error!)
return
}
if let response = response as? HTTPURLResponse {
print("EndPoint HTTP Status code: \(response.statusCode)")
}
if let safeData = data {
if let barcode = self.parseJSONEndpoint(endPointData: safeData) {
self.delegate?.didUpdateBarcode(barcode: barcode)
}
}
}
task.resume()
}
}
func parseJSONEndpoint(endPointData: Data) -> BarcodeModel? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(BarcodeData.self, from: endPointData)
let productNumber = decodedData.product_number
let batchNumber = decodedData.batchnumber
let barcode = BarcodeModel(productNumber: productNumber, batchNumber: batchNumber)
print(batchNumber)
return barcode
} catch {
print(error)
return nil
}
}
func performRequestProductInfo(urlString: String) {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
var request = URLRequest(url: url)
request.httpMethod = "GET"
let task = session.dataTask(with: request) { (data, response, error) in
if error != nil {
print(error!)
return
}
if let response = response as? HTTPURLResponse {
print("ProductInfo HTTP Status code: \(response.statusCode)")
}
if let safeData = data {
if let pharmo = self.parseJSONProductInfo(pharmoData: safeData) {
self.delegate?.didUpdatePharmo(pharmo: pharmo)
}
}
}
task.resume()
}
}
func parseJSONProductInfo(pharmoData: Data) -> PharmoModel? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(PharmoData.self, from: pharmoData)
let id = decodedData.id
let number = decodedData.number
let name = decodedData.name
let atcCode = decodedData.atc_code
let imagePath = decodedData.image_path
let displayImage = decodedData.display_image
let storageGroupId = decodedData.storage_group_id
let animalGroupId = decodedData.animal_group_id
let udlevbest = decodedData.udlevbest
let packageSizeText = decodedData.package_size_text
let packageSizeNum = decodedData.package_size_num
let unitCode = decodedData.unit_code
let strengthText = decodedData.strength_text
let prodPrice = decodedData.prod_price
let aupPrice = decodedData.aup_price
let aupInstPrice = decodedData.aup_inst_price
let animalGroups = decodedData.animal_groups
let udleveringsbestemmelse = decodedData.udleveringsbestemmelse
let animalGroup = decodedData.animal_group
let storageGroup = decodedData.storage_group
let species = decodedData.species
let indications = decodedData.indications
let substances = decodedData.substances
let manufacturer = decodedData.manufacturer
let pharmo = PharmoModel(id: id, number: number, name: name, atc_code: atcCode, image_path: imagePath, display_image: displayImage, storage_group_id: storageGroupId, animal_group_id: animalGroupId, udlevbest: udlevbest, package_size_text: packageSizeText, package_size_num: packageSizeNum, unit_code: unitCode, strength_text: strengthText, prod_price: prodPrice, aup_price: aupPrice, aup_inst_price: aupInstPrice, animal_groups: animalGroups, udleveringsbestemmelse: udleveringsbestemmelse, animal_group: animalGroup, storage_group: storageGroup, species: species, indications: indications, substances: substances, manufacturer: manufacturer)
print(name)
return pharmo
} catch {
print(error)
return nil
}
}
}
From the ViewController.swift running the barcode scanner I call the function fetchEndpoint(dataMatrix: String)
extension ViewController: BarcodeScannerCodeDelegate {
func scanner(_ controller: BarcodeScannerViewController, didCaptureCode code: String, type: String) {
print("Barcode Data: \(code)")
print("Symbology Type: \(type)")
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
networkManager.fetchEndpoint(dataMatrix: code)
}
}
}
From the console output I can see this 2 print() statements from ViewController.swift:
print("Barcode Data: \(code)")
print("Symbology Type: \(type)")
I can also see this print() statement from Networking.swift:
print(urlString)
But nothing happends after that. Again if I run the same code in a playground it works fine. I have also made requests using Postman, so I can see the JSON file and be sure the urlstring is working.
Anyone have some idea what am I doing wrong?
I was able to find the problem. The string being read from the scanner had an non ASCII character.
At any point XCode said anything about a non ASCII character, I had to copy the string into a playground, then I received this error:
Unprintable ASCII character found in source file
I copied the string into a terminal shell and I was able to see the character.
datamatrix=^]01036611030467831722113010RXT0711GC
I will try to use URLComponents or percent encoding

How to get the value of url parameter using swift 4.1

I am trying to get parameters for urls and I try to get only the date not time the URL.
http://aa.no-ip.biz:8001/hf_tracker/api/history.php?accesskey=12345&Vehilce=1618&FromDate=2018-05-10 13:11&ToDate=2018-05-14 12:11
Code:
extension URL {
func valueOf(_ queryParameterName: String) -> String? {
guard let url = URLComponents(string: self.absoluteString) else {
return nil
}
return url.queryItems?.first(where: { $0.name == queryParameterName})?.value
}
}
let newURL = URL(string: "assetlinkasia.no-ip.biz:8001/hf_tracker/api/…)!
newURL.valueOf("toDate")
newURL.valueOf("fromDate")
How can I only get the date and not time?
This is the way you can do it,
Your URL extension here, from here
extension URL {
func valueOf(_ queryParamaterName: String) -> String? {
guard let url = URLComponents(string: self.absoluteString) else { return nil }
return url.queryItems?.first(where: { $0.name == queryParamaterName })?.value
}
}
Your code goes here,
let string = "http://aa.no-ip.biz:8001/hf_tracker/api/history.php?accesskey=12345&Vehilce=1618&FromDate=2018-05-10 13:11&ToDate=2018-05-14 12:11"
let test = string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let url = URL(string: test!)!
let fromDate = url.valueOf("FromDate")
let toDate = url.valueOf("ToDate")
let date1 = fromDate?.components(separatedBy: " ").first
print(date1)
let date2 = toDate?.components(separatedBy: " ").first
print(date2 )
Output will be below,
2018-05-10
2018-05-14
In my apps a use a helper function that parses the url and returns an optional dictionary:
func parameters(for url: URL) -> [String: String]? {
guard let urlQuery = url.query else { return nil }
// Create all parameters dictionary
let queryArray = urlQuery.split { $0 == "&" }.map(String.init)
var parametersDict: [String: String] = [:]
for queryParameter in queryArray {
// split the queryParam into key / value
let keyValueArray = queryParameter.split{ $0 == "=" }.map(String.init)
let key = keyValueArray.first!
let value = keyValueArray.last!.removingPercentEncoding!
parametersDict.updateValue(value, forKey: key)
}
return parametersDict
}
And use it like this:
let params = parameters(for: URL(string: "https://someurl.com?name=john")!)
if let name = params?["name"] {
print(name)
}
Or you can add a var to URL extension:
extension URL {
var parameters: [String: String]? {
guard let urlQuery = self.query else { return nil }
// Create all parameters dictionary
let queryArray = urlQuery.split { $0 == "&" }.map(String.init)
var parametersDict: [String: String] = [:]
for queryParameter in queryArray {
// split the queryParam into key / value
let keyValueArray = queryParameter.split{ $0 == "=" }.map(String.init)
let key = keyValueArray.first!
let value = keyValueArray.last!.removingPercentEncoding!
parametersDict.updateValue(value, forKey: key)
}
return parametersDict
}
}
And get the parameter:
let params = URL(string: "https://someurl.com?name=john")!.parameters
if let name = params?["name"] {
print(name)
}

UITableCell value not passing to function within UIViewController Swift 3

I have a table that is populated by a search function. There are two buttons within the cell, a checkmark to say yes to a user and an X to say no. There is an insert function that inserts the selection into the database. Unfortunately the value from the table is not being passed to the insert function. Within the insert function, I'm using guestusername.text which is the name of the label in my cell. I'm getting the error 'Use of unresolved identifier guestusername'. I've tried everything I can think of, code below.
class MyShotsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var guest = [AnyObject]()
var avas = [UIImage]()
var valueToPass:String!
var revieweduser:String!
var age = [AnyObject]()
var city = [AnyObject]()
var state = [AnyObject]()
#IBOutlet var tableView: UITableView!
var cell: MyShotsCell?
var index = 0
override func viewDidLoad() {
super.viewDidLoad()
doSearch("")
}
// cell numb
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return guest.count
}
// cell config
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MyShotsCell
// get one by one user related inf from users var
let guest2 = guest[indexPath.row]
let ava = avas[indexPath.row]
// shortcuts
let guestname = guest2["username"] as? AnyObject
let age = guest2["age"]
let city = guest2["city"] as? String
let state = guest2["state"] as? String
// refer str to cell obj
cell.guestusername.text = guestname as! String
cell.ageLbl.text = (NSString(format: "%#", age as! CVarArg) as String)
cell.cityLbl.text = city
cell.stateLbl.text = state
cell.avaImg.image = ava as? UIImage
return cell
}
// search / retrieve users
public func doSearch(_ guestusername : String) {
// shortcuts
let username = user?["username"] as! String
let url = URL(string: "http://www.xxxxx.com/xxxxx.php")!
var request = URLRequest(url: url) // create request to work with users.php file
request.httpMethod = "POST" // method of passing inf to users.php
let body = "revieweduser=\(username)" // body that passes inf to users.php
request.httpBody = body.data(using: .utf8) // convert str to utf8 str - supports all languages
// launch session
URLSession.shared.dataTask(with: request) { data, response, error in
// getting main queue of proceeding inf to communicate back, in another way it will do it in background
// and user will no see changes :)
DispatchQueue.main.async(execute: {
if error == nil {
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
// clean up
self.guest.removeAll(keepingCapacity: false)
self.avas.removeAll(keepingCapacity: false)
self.tableView.reloadData()
// delcare new secure var to store json
guard let parseJSON = json else {
print("Error while parsing")
return
}
guard let parseUSERS = parseJSON["users"] else {
print(parseJSON["message"] ?? [NSDictionary]())
return
}
self.guest = parseUSERS as! [AnyObject]
print(self.guest)
// for i=0; i < users.count; i++
for i in 0 ..< self.guest.count {
// getting path to ava file of user
let ava = self.guest[i]["ava"] as? String
let revieweduser = self.guest[i]["username"] as? String
let age = (NSString(format: "%#", self.guest[i]["age"] as! CVarArg) as String)
let city = self.guest[i]["city"] as? String
let state = self.guest[i]["state"] as? String
self.tableView.reloadData()
} catch {
DispatchQueue.main.async(execute: {
let message = "\(error)"
appDelegate.infoView(message: message, color: colorSmoothRed)
})
return
}
} else {
DispatchQueue.main.async(execute: {
let message = error!.localizedDescription
appDelegate.infoView(message: message, color: colorSmoothRed)
})
return
}
})
} .resume()
}
// custom body of HTTP request to upload image file
func createBodyWithParams(_ parameters: [String: String]?, boundary: String) -> Data {
let body = NSMutableData();
if parameters != nil {
for (key, value) in parameters! {
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString("\(value)\r\n")
}
}
return body as Data
}
func insertShot(_ rating : String) {
self.tableView.reloadData()
let reviewer = user?["username"] as! String
// url path to php file
let url = URL(string: "http://www.xxxxxx.com/xxxxxxx.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// param to be passed to php file
let param = [
"user" : reviewer,
"revieweduser" : cell?.guestusername.text,
"rating" : rating
] as [String : Any]
// body
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
// ... body
request.httpBody = createBodyWithParams(param as? [String : String], boundary: boundary)
// launch session
URLSession.shared.dataTask(with: request) { data, response, error in
// get main queu to communicate back to user
DispatchQueue.main.async(execute: {
if error == nil {
do {
// json containes $returnArray from php
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
// declare new var to store json inf
guard let parseJSON = json else {
print("Error while parsing")
return
}
// get message from $returnArray["message"]
let message = parseJSON["message"]
//print(message)
// if there is some message - post is made
if message != nil {
// reset UI
// self.msgTxt.text = ""
// switch to another scene
//self.tabBarController?.selectedIndex = 3
_ = self.navigationController?.popViewController(animated: true)
}
} catch {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = "\(error)"
appDelegate.infoView(message: message, color: colorSmoothRed)
})
return
}
} else {
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = error!.localizedDescription
appDelegate.infoView(message: message, color: colorSmoothRed)
})
return
}
})
}.resume()
return
}
#IBAction func yesBtn_clicked(_ sender: UIButton) {
self.insertShot("Yes")
}
#IBAction func noBtn_clicked(_ sender: UIButton) {
self.insertShot("No")
}
}

Getting Hash Mismatch in pay u money Swift 3

Im New to Swift and I'm Integrating PayUmoney IOS SDK in swift, Im getting trouble When I'm doing in live its showing hash mismatch (Hash mismatch1) If I'm doing in test its showing invalid merchant key (Invalid key) I struck here from 2 weeks Did so many things and didn't get any solution for this can any one help it would be awesome. Below is my code, Thank you in Advance.
var params : PUMRequestParams = PUMRequestParams.shared()
var utils : Utils = Utils()
params.environment = PUMEnvironment.test;
params.firstname = txtFldName.text;
params.key = "bZf4AOjj";
params.merchantid = "5745303";
params.logo_url = "";
params.productinfo = "Product Info";
params.email = txtFldEmail.text;
params.phone = "";
params.surl = "https://www.payumoney.com/mobileapp/payumoney/success.php";
params.furl = "https://www.payumoney.com/mobileapp/payumoney/failure.php";
if(params.environment == PUMEnvironment.test){
generateHashForProdAndNavigateToSDK()
}
else{
calculateHashFromServer()
}
// assign delegate for payment callback.
params.delegate = self;
}
func generateHashForProdAndNavigateToSDK() -> Void {
let txnid = params.txnid!
let hashSequence : NSString = "\(params.key)|\(txnid)|\(params.amount)|\(params.productinfo)|\(params.firstname)|\(params.email)|||||||||||2uIsGhXWVw" as NSString
let data :NSString = utils.createSHA512(hashSequence as String!) as NSString
params.hashValue = data as String!;
startPaymentFlow();
}
// MARK:HASH CALCULATION
func prepareHashBody()->NSString{
return "SHA-512key=\(params.key!)&amount=\(params.amount!)&txnid=\(params.txnid!)&productinfo=\(params.productinfo!)&email=\(params.email!)&firstname=\(params.firstname!)" as NSString;
}
func calculateHashFromServer(){
let config = URLSessionConfiguration.default // Session Configuration
let session = URLSession(configuration: config) // Load configuration into Session
let url = URL(string: "https://test.payumoney.com/payment/op/v1/calculateHashForTest")!
var request = URLRequest(url: url)
request.httpBody = prepareHashBody().data(using: String.Encoding.utf8.rawValue)
request.httpMethod = "POST"
let task = session.dataTask(with: request, completionHandler: {
(data, response, error) in
if error != nil {
print(error!.localizedDescription)
} else {
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]{
print(json)
let status : NSNumber = json["status"] as! NSNumber
if(status.intValue == 0)
{
self.params.hashValue = json["result"] as! String!
OperationQueue.main.addOperation {
self.startPaymentFlow()
}
}
else{
OperationQueue.main.addOperation {
self.showAlertViewWithTitle(title: "Message", message: json["message"] as! String)
}
}
}
} catch {
print("error in JSONSerialization")
}
}
})
task.resume()
}
Hello Vinny do with webview its working for me. Before I also used this PayUmoney IOS SDK but faced so many problems so based on objective-c I did this so I think its useful to you. create a weak var webview and create class UIwebviewdelegate
class PayumoneyViewController: UIViewController, UIWebViewDelegate, UIAlertViewDelegate {
#IBOutlet weak var Webview: UIWebView!
and for test use below credentials
//test
var merchantKey = "40747T"
var salt = "ur salt"
var PayUBaseUrl = "https://test.payu.in"
For live
//Production
var merchantKey = “xxxxxx”
var salt = “xxxxx”
var PayUBaseUrl = "https://secure.payu.in"
let productInfo = “Myapp” //It can be Project name or anything else
let firstName = “Santoshi” //Details of user whose is purchasing order
let email = “santoshi#app.com" //Details of user whose is purchasing order
let phone = "xxxxxxxxx" //Details of user whose is purchasing order
let sUrl = "www.google.com" //By this URL we match whether payment got success or failure
let fUrl = "www.google.com" //By this URL we match whether payment got success or failure
let service_provider = "payu_paisa"
var txnid1: String! = "" //Its an unique id which can give order a specific order number.
let totalPriceAmount = "1.0"
Above viewdidload do like this
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
initPayment()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
}
In viewdidload do like this
override func viewDidLoad() {
super.viewDidLoad()
Webview.delegate = self
// Do any additional setup after loading the view.
}
Create payment and Generate Hash key
func initPayment() {
txnid1 = “Myapp\(String(Int(NSDate().timeIntervalSince1970)))"
//Generating Hash Key
let hashValue = String.localizedStringWithFormat("%#|%#|%#|%#|%#|%#|||||||||||%#",merchantKey,txnid1,totalPriceAmount,productInfo,firstName,email,salt)
let hash = self.sha1(string: hashValue)
let postStr = "txnid="+txnid1+"&key="+merchantKey+"&amount="+totalPriceAmount+"&productinfo="+productInfo+"&firstname="+firstName+"&email="+email+"&phone="+phone+"&surl="+sUrl+"&furl="+fUrl+"&hash="+hash+"&service_provider="+service_provider
let url = NSURL(string: String.localizedStringWithFormat("%#/_payment", PayUBaseUrl))
let request = NSMutableURLRequest(url: url! as URL)
do {
let postLength = String.localizedStringWithFormat("%lu",postStr.characters.count)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Current-Type")
request.setValue(postLength, forHTTPHeaderField: "Content-Length")
request.httpBody = postStr.data(using: String.Encoding.utf8)
Webview.loadRequest(request as URLRequest)
}
catch let error as NSError
{
print(error)
}
}
Finally Do this
func sha1(string:String) -> String {
let cstr = string.cString(using: String.Encoding.utf8)
let data = NSData(bytes: cstr, length: string.characters.count)
var digest = [UInt8](repeating: 0, count:Int(CC_SHA512_DIGEST_LENGTH))
CC_SHA512(data.bytes, CC_LONG(data.length), &digest)
let hexBytes = digest.map { String(format: "%02x", $0) }
return hexBytes.joined(separator: "")
}
func webViewDidFinishLoad(_ webView: UIWebView) {
let requestURL = self.Webview.request?.url
let requestString:String = (requestURL?.absoluteString)!
if requestString.contains("https://www.payumoney.com/mobileapp/payumoney/success.php") {
print("success payment done")
}else if requestString.contains("https://www.payumoney.com/mobileapp/payumoney/failure.php") {
print("payment failure")
}
}
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
let requestURL = self.Webview.request?.url
print("WebView failed loading with requestURL: \(requestURL) with error: \(error.localizedDescription) & error code: \(error)")
if error._code == -1009 || error._code == -1003 {
showAlertView(userMessage: "Please check your internet connection!")
}else if error._code == -1001 {
showAlertView(userMessage: "The request timed out.")
}
}
func showAlertView(userMessage:String){
}
I have Faced Same problem and i have got solution of this problem.
In my code this line generate optional values --> let hashSequence : NSString = "(params.key!)|(txnid)|(params.amount!)|(params.productinfo!)|(params.firstname!)|(params.email!)|||||||||||(params.merchantid!)" as NSString
remove optional from the values.

OAuth2, Swift 3, Instagram

There seem to be lots of changes at IG. Many OAuth2 repos, all seem to have bugs, or really not easily converted to Swift3. Wondering if anyone has a solution for moving to Swift3 and working with the latest changes at Instagram?
Solutions most welcome. OAuth2 implementation seems to one of the more complicated things out there. Surprised that IG has not offered their own example docs on how to do this with iOS. They only have docs for web based solutions.
Maybe something brewing there? Zillions of coders they have on staff. But for now, on the hunt for a (dare I say?) simple solution.
thanks a million. :-)
For Swift 3:
Update: April 17 2017: Because of broken dependencies, the installation by Pods is no longer working. Therefore I have ripped the needed content and created a new Github project using a Bridging Header and stored all the needed files within the project. If you clone or download the github project, you'll instantly be able to login to Instagram.
To use those files in your project, simply drag and drop all the files from the SimpleAuth folder to your project, make sure to mark copy item if needed
Also you need to disable Disable implicit oAuth within the Instagram developer console.
Then you either copy/paste my code from the Bridging Header into your or you use mine. Set the Bridging Header at the Target's Build Settings.
Everything else works as before:
I have a struct for the Instagram Account:
struct InstagramUser {
var token: String = ""
var uid: String = ""
var bio: String = ""
var followed_by: String = ""
var follows: String = ""
var media: String = ""
var username: String = ""
var image: String = ""
}
The function to receive the token:
typealias JSONDictionary = [String:Any]
var user: InstagramUser?
let INSTAGRAM_CLIENT_ID = "16ee14XXXXXXXXXXXXXXXXXXXXXXXXX"
let INSTAGRAM_REDIRECT_URI = "http://www.davidseek.com/just_a_made_up_dummy_url" //just important, that it matches your developer account uri at Instagram
extension ViewController {
func connectInstagram() {
let auth: NSMutableDictionary = ["client_id": INSTAGRAM_CLIENT_ID,
SimpleAuthRedirectURIKey: INSTAGRAM_REDIRECT_URI]
SimpleAuth.configuration()["instagram"] = auth
SimpleAuth.authorize("instagram", options: [:]) { (result: Any?, error: Error?) -> Void in
if let result = result as? JSONDictionary {
var token = ""
var uid = ""
var bio = ""
var followed_by = ""
var follows = ""
var media = ""
var username = ""
var image = ""
token = (result["credentials"] as! JSONDictionary)["token"] as! String
uid = result["uid"] as! String
if let extra = result["extra"] as? JSONDictionary,
let rawInfo = extra ["raw_info"] as? JSONDictionary,
let data = rawInfo["data"] as? JSONDictionary {
bio = data["bio"] as! String
if let counts = data["counts"] as? JSONDictionary {
followed_by = String(describing: counts["followed_by"]!)
follows = String(describing: counts["follows"]!)
media = String(describing: counts["media"]!)
}
}
if let userInfo = result["user_info"] as? JSONDictionary {
username = userInfo["username"] as! String
image = userInfo["image"] as! String
}
self.user = InstagramUser(token: token, uid: uid, bio: bio, followed_by: followed_by, follows: follows, media: media, username: username, image: image)
} else {
// this handles if user aborts or the API has a problem like server issue
let alert = UIAlertController(title: "Error!", message: nil, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
if error != nil {
print("Error during SimpleAuth.authorize: \(error)")
}
}
}
}
Instagram also says:
Important
Even though our access tokens do not specify an expiration time, your
app should handle the case that either the user revokes access, or
Instagram expires the token after some period of time. If the token is
no longer valid, API responses will contain an
“error_type=OAuthAccessTokenException”. In this case you will need to
re-authenticate the user to obtain a new valid token. In other words:
do not assume your access_token is valid forever.
So handle the case of receiving the OAuthAccessTokenException
This Code bellow I use for facebook and google+, I think it'ill work for Instagram too, maybe some adjusts.
import UIKit
class Signup: UIViewController, UIWebViewDelegate {
let GOOGLE_ID = "xxxxxx.apps.googleusercontent.com"
let GOOGLE_SECRET = "xxxxxxx";
let GOOGLE_REDIRECT_URI="http://yourdomain.com/api/account/googlecallback"
let GOOGLE_TOKEN_URL = "https://accounts.google.com/o/oauth2/token";
let GOOGLE_OAUTH_URL = "https://accounts.google.com/o/oauth2/auth";
let GOOGLE_OAUTH_SCOPE = "profile email";
let GOOGLE_GET_PROFILE = "https://www.googleapis.com/userinfo/v2/me";
let FACEBOOK_ID = "xxxxx";
let FACEBOOK_REDIRECT_URI = "http://yourdomain.com/api/account/facebookcallback";
let FACEBOOK_OAUTH_URL = "https://www.facebook.com/dialog/oauth?client_id=";
let FACEBOOK_OAUTH_SCOPE = "public_profile,email"
let FACEBOOK_GET_PROFILE = "https://graph.facebook.com/me?access_token="
var currentURL: String = ""
var queryString: String = ""
var receivedToken: String = ""
var authCode: String = ""
var authComplete = false
var webV:UIWebView = UIWebView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
#IBAction func google(_ sender: AnyObject) {
AppVars.Provider = "Google"
webV.delegate = self
let url = GOOGLE_OAUTH_URL + "?redirect_uri=" + GOOGLE_REDIRECT_URI + "&response_type=code&client_id=" + GOOGLE_ID + "&scope=" + GOOGLE_OAUTH_SCOPE
let urlString :String = url.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
webV.loadRequest(URLRequest(url: URL(string:urlString)!))
self.view.addSubview(webV)
}
#IBAction func facebook(_ sender: AnyObject) {
AppVars.Provider = "Facebook"
webV.delegate = self
let url = FACEBOOK_OAUTH_URL + FACEBOOK_ID + "&redirect_uri=" + FACEBOOK_REDIRECT_URI + "&scope=" + FACEBOOK_OAUTH_SCOPE + "&display=popup&response_type=token"
let urlString :String = url.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
webV.loadRequest(URLRequest(url: URL(string:urlString)!))
self.view.addSubview(webV)
}
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
self.showAlert(self, message: "Internet is not working")
}
func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
return true;
}
func webViewDidStartLoad(_ webView: UIWebView) {
}
func webViewDidFinishLoad(_ webView: UIWebView) {
currentURL = (webView.request?.url!.absoluteString)!
if AppVars.Provider == "Google" {
googleSignup((webView.request?.url!)!)
} else {
facebookSignup((webView.request?.url!)!)
}
}
func googleSignup (_ returnCode: URL) {
let url = String(currentURL)
if (url?.range(of: "?code=") != nil && authComplete != true) {
authCode = getQueryItemValueForKey("code", url: returnCode)!
authComplete = true
let paramString = "code=" + authCode + "&client_id=" + GOOGLE_ID + "&client_secret=" +
GOOGLE_SECRET + "&redirect_uri=" + GOOGLE_REDIRECT_URI + "&grant_type=authorization_code"
self.requestServer(urlSource: GOOGLE_TOKEN_URL, params: paramString, requestType: "POST") { (dataResult, errorResult) -> () in
if errorResult != nil {
self.showAlert(self, message: "Internet is not working")
} else {
let dataString:NSString = NSString(data: dataResult as! Data, encoding: String.Encoding.utf8.rawValue)!
let dataResult2 = dataString.data(using: String.Encoding.utf8.rawValue, allowLossyConversion: false)!
do {
let jsonDict = try JSONSerialization.jsonObject(with: dataResult2, options: .allowFragments) as! [String:Any]
if let token = jsonDict["access_token"] as? String {
self.requestServerSignup(self.GOOGLE_GET_PROFILE, param: token, requestType: "GET") { (dataResult, errorResult) -> () in
if errorResult != nil {
self.showAlert(self, message: "Internet is not working")
} else {
let dataString:NSString = NSString(data: dataResult as! Data, encoding: String.Encoding.utf8.rawValue)!
let dataResult2 = dataString.data(using: String.Encoding.utf8.rawValue, allowLossyConversion: false)!
do {
let jsonDict = try JSONSerialization.jsonObject(with: dataResult2, options: .allowFragments) as! [String:Any]
if let name = jsonDict["name"] as? String {
AppVars.NameLogin = name
AppVars.PictureLogin = jsonDict["picture"] as! String
AppVars.EmailLogin = jsonDict["email"] as! String
self.performSegue(withIdentifier: "externalLoginSegue", sender: self)
// show picture, email and name for checking profile
}
} catch {
self.showAlert(self, message: "Internet is not working")
}
}
}
}
} catch {
self.showAlert(self, message: "Internet is not working")
}
}
}
self.webV.removeFromSuperview()
}
}
func facebookSignup(_ returnCode: URL) {
let url = String(currentURL)
if (url?.range(of: "access_token=") != nil && authComplete != true) {
let url2: String = returnCode.absoluteString.replacingOccurrences(of: "#access_token", with: "access_token")
let url3: URL = URL(string: url2)!
authCode = getQueryItemValueForKey("access_token", url: (url3))!
authComplete = true
let paramString = "code=" + authCode + "&client_id=" + GOOGLE_ID + "&client_secret=" +
GOOGLE_SECRET + "&redirect_uri=" + GOOGLE_REDIRECT_URI + "&grant_type=authorization_code"
self.requestServer(urlSource: self.FACEBOOK_GET_PROFILE + authCode + "&fields=name,picture,email", params: paramString, requestType: "GET") { (dataResult, errorResult) -> () in
if errorResult != nil {
self.showAlert(self, message: "Internet is not working")
} else {
let dataString:NSString = NSString(data: dataResult as! Data, encoding: String.Encoding.utf8.rawValue)!
let dataResult2 = dataString.data(using: String.Encoding.utf8.rawValue, allowLossyConversion: false)!
do {
let jsonDict = try JSONSerialization.jsonObject(with: dataResult2, options: .allowFragments) as! [String:Any]
if let name = jsonDict["name"] as? String {
AppVars.NameLogin = name
if let picture = jsonDict["picture"] as? [String:Any] {
if let dataPicture = picture["data"] as? [String:Any] {
if let url = dataPicture["url"] as? String {
AppVars.PictureLogin = url
}
}
}
AppVars.EmailLogin = jsonDict["email"] as! String
self.performSegue(withIdentifier: "externalLoginSegue", sender: self)
// show picture, email and name for checking profile
}
} catch {
self.showAlert(self, message: "Internet is not working")
}
}
}
self.webV.removeFromSuperview()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getQueryItemValueForKey(_ key: String, url: URL) -> String? {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
return nil
}
guard let queryItems = components.queryItems else { return nil }
return queryItems.filter {
$0.name == key
}.first?.value
}
func requestServer(urlSource:String, params:String, requestType:String, result:#escaping (_ dataResult:NSData?, _ errorResult:NSError?) -> ()) {
let url: URL = URL(string: urlSource)!
var request = URLRequest(url:url)
request.httpMethod = requestType
request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
if params.characters.count > 0 {
request.httpBody = params.data(using: String.Encoding.utf8)
}
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
if error == nil {
result(data as NSData?, nil)
} else {
result(nil, error as NSError?)
}
})
}.resume()
}
}

Resources