I am using stpaddcardviewcontroller UI element to ask a customer to enter the new card information
let addCardViewController = STPAddCardViewController()
addCardViewController.delegate = self
present(navigationController, animated: true)
Above code will show the UI but after tapping on the Done button, I need to get the token (generated from the added card information) for adding a new card/source to the existing customer.
I am using the following delegate method to get the token from stpaddcardviewcontroller UI
extension viewController : STPAddCardViewControllerDelegate {
func addCardViewControllerDidCancel(_ addCardViewController: STPAddCardViewController) {
dismiss(animated: true)
}
func addCardViewController(_ addCardViewController: STPAddCardViewController, didCreatePaymentMethod paymentMethod: STPPaymentMethod, completion: #escaping STPErrorBlock) {
dismiss(animated: true)
}
How can I receive the card token in delegate methods? So that I can pass to Add Card API ?
You get the PaymentMethod token in your didCreatePaymentMethod delegate.
Stripe-iOS (using your publishable key) cannot update Customers by itself. There are 2 options here:
1) Post the token to a backend server endpoint where you would use a Stripe API library (with your Stripe secret key) and attach the PaymentMethod to a Stripe Customer: https://stripe.com/docs/api/payment_methods/attach
2) If you use Ephemeral keys on your iOS app allows you to attach a PaymentMethod to a Stripe Customer. The SDK handles it for you.
Stripe-iOS actually offers prebuilt UI to handle this too such as STPPaymentOptionsViewController. You would need to refer to the "standard integration" guide here which uses STPCustomerContext: https://stripe.com/docs/mobile/ios/standard
Related
iOS app using GIDSignIn for o-Authentication.
We are wondering why when the scopes are presented and not auto selected
Our Client ID and app is verified in our google console and we do NOT show an unsafe app upon sign in.
Does this change when the app is live in the app store? We do not understand why we have to select the scope ourselves when in
func signInWithGoogle() {
guard let clientID = FirebaseApp.app()?.options.clientID else { return }
// Create Google Sign In configuration object.
let config = GIDConfiguration(clientID: clientID)
print("Client ID: \(clientID)")
let additionalScopes = ["https://www.googleapis.com/auth/youtube.readonly", "https://www.googleapis.com/auth/yt-analytics.readonly"]
// Start the sign in flow! GIDSignIn
GIDSignIn.sharedInstance.signIn(with: config, presenting: self, hint: nil, additionalScopes: additionalScopes) { [unowned self] user, error in
if let error = error {
// ...
return
}
}
GIDGoogleSignIn Framework Reference
"This is the intended behavior. We require the user to provide explicit consent for each scope being requested in addition to basic profile.
Note that you can check which scopes the user grants after a successful sign-in and, at an appropriate moment, re-request the additional scopes via
addScopes
if needed."
GoogleSignIn-iOS Github Source
I’m trying to integrate Siri Shortcuts to my application. The concept which I’m trying is to get reward points of my card with secret pin confirmation. Please find what I have done for this below.
Enabled Siri in capabilities and added Siri Intent definition file.
Added new custom intent named say Rewards.
Defined the title. Subtitle and params(accType, pin) with confirmation enabled. Pin will be sent separately to user.
Then defined the intent response with param ‘rewardPoints’ and defined the response messages.
Added Siri intent extensions.
Added custom intent to info.plist files within project and intent extension.
Verified and added new handler for the custom intent and define the resolve, handle and confirm methods as below. For now, I’m returning random no for reward points.
//
// RewardsIntentHandler.swift
// SiriIntentExt
//
import UIKit
import Intents
class RewardsIntentHandler: NSObject, RewardsIntentHandling {
func resolveAccType(for intent:RewardsIntent, with completion: #escaping ([INStringResolutionResult]) -> Void) {
guard let accType = intent.accType else {
completion([INStringResolutionResult.needsValue()])
return
}
completion([INStringResolutionResult.success(with: accType)])
}
func resolvePin(for intent:RewardsIntent, with completion: #escaping ([INIntegerResolutionResult]) -> Void) {
guard let verifyPin = intent.pin else {
completion([INIntegerResolutionResult.needsValue()])
return
}
completion([INIntegerResolutionResult.confirmationRequired(with: verifyPin as? Int)])
}
func confirm(intent: RewardsIntent, completion: #escaping (RewardsIntentResponse) -> Void) {
completion(RewardsIntentResponse.init(code: RewardsIntentResponseCode.ready, userActivity: nil))
}
func handle(intent: RewardsIntent, completion: #escaping (RewardsIntentResponse) -> Void) {
guard intent.accType != nil else {
completion(RewardsIntentResponse.init(code: RewardsIntentResponseCode.continueInApp, userActivity: nil))
return
}
guard intent.pin != nil else {
completion(RewardsIntentResponse.init(code: RewardsIntentResponseCode.continueInApp, userActivity: nil))
return
}
let response = RewardsIntentResponse.success(rewardPoints: NSNumber(value: 3453))
completion(response)
}
}
Modified the IntentHandler to return rewards handler for rewards intent
//
// IntentHandler.swift
// SiriIntentExt
//
import Intents
class IntentHandler: INExtension {
override func handler(for intent: INIntent) -> Any {
if intent is RewardsIntent {
return RewardsIntentHandler()
}
return self
}
}
Donated the intent on view load as below.
//
// ViewController.swift
// Shortcuts
//
import UIKit
import Intents
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
siriAuthorisarion()
donateRewardIntent()
}
func siriAuthorisarion() {
INPreferences.requestSiriAuthorization { (status) in
print("Siri Authorization Status - ", status)
}
}
func donateRewardIntent() {
let rewardsIntent = RewardsIntent()
rewardsIntent.suggestedInvocationPhrase = "Reward Points"
rewardsIntent.accType = "test account"
let interaction = INInteraction(intent: rewardsIntent, response: nil)
interaction.donate { error in
if let error = error {
print("Donating intent failed with error \(error)")
}
DispatchQueue.main.async {
let alert = UIAlertController.init(title: ((error != nil) ? "Error" : "Success"), message: ((error != nil) ? "Oops!!! Error occured on donating intent." : "Intent donated succussfully!!!"), preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
}
}
I'm facing problem from the above code base. Siri is not requesting for pin and not able to get the exact reward points for the account.
Have following questions.
Can we add the intents programmatically to Siri instead adding from shortcuts app or settings. So that user can directly use the functionality once installing the application.
Once intent is added using Shortcuts app, I’m trying the ask Siri for reward points. Its immediately requesting for my app shortcuts defined. Once we say 'yes' to request, I need to be asked for pin. But Siri replies with some problem with my app. What to be done for asking for next param value.
In the handler file, I have added the resolve methods for each parameters. I feel, resolve methods are not getting called to validate the values. Do we need to handle anything to make resolve methods work?
How can I debug the handler implementation using breakpoint within resolve/handle/confirm methods.
Thanks in advance.
Find my analysis for the above questions.
Can we add the intents programmatically to Siri instead adding from shortcuts app or settings. So that user can directly use the functionality once installing the application.
By default, intents are provided for specific domains such as messaging, payments, photos, workout, etc. No need to explicitly add intents through shortcuts for theses specific domains. Apart from these domains if we are creating custom intent, we are in need to donate and add the intents to Siri using shortcut/settings application.
Once intent is added using Shortcuts app, I’m trying the ask Siri for reward points. Its immediately requesting for my app shortcuts defined. Once we say 'yes' to request, I need to be asked for pin. But Siri replies with some problem with my app. What to be done for asking for next param value.
From iOS13, Apple has added Siri parameters and Siri suggestion for custom intents to request the missing parameters. Till iOS12, we don't have parameters option for custom intents.
In the handler file, I have added the resolve methods for each parameters. I feel, resolve methods are not getting called to validate the values. Do we need to handle anything to make resolve methods work?
In iOS12, we cannot add resolve methods for parameters in custom intents. Resolve methods handled only for specific domains provided within Intents extensions as mentioned in question 1. From iOS13, we can have resolve methods for custom intents based on the parameters.
How can I debug the handler implementation using breakpoint within resolve/handle/confirm methods.
We can add breakpoints and debug intent handler methods.
Thanks.
I am working on a stripe project on iOS. I followed the start guide on stripe website for a primary test.
For iOS app, their SDK had a built-in addCardViewController. So I just copy and paste the code to my ViewController file. However, now I am having an error which is, an unresolved identifier submitToBackEnd.
Can anyone tell me what the possible problem is?
Below I have added the code which I used:
func addCardViewController(_ addCardViewController: STPAddCardViewController, didCreateToken token: STPToken, completion: #escaping STPErrorBlock) {
submitTokenToBackend(token, completion: { (error: Error?) in
if let error = error {
// Show error in add card view controller
completion(error)
}
else {
// Notify add card view controller that token creation was handled successfully
completion(nil)
// Dismiss add card view controller
dismiss(animated: true)
}
})
}
It's because you're missing the submitTokenToBackend function declaration. The Stripe documentation assumes you're writing it yourself. (it's mentioned here after the code block https://stripe.com/docs/mobile/ios/custom#stpapiclient--stpcardparams)
The implementation varies greatly depending on what you use to send requests from your App to your backend. It's not exactly the same but you can look at this part of the Standard Example to see how it roughly works:
https://github.com/stripe/stripe-ios/blob/master/Example/Standard%20Integration%20(Swift)/MyAPIClient.swift#L25
Amazon docs docs outlines how its custom authentication flow works. But there are only passing mentions of iOS.
I have a working authentication system using AWS User Pools and its Custom Authentication Flow using Python Triggers and an iOS Swift app.
But there's a detail still troubling me - see comment after code.
In the AWSCognitoIdentityCustomAuthentication handler I've got this:
func getCustomChallengeDetails(_ authenticationInput: AWSCognitoIdentityCustomAuthenticationInput, customAuthCompletionSource: AWSTaskCompletionSource<AWSCognitoIdentityCustomChallengeDetails>) {
self.customAuthenticationCompletion = customAuthCompletionSource
if authenticationInput.challengeParameters.count > 0 {
DispatchQueue.main.async {
if let code = self.codeTextField.text {
let details = AWSCognitoIdentityCustomChallengeDetails(
challengeResponses: ["CODE" : code])
details.initialChallengeName = "CUSTOM_CHALLENGE"
customAuthCompletionSource.set(result: details)
}
}
}
func didCompleteStepWithError(_ error: Error?) {
// handling code
}
}
The first call of getCustomChallengeDetails() has an empty list for challengeParameters. The second call has a correctly populated challengeParameters
The method didCompleteStepWithError(_ error: Error?) misled me as I thought it only called when an error occurs but is in fact also called on success with error set to nil.
I also have a UIViewController that prompts the user for a CODE which they've been emailed by my server code. When the user submits the CODE I call this:
if let code = codeTextField.text {
let details = AWSCognitoIdentityCustomChallengeDetails(
challengeResponses: ["CODE" : code])
details.initialChallengeName = "CUSTOM_CHALLENGE"
self.customAuthenticationCompletion?.set(result: details)
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
}
}
This works. The server code will authenticate users who enter correct CODE values but deny those who submit an incorrect value for CODE.
But why the two customAuthenticationCompletion?.set(result: details) calls?
Can anyone say where I've taken a misstep?
I have a tableView that utilizes the UIActivityViewController so users can share content on other 3rd party networks Facebook, twitter, text message etc. I have a function called IncreaseShareByOne() and it's purpose is to count the number of times that something has been shared . My problem is that right now that function fires of every time the UIActivityViewController is clicked . Is there someway that I can find out if a user really shared something so that I can use that function correctly ? becomes sometimes you open the UIActivityViewController and decide not to share anything so I want to catch and not use that function. I am new to swift and am using version 3 .
func sharedShareAction(controller: UIViewController, sender: UIButton) {
controller.present(activityViewController,animated: true,completion: nil)
IncreaseShareByOne()
}
You can add a completion handler to your UIActivityViewController. In the completion handler, check whether the user submitted using the completed value. You'll probably want to do something like this:
func sharedShareAction(controller: UIViewController, sender: UIButton) {
controller.present(activityViewController,animated: true, completion: nil)
activityViewController.completionWithItemsHandler = { activity, completed, items, error in
if !completed {
// handle task not completed
return
}
IncreaseShareByOne()
}
}
Check the API docs for more info.