Apps Script API errors on given ViewController - ios

Has anyone gone through this API and has figured it out?
This is my third time trying to get this to work by following this guide
I am using the swift version of this guide.
Google Apps Script Guide
And it always give me the same errors.
import UIKit
class ViewController: UIViewController {
private let kKeychainItemName = "Google Apps Script Execution API"
private let kClientID = "493692471278-3mf6bo212flgjopl06hrjfeepphe70h4.apps.googleusercontent.com"
private let kScriptId = "Mj0RNm2ZtohFurieBLPwnxYAb4Jnnku4P"
// If modifying these scopes, delete your previously saved credentials by
// resetting the iOS simulator or uninstall the app.
private let scopes = ["https://www.googleapis.com/auth/drive"]
private let service = GTLService() // error Use of unresolved identifier 'GTLService'
let output = UITextView()
// When the view loads, create necessary subviews
// and initialize the Google Apps Script Execution API service
override func viewDidLoad() {
super.viewDidLoad()
output.frame = view.bounds
output.editable = false
output.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 20, right: 0)
output.autoresizingMask = UIViewAutoresizing.FlexibleHeight |
UIViewAutoresizing.FlexibleWidth
// error*** Binary operator '|' cannot be applied to two 'UIViewAutoresizing' operands
view.addSubview(output);
// Error**Use of unresolved identifier 'GTMOAuth2ViewControllerTouch'
if let auth = GTMOAuth2ViewControllerTouch.authForGoogleFromKeychainForName(
kKeychainItemName,
clientID: kClientID,
clientSecret: nil) {
service.authorizer = auth
}
}
// When the view appears, ensure that the Google Apps Script Execution API service is authorized
// and perform API calls
override func viewDidAppear(animated: Bool) {
if let authorizer = service.authorizer,
canAuth = authorizer.canAuthorize where canAuth {
callAppsScript()
} else {
presentViewController(
createAuthController(),
animated: true,
completion: nil
)
}
}
// Calls an Apps Script function to list the folders in the user's
// root Drive folder.
func callAppsScript() {
output.text = "Getting folders..."
let baseUrl = "https://script.googleapis.com/v1/scripts/\(kScriptId):run"
let url = GTLUtilities.URLWithString(baseUrl, queryParameters: nil)
// error ** Use of unresolved identifier 'GTLUtilities'
// Create an execution request object.
var request = GTLObject()
// Error** Use of unresolved identifier 'GTLObject'
request.setJSONValue("getFoldersUnderRoot", forKey: "function")
// Make the API request.
service.fetchObjectByInsertingObject(request,
forURL: url,
delegate: self,
didFinishSelector: "displayResultWithTicket:finishedWithObject:error:")
}
// Displays the retrieved folders returned by the Apps Script function.
func displayResultWithTicket(ticket: GTLServiceTicket,
finishedWithObject object : GTLObject,
error : NSError?) {
if let error = error {
// The API encountered a problem before the script
// started executing.
showAlert("The API returned the error: ",
message: error.localizedDescription)
return
}
if let apiError = object.JSON["error"] as? [String: AnyObject] {
// The API executed, but the script returned an error.
// Extract the first (and only) set of error details and cast as
// a Dictionary. The values of this Dictionary are the script's
// 'errorMessage' and 'errorType', and an array of stack trace
// elements (which also need to be cast as Dictionaries).
let details = apiError["details"] as! [[String: AnyObject]]
var errMessage = String(
format:"Script error message: %#\n",
details[0]["errorMessage"] as! String)
if let stacktrace =
details[0]["scriptStackTraceElements"] as? [[String: AnyObject]] {
// There may not be a stacktrace if the script didn't start
// executing.
for trace in stacktrace {
let f = trace["function"] as? String ?? "Unknown"
let num = trace["lineNumber"] as? Int ?? -1
errMessage += "\t\(f): \(num)\n"
}
}
// Set the output as the compiled error message.
output.text = errMessage
} else {
// The result provided by the API needs to be cast into the
// correct type, based upon what types the Apps Script function
// returns. Here, the function returns an Apps Script Object with
// String keys and values, so must be cast into a Dictionary
// (folderSet).
let response = object.JSON["response"] as! [String: AnyObject]
let folderSet = response["result"] as! [String: AnyObject]
if folderSet.count == 0 {
output.text = "No folders returned!\n"
} else {
var folderString = "Folders under your root folder:\n"
for (id, folder) in folderSet {
folderString += "\t\(folder) (\(id))\n"
}
output.text = folderString
}
}
}
// Creates the auth controller for authorizing access to Google Apps Script Execution API
private func createAuthController() -> GTMOAuth2ViewControllerTouch {
// Error** Use of undeclared type 'GTLServiceTicket' let scopeString = " ".join(scopes) // Error* 'join' is unavailable: call the 'joinWithSeparator()' method on the sequence of elements
return GTMOAuth2ViewControllerTouch(
scope: scopeString,
clientID: kClientID,
clientSecret: nil,
keychainItemName: kKeychainItemName,
delegate: self,
finishedSelector: "viewController:finishedWithAuth:error:"
)
}
// Handle completion of the authorization process, and update the Google Apps Script Execution API
// with the new credentials.
func viewController(vc : UIViewController,
finishedWithAuth authResult : GTMOAuth2Authentication, error : NSError?)
// Error** Use of undeclared type 'GTMOAuth2Authentication' {
if let error = error {
service.authorizer = nil
showAlert("Authentication Error", message: error.localizedDescription)
return
}
service.authorizer = authResult
dismissViewControllerAnimated(true, completion: nil)
}
// Helper for showing an alert
func showAlert(title : String, message: String) {
let alert = UIAlertView(
title: title,
message: message,
delegate: nil,
cancelButtonTitle: "OK"
)
alert.show()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I find it hard to believe that google would make a guide and have it not work for the current version of xcode. It even says at the bottom of their guide that it was last updated February 2016.
Wanted to see if anyone has had any luck with following this guide in the past.
is there another swift guide for this google API?
Thank you in advance.

1)Looks like you aren't getting the header files. You need a Bridging-Header.h. That step is omitted from the Quickstart; see the Google Drive Quickstart for the step you need to take.
2)You can just comment out the following line, it doesn't seem to be necessary.
output.autoresizingMask = UIViewAutoresizing.FlexibleHeight |
UIViewAutoresizing.FlexibleWidth
3)Those changes will fix the compile problems. I found that after fixing the compile problems, it would not link and run on a phone.
The Quickstart guide has you link the GTL.framework with your app using Xcode's 'Link Binary with Libraries'. I instead installed it using Cocoapods (https://cocoapods.org/pods/Google-API-Client) and was then able to run my app.

Related

How to resolve totally app freeze after DocuSign login

My app totally freeze after successful login to DocuSign
Here my code:
#IBAction private func signDocument(_ sender: UIButton) {
guard let hostURL = URL(string: Environment.current.docuSignHost) else { return }
isLoading = true
DSMManager.login(withEmail: Environment.current.docuSignUserID,
password: Environment.current.docuSignPass,
integratorKey: Environment.current.docuSignIntegratorKey,
host: hostURL) { [weak self] info, error in
self?.isLoading = false
if let error = error {
self?.error = error
} else {
self?.showDocuSign(info: info)
}
}
}
// MARK: - Helpers
private func showDocuSign(info: DSMAccountInfo?) {
guard let info = info else { return }
envelopManager.perform(with: info, presentingController: self)
}
final class EnvelopeManager {
private let envelopesManager = DSMEnvelopesManager()
private let templateManager = DSMTemplatesManager()
// MARK: - Lifecycle
func sync() {
envelopesManager.syncEnvelopes()
}
func perform(with config: DSMAccountInfo, presentingController: UIViewController) {
guard let path = Bundle.main.path(forResource: R.file.tgkCapitalPortfolioBAgreementPdf.name, ofType: "pdf") else { return }
let envelopDefinition = DSMEnvelopeDefinition()
envelopDefinition.envelopeName = "Some name"
envelopDefinition.emailSubject = "Please Sign Envelope on Document"
envelopDefinition.emailBlurb = "Hello, Please sign my Envelope"
let builder = DSMDocumentBuilder()
builder.addDocumentId("1")
builder.addName(R.file.tgkCapitalPortfolioBAgreementPdf.name)
builder.addFilePath(Bundle.main.path(forResource: R.file.tgkCapitalPortfolioBAgreementPdf.name,
ofType: "pdf")!)
let document = builder.build()
envelopDefinition.documents = [document]
let signHere = DSMSignHere()
signHere.documentId = document.documentId
signHere.pageNumber = 1
signHere.recipientId = "1"
signHere.frame = .init(originX: 100,
originY: 100,
width: 100,
height: 100,
originYOffsetApplied: 50)
signHere.tabId = "1"
let tabs = DSMTabs()
tabs.signHereTabs = [signHere]
let signer = DSMSigner()
signer.email = config.email
signer.name = config.userName
signer.userId = config.userId
signer.clientUserId = config.userId
signer.routingOrder = 1
signer.recipientId = "1"
signer.tabs = tabs
let signers: [DSMSigner] = [signer]
let recipients = DSMRecipients()
recipients.signers = signers
envelopDefinition.recipients = recipients
envelopDefinition.status = "created"
envelopesManager.composeEnvelope(with: envelopDefinition, signingMode: .offline) { [weak self] envelopID, error in
if let envelopID = envelopID {
print(envelopID)
self?.presentSigning(presenter: presentingController,
envelopeID: envelopID)
} else {
print(error.localizedDescription)
}
}
}
private func presentSigning(presenter: UIViewController, envelopeID: String) {
envelopesManager.resumeSigningEnvelope(withPresenting: presenter,
envelopeId: envelopeID) { (viewController, error) in
if let viewController = viewController {
print(viewController)
}
if let error = error {
print(error.localizedDescription)
}
}
}
}
All closures have a success status but the app freezes and any DocuSign view controllers are not showing.
But if in the second attempt I add the calling the logout before login - all works as expected
#IBAction private func signDocument(_ sender: UIButton) {
guard let hostURL = URL(string: Environment.current.docuSignHost) else { return }
isLoading = true
DSMManager.logout()
DSMManager.login(withEmail: Environment.current.docuSignUserID,
password: Environment.current.docuSignPass,
integratorKey: Environment.current.docuSignIntegratorKey,
host: hostURL) { [weak self] info, error in
self?.isLoading = false
if let error = error {
self?.error = error
} else {
self?.showDocuSign(info: info)
}
}
}
How to resolve this issue? How to make that my app will not freeze after any successful login?
Edit1
I have figured out that the total app freeze is occurring by the first app install. When I open an app that was already installed and I many times opened it earlier and go to DocuSign flow, call logout and finally call login- all works as expected - I don't have any app freeze. But if I don't call the logout method in this chain then my app freezes.
The problem was consistent in that DSMManager.setup() called earlier than applicationDidLaunch. After I moved it to applicationDidLaunch the problem was resolved
Thanks for posting the solution #igdev.
Yes, correct sequence to perform SDK setup is during applicationDidLaunch or afterwards, say during viewDidLoad() of any of the viewControllers (lazy sdk setup & initialization). As long as setup() is done prior to any of the sdk-calls such as login(withAccessToken:...) or cacheEnvelope(...). DocuSign SDK setup() establishes the core data and other essential components required for its functionality.
Typical sequence of calls made with DocuSign SDK.
Application Launch
Initialize DocuSign SDK with DocuSignSDK setup()
Login with DocuSignSDK login(with...). Login could be skipped if a prior SDK session is already established, for e.g. when getting signatures in offline-envelopes using downloaded templates.
Accessing TemplatesManager or EnvelopesManager functionality [Download templates, Sign Envelopes, Sync offline envelopes, etc] and other tasks such as handling DocuSign-SDK notifications to track events (e.g. Signing Completed Envelope Cached, etc).
Logout, it's not required, if needed can perform DSMManager.logout() when client user is logged out.

I tried to connect and fetch mails using mailcore2 in iOS. But I got error

Error Domain=MCOErrorDomain Code=5 "Unable to authenticate with the current session's credentials." UserInfo={NSLocalizedDescription=Unable to authenticate with the current session's credentials.}
I put this code in my project.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
prepareImapSession()
}
var imapsession:MCOIMAPSession = MCOIMAPSession()
var error : Error? = nil
func prepareImapSession()
{
// CONFIGURE THAT DEPENDING OF YOUR NEEDS
imapsession.hostname = "imap.gmail.com" // String
imapsession.username = my email // String
imapsession.password = password // String
imapsession.port = 993 // UInt32 number
imapsession.authType = MCOAuthType.saslLogin
imapsession.connectionType = MCOConnectionType.TLS
DispatchQueue.main.asyncAfter(deadline: .now() + 8) { [self] in
self.useImapWithUIDS()
}
imapsession.connectOperation()
}
func useImapWithUIDS() {
// There is more than one option here, explore depending of your needs
// let kind = MCOIMAPMessagesRequestKind()
// let headers = kind.union(MCOIMAPMessagesRequestKind.headers)
// let request = headers.union(MCOIMAPMessagesRequestKind.flags)
let requestKind: MCOIMAPMessagesRequestKind = [.headers, .flags]
let folder : String = "INBOX"
// HERE ALSO EXPLORE DEPENDING OF YOUR NEEDS, RANGE IT IS THE RANGE OF THE UIDS THAT YOU WANT TO FETCH, I SUGGEST TO YOU TO CHANGE THE // NUMBER ONE IF YOU HAVE A LOWER BOUND TO FETCH EMAIL
let uids : MCOIndexSet = MCOIndexSet(range: MCORangeMake(1, UINT64_MAX))
let fetchOperation = imapsession.fetchMessagesOperation(withFolder: folder, requestKind: requestKind, uids: uids)
fetchOperation?.start
{ [self] (err, msg, vanished) -> Void in
if (err != nil)
{
self.error = err
NSLog((err?.localizedDescription)!)
}
else
{
guard let msgs = msg as? [MCOIMAPMessage]
else
{
print("ERROR GETTING THE MAILS")
return
}
for i in 0..<msgs.count
{
// THE SUBJECT
let subject = msgs[i].header.subject
// THE uid for this email. The uid is unique for one email
let uid = msgs[i].uid
self.useImapFetchContent(uidToFetch: uid)
// The sequenceNumber like the nomber say it is the sequence for the emails in the INBOX from the first one // (sequenceNumber = 1) to the last one , it not represent always the same email. Because if you delete one email then //next one will get the sequence number of that email that was deleted
let sequenceNumber = msgs[i].sequenceNumber
}
}
}
}
// MARK: - EXTRACT THE CONTENT OF ONE EMAIL, IN THIS FUNCTION YOU NEED THE uid, THE UNIQUE NUMBER FOR ONE EMAIL
func useImapFetchContent(uidToFetch uid: UInt32) {
let operation: MCOIMAPFetchContentOperation = imapsession.fetchMessageOperation(withFolder: "INBOX", uid: uid)
operation.start { (Error, data) in
if (Error != nil)
{
NSLog("ERROR")
return
}
let messageParser: MCOMessageParser = MCOMessageParser(data: data)
// IF YOU HAVE ATTACHMENTS USE THIS
let attachments = messageParser.attachments() as? [MCOAttachment]
// THEN YOU NEED THIS PROPERTIE, IN THIS EXAMPLE I TAKE THI FIRST, USE WHAT EVER YOU WANT
let attachData = attachments?.first?.data
// FOR THE MESSAGEPARSER YOU CAN EPLORE MORE THAN ONE OPTION TO OBTAIN THE TEXT
let msgPlainBody = messageParser.plainTextBodyRendering()
}
}
}
I using the mailcore2 framework. I got error description Unable to authenticate with the current session's credentials.
It can be related with 2nd factor authentication on your account. It was described on Apple forum.

How to integrate Paytm payment gateway in Swift

I have checked all the tutorial and also did a lot of R & D on gateway integration.
But didn't find a way to integrate paytm payment gateway.
func paymentConfiguration()
{
var orderDict = [AnyHashable: Any]()
orderDict["MID"] = "WorldP64425807474247"
orderDict["CHANNEL_ID"] = "WAP"
orderDict["INDUSTRY_TYPE_ID"] = "Retail"
orderDict["WEBSITE"] = "worldpressplg"
orderDict["TXN_AMOUNT"] = "1"
orderDict["ORDER_ID"] = ViewController.generateOrderID(withPrefix: "")
orderDict["CALLBACK_URL"] = "https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=<ORDER_ID>"
orderDict["CHECKSUMHASH"] = "w2QDRMgp1/BNdEnJEAPCIOmNgQvsi+BhpqijfM9KvFfRiPmGSt3Ddzw+oTaGCLneJwxFFq5mqTMwJXdQE2EzK4px2xruDqKZjHupz9yXev4="
orderDict["REQUEST_TYPE"] = "DEFAULT"
orderDict["CUST_ID"] = "1234567890"
var order = PGOrder(params: orderDict)
}
func openPaytmController()
{
PGServerEnvironment.selectServerDialog(view, completionHandler: {(_ type: ServerType) -> Void in
var txnController = PGTransactionViewController.initTransaction(forOrder: order)
if type != eServerTypeNone {
txnController.serverType = type
txnController.merchant = mc
txnController.delegate = self
self.show(txnController)
}
})
}
Any help would be greatly appreciated.
Thanks in advance
**
PayTM Integaration with swift with detail
**
##Download paytm sdk##
https://github.com/Paytm-Payments/Paytm_iOS_App_Kit
Make sure the dynamic lib and systemConfiguration.framwork is added in “Linked binaries and frameworks”
Add bridging header file into the project
#import "PaymentsSDK.h"
You have to generate CheckSumHash key - PayTm unique key for transaction purpose
Pass the below parameters to generate checkSumHash
let params:[String: Any] = [
"CUST_ID”:<Your Customer ID>, // you have to generate unique customer ID (Generate random string - less than 50 length count )
"TXN_AMOUNT":"10.00", // sample amount
“MID": <Your merchant ID>,
"ORDER_ID”:<Your Order ID>, // you have to generate unique order ID (Generate random string - less than 50 length count )
"INDUSTRY_TYPE_ID":"Retail", //Staging Environment
"CHANNEL_ID":"WAP", //Staging Environment
"WEBSITE":"APPSTAGING", //Staging Environment - Mobile
"CALLBACK_URL":"https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=\(<Your Order ID>)” // This should be important one and make sure the correct order ID.
]
In your server , You have to setUp the the file that should generate CheckSumHash key based on the given parameters and merchant key (Which is stored in the file; Don’t use inside your app ). That should be your CHECKSUM URL along with the above mentioned parameter. And finally, we get the CheckSumHash in the response
You have to given the above mentioned parameters along with checkSumHash (which you got the response - refer :step 3) to imitate PGTransactionViewCOntroller
let params:[String: Any] = [
"CUST_ID”:<Your Customer ID>, // you have to generate unique customer ID (Generate random string - less than 50 length count )
"TXN_AMOUNT":"10.00", // sample amount
“MID": <Your merchant ID>,
"ORDER_ID”:<Your Order ID>, // you have to generate unique order ID (Generate random string - less than 50 length count )
"INDUSTRY_TYPE_ID":"Retail", //Staging Environment
"CHANNEL_ID":"WAP", //Staging Environment
"WEBSITE":"APPSTAGING", //Staging Environment - Mobile
"CALLBACK_URL":"https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=\(<Your Order ID>)” // This should be important one and make sure the correct order ID. ,“CHECKSUMHASH”:<your geenrated CheckSumHash key> // which you got the response of generate CheckSumHash
]
let order = PGOrder(params: params)
let txnController = PGTransactionViewController(transactionFor: order)
txnController?.serverType = eServerTypeStaging
txnController?.merchant = PGMerchantConfiguration.default()
txnController?.merchant.checksumGenerationURL = CheckSumGenerationURL
txnController?.merchant.merchantID = "FlotaS90100524961231"
txnController?.merchant.checksumValidationURL = CheckSumVerifyURL + orderID
txnController?.loggingEnabled = true
txnController?.merchant.website = "APPSTAGING"
txnController?.merchant.industryID = "Retail"
txnController?.serverType = eServerTypeStaging
txnController?.delegate = self
self.navigationController?.pushViewController(txnController!, animated: true)
PayTM delegates to handle response
func didSucceedTransaction(controller: PGTransactionViewController, response: [NSObject : AnyObject]) {
print(response)
}
func didFinishedResponse(_ controller: PGTransactionViewController!, response responseString: String!) {
print(responseString) // Response will be in string
let data = responseString.data(using: .utf8)!
let obj = JSON(data: data)
if obj["STATUS"].stringValue != "TXN_SUCCESS" {
//handle what you want
}
}
}
func didFailTransaction(_ controller: PGTransactionViewController!, error: Error!, response: [AnyHashable : Any]!) {
print(error)
}
func didCancelTrasaction(_ controller: PGTransactionViewController!) {
print("User camcelled the trasaction")
controller.navigationController?.popViewController(animated: true)
}
func errorMisssingParameter(_ controller: PGTransactionViewController!, error: Error!) {
print(error.localizedDescription)
controller.navigationController?.popViewController(animated: true)
}
Try this code:
func showController(controller: PGTransactionViewController) {
if self.navigationController != nil {
self.navigationController?.pushViewController(controller, animated: true)
} else {
self.present(controller, animated: true, completion: nil)
}
}
func removeController(controller: PGTransactionViewController) {
if self.navigationController != nil {
self.navigationController?.popViewController(animated: true)
} else {
controller.dismiss(animated: true, completion: nil)
}
}
//Creat Payment----------------
func creatPayment(CheckSum: String) {
let mc = PGMerchantConfiguration.default()!
var orderDict = [String : Any]()
orderDict["MID"] = "WorldP64425807474247";
orderDict["ORDER_ID"] = ViewController.generateOrderID(withPrefix: "");
orderDict["CUST_ID"] = "1234567890";
orderDict["INDUSTRY_TYPE_ID"] = "Retail";
orderDict["CHANNEL_ID"] = "WAP";
orderDict["TXN_AMOUNT"] = self.FINAL_AMOUNT;
orderDict["WEBSITE"] = "APP_STAGING";
orderDict["CALLBACK_URL"] = "https://pguat.paytm.com/paytmchecksum/paytmCallback.jsp";
orderDict["CHECKSUMHASH"] = CheckSum;
let pgOrder = PGOrder(params: orderDict )
let transaction = PGTransactionViewController.init(transactionFor: pgOrder)
transaction!.serverType = eServerTypeStaging
transaction!.merchant = mc
transaction!.loggingEnabled = true
transaction!.delegate = self
self.showController(controller: transaction!)
}
func didFinishedResponse(_ controller: PGTransactionViewController!, response responseString: String!) {
print(responseString)
}
func didCancelTrasaction(_ controller: PGTransactionViewController!) {
print("CANCELLED")
}
func errorMisssingParameter(_ controller: PGTransactionViewController!, error: Error!) {
self.removeController(controller: controller)
print(error)
}
You have given the checksum as hardcore so, when the paytm decode your checksum and comapare with your parameters, the comparison will get fail. so you need to provide a new checksum when ever you make a payment.
The main thing you need to be care is that, the given parameters for checksum generation and payment setup should be same.
Checksum can be generated in the backend with the help of checksum generation kit provided by paytm
you should call the func creatPayment(CheckSum: String) in success of Generate checksumApi and give the checksum to the argument in the function
In Swift 5.0 Follow the following steps:-
1:- Follow these steps to download and import the library in your project:-
Download SDK from:-
https://github.com/Paytm-Payments/Paytm_iOS_App_Kit
Open your project in XCode and from the File menu, select Add files to
"your project"
Select Paytm.framework in the directory you just unzipped
Make sure 'Copy items if needed' is checked and click 'Add' Under
"Link Binary With Libraries" in the "Build Phases" tab of your
project settings, add SystemConfiguration.framework
Check if PaytmSDK.framework is added in both “Link Binary With
Libraries” and “Embedded Binaries”. If not, add by clicking on the plus icon.
Import PaytmSDK to ViewController
import PaymentSDK
Generate ChecksumHash
Security parameters to avoid tampering. Generated using server-side checksum utility provided by Paytm. Merchant has to ensure that this always gets generated on the server. Utilities to generate checksum hash is available
Add code on your payment ViewController to execute the payment process
var txnController = PGTransactionViewController()
var serv = PGServerEnvironment()
var params = [String:String]()
var order_ID:String?
var cust_ID:String?
func beginPayment() {
serv = serv.createStagingEnvironment()
let type :ServerType = .eServerTypeStaging
let order = PGOrder(orderID: "", customerID: "", amount: "", eMail: "", mobile: "")
order.params = ["MID": "rxazcv89315285244163",
"ORDER_ID": "order1",
"CUST_ID": "cust123",
"MOBILE_NO": "7777777777",
"EMAIL": "username#emailprovider.com",
"CHANNEL_ID": "WAP",
"WEBSITE": "WEBSTAGING",
"TXN_AMOUNT": "100.12",
"INDUSTRY_TYPE_ID": "Retail",
"CHECKSUMHASH": "oCDBVF+hvVb68JvzbKI40TOtcxlNjMdixi9FnRSh80Ub7XfjvgNr9NrfrOCPLmt65UhStCkrDnlYkclz1qE0uBMOrmuKLGlybuErulbLYSQ=",
"CALLBACK_URL": "https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=order1"]
self.txnController = self.txnController.initTransaction(for: order) as! PGTransactionViewController
self.txnController.title = "Paytm Payments"
self.txnController.setLoggingEnabled(true)
if(type != ServerType.eServerTypeNone) {
self.txnController.serverType = type;
} else {
return
}
self.txnController.merchant = PGMerchantConfiguration.defaultConfiguration()
self.txnController.delegate = self
self.navigationController?.pushViewController(self.txnController, animated: true)
}
Change "CHECKSUMHASH": value in params that comes from API
order.params["CHECKSUMHASH"] = checkSum // API checkSum value
confirm the protocol-delegate of ‘PGTransactionDelegate’ to Handle error and success responses
To handle success/errors on completion of payment, implement "didFinishedResponse", "didCancelTrasaction", "errorMisssingParameter" methods of the "PGTransactionDelegate". Code snippet provided below:-
extension PaymentViewController : PGTransactionDelegate {
//this function triggers when transaction gets finished
func didFinishedResponse(_ controller: PGTransactionViewController, response responseString: String) {
let msg : String = responseString
var titlemsg : String = ""
if let data = responseString.data(using: String.Encoding.utf8) {
do {
if let jsonresponse = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:Any] , jsonresponse.count > 0{
titlemsg = jsonresponse["STATUS"] as? String ?? ""
}
} catch {
debugLog("Something went wrong")
}
}
let actionSheetController: UIAlertController = UIAlertController(title: titlemsg , message: msg, preferredStyle: .alert)
let cancelAction : UIAlertAction = UIAlertAction(title: "OK", style: .cancel) {
action -> Void in
controller.navigationController?.popViewController(animated: true)
}
actionSheetController.addAction(cancelAction)
self.present(actionSheetController, animated: true, completion: nil)
}
//this function triggers when transaction gets cancelled
func didCancelTrasaction(_ controller : PGTransactionViewController) {
controller.navigationController?.popViewController(animated: true)
}
//Called when a required parameter is missing.
func errorMisssingParameter(_ controller : PGTransactionViewController, error : NSError?) {
controller.navigationController?.popViewController(animated: true)
}
}

Realm Sync swift example

Hi all im trying to create an ios app that sync data using Realm Object server
but there is something im missing
i installed corretly Realm object server on my server (remote)
i can access the dashboard correctly
i can login with Syncuser
but i have problem syncing data.. when i open the app i login the user but after that ( im unable to sync anyting )
i searched online for a full example but without success
any one can suggest a simple and easy example for use realm sync with swift?
Thanks
This is my actual implementation for a chat app using RealmSwift. I used a model object called Message defined below:
class Message: Object {
dynamic var userId = ""
dynamic var name = ""
dynamic var text = ""
dynamic var dateCreated = NSDate()
}
Next I used created a controller for sending and sync messages:
// Instance variables
var messages: Results<Message>!
var token: NotificationToken!
var configuration: Realm.Configuration!
override func viewDidLoad() {
super.viewDidLoad()
// Your viewDidLoad implementation
self.setupRealm()
}
Next the setup methods for Realm. As mentioned in Real Documentation, if a Realm has read-only permissions, then you must use the asyncOpen API as described in Asynchronously Opening Realms. Opening a read-only Realm without asyncOpen will cause an error.
private func setupRealm() {
let serverURL = URL(string: "http://your.server.ip:9080")!
let credentials = SyncCredentials.usernamePassword(username: "example#mail.com", password: "password")
SyncUser.logIn(with: credentials, server: serverURL) { user, error in
if let user = user {
let syncURL = URL(string: "realm://your.server.ip:9080/~/Message")!
let syncConfig = SyncConfiguration(user: user, realmURL: syncURL)
self.configuration = Realm.Configuration(syncConfiguration: syncConfig)
self.setupDataSource()
} else if let error = error {
// handle error
debugPrint("error: \(error.localizedDescription)")
}
}
}
private func setupDataSource() {
Realm.asyncOpen(configuration: self.configuration) { realm, error in
if let realm = realm {
// Realm successfully opened, with all remote data available
self.messages = realm.objects(Message.self).sorted(byKeyPath: "dateCreated", ascending: true)
self.token = self.messages.addNotificationBlock({ (changes: RealmCollectionChange) in
debugPrint("Message update event")
self.collectionView.reloadData()
})
} else if let error = error {
// Handle error that occurred while opening or downloading the contents of the Realm
debugPrint("error: \(error.localizedDescription)")
}
}
}
deinit {
self.token?.stop()
}
Finally the sendMessage() method that I use to send the message:
func sendMessage(id: String, name: String, text: String) {
let message = Message()
message.userId = id
message.name = name
message.text = text
message.dateCreated = NSDate()
Realm.asyncOpen(configuration: self.configuration) { realm, error in
if let realm = realm {
// Realm successfully opened, with all remote data available
try! realm.write() {
realm.add(message)
}
} else if let error = error {
// Handle error that occurred while opening or downloading the contents of the Realm
debugPrint("error: \(error.localizedDescription)")
}
}
}
Hope it helps!
Bye!

Swift: Exception when requesting access to Facebook

After updating to XCode 8, Swift 3, and iOS 10, I've begun to get the following error when requesting permission to access Facebook accounts:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Access options are not
permitted for this account type. The options argument must be nil.'
I've found three mentions of this error on SO:
Access options are not permitted for this account type. The options argument must be nil.;
Facebook SDK login crash
NSInvalidArgumentException thrown from ACAccountStore when calling [FBSession openActiveSessionWithPermissions...] on iOS 6.0 and iOS 6.0.1
The first two have no answers; the last suggests checking that the value returned from accountType(withAccountTypeIdentifier ...) isn't nil, which I was already doing.
As mentioned elsewhere, this error is inconsistent with the documentation, which states that Facebook requires an options dictionary.
Here is a small example which reproduces the problem and makes a big show of error checking everything I could think to error check:
import UIKit
import Social
import Accounts
class DVSocialTestViewController: UIViewController {
let localURL = URL(string: "fb://")
let serviceType = SLServiceTypeFacebook
let accountID = ACAccountTypeIdentifierFacebook
var accountType: ACAccountType? {
return ACAccountStore().accountType(withAccountTypeIdentifier: self.accountID)
}
var accounts: [Any]? {
guard let ac = self.accountType else { return nil }
return ACAccountStore().accounts(with: ac)
}
static let appID = "MyAppID"
let basicOptions =
[ACFacebookAppIdKey: DVSocialTestViewController.appID,
ACFacebookPermissionsKey: ["basic_info"],
ACFacebookAudienceKey: ACFacebookAudienceFriends] as [AnyHashable: Any]
let publishOptions =
[ACFacebookAppIdKey:DVSocialTestViewController.appID,
ACFacebookPermissionsKey:["publish_actions"],
ACFacebookAudienceKey:ACFacebookAudienceFriends] as [AnyHashable: Any]
var applicationIsInstalled: Bool {
guard let url = self.localURL else {
return false
}
return UIApplication.shared.canOpenURL(url)
}
var serviceIsAvailable: Bool {
return SLComposeViewController.isAvailable(forServiceType: self.serviceType)
}
var userIsLoggedIn: Bool {
guard let ac = self.accounts, ac.count > 0 else {
NSLog("\(self.accounts)")
return false
}
return true
}
func requestPermissionsForAccountType(_ type: ACAccountType) {
ACAccountStore().requestAccessToAccounts(with: type, options: self.basicOptions) {
(success: Bool, error: Error?) -> Void in
if !success {
NSLog("\(error)")
return
}
ACAccountStore().requestAccessToAccounts(with: type, options: self.publishOptions) {
(success: Bool, error: Error?) -> Void in
if !success {
NSLog("\(error)")
return
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
guard self.applicationIsInstalled else {
NSLog("FB Application is not installed.")
return
}
guard self.serviceIsAvailable else {
NSLog("FB Service is unavailable.")
return
}
guard self.userIsLoggedIn else {
NSLog("User is not logged into FB.")
return
}
guard let AT = self.accountType else {
NSLog("No accounts.")
return
}
self.requestPermissionsForAccountType(AT)
}
}
Has anyone run into this? Any suggestions about what I'm missing?
Edit:
There are few reasons why I feel my question is different from the proposed duplicate.
I'm not using the Facebook SDK.
This is not a "rare case"--it consistently happens with this example every time I run it.
This specifically began happening upon updating to XCode 8, Swift 3, and iOS 10 from the preceding versions.
As stated above, the only answer to the other question (which I admit is not accepted) does not solve my problem.
I've provided a complete, minimal example, which the other question does not.

Resources