STPPaymentMethod TextField won't accept any programmatic card numbers - swift

I have recently installed the pod StripeCardScan on my project. I am able to get it to work correctly, however, it isn't possible to get the STPPaymentCardTextField to accept any programmatic inputs, from the card scan or just using a manual let statement. I have googled and reviewed several articles on this, but I feel I am missing something. I am wondering if I need to set a delegate for the class?
Here is the code I am trying to use to put the scanned card into the number field:
cardScanSheet.present(from: self) { [weak self] result in
var title = ""
var message = ""
switch result {
case .completed(let card):
title = "Scan Completed"
message = card.pan
let cardParams = STPPaymentMethodCardParams()
cardParams.number = card.pan
//cardParams.number = "4511554566354474". <- Even when doing this manually, it still does not take
self?.addCardView.cardField.paymentMethodParams.card = cardParams
print("card [pam \(card.pan)")
case .canceled:
title = "Scan Canceled"
message = "Canceled the scan"
case .failed(let error):
title = "Scan Failed"
message = "Failed with error: \(error.localizedDescription)"
}

I think you still need an instance of STPPaymentMethodParams to set the card number programatically. Have you tried following yet?
let cardParams = STPPaymentMethodCardParams()
cardParams.number = card.pan
let paymentMethodParams = STPPaymentMethodParams.init(card: cardParams, billingDetails: STPPaymentMethodBillingDetails(), metadata: [:])
self?.addCardView.cardField.paymentMethodParams = paymentMethodParams ```

Related

How to retrieve message as a String from MessageKit

I am using MessageKit to make a basic chatting app. However, I wanted to do something with the text of the latest sent message.
This is an example of what I want:
print("This is what I was talking about:\n\n", newMessage.kind)
I get:
text("Hi StackOverflow!")
However, I wish to get only this String "Hi StackOverflow". Any help would be appreciated thanks.
You can use a switch statement. For example,
var message = ""
switch newMessage.kind {
case .text(let messageText):
message = messageText
default:
break
}
This question is similar to yours, and may be useful
func getTheMessageText(messageKind: MessageKind) -> String {
if case .text(let value) = messageKind {
return value
}
return ""
}
Usage: Call this method to get the message as a string like
let messageType:MessageType = messageList[indexPath.section]
getTheMessageText(messageKind: messageType.kind)

Keychain references in Swift used in NEVPNManager

I'm trying to connect to a VPN using Swift in Xcode. I'm using KeychainSwift to keep keychain references. My code looks like this:
private func connectVPN(completion: #escaping () -> Void) {
let keychain = KeychainSwift()
keychain.set("<mypassword>", forKey: "passref")
keychain.set("<sharedsecretpassword>", forKey: "secretref")
NEVPNManager.shared().loadFromPreferences { error in
let vpnhost = "<11.11.11.11>"
let username = "<myusername>"
let p = NEVPNProtocolIPSec()
p.username = username
p.localIdentifier = username
p.serverAddress = vpnhost
p.remoteIdentifier = vpnhost
p.authenticationMethod = .sharedSecret
p.disconnectOnSleep = false
p.sharedSecretReference = keychain.getData("secretref")
p.passwordReference = keychain.getData("passref")
var rules = [NEOnDemandRule]()
let rule = NEOnDemandRuleConnect()
rule.interfaceTypeMatch = .any
rules.append(rule)
NEVPNManager.shared().localizedDescription = "My VPN"
NEVPNManager.shared().protocolConfiguration = p
NEVPNManager.shared().onDemandRules = rules
NEVPNManager.shared().isOnDemandEnabled = true
NEVPNManager.shared().isEnabled = true
NEVPNManager.shared().saveToPreferences { error in
if (error != nil) {
print(error!)
} else {
do {
try NEVPNManager.shared().connection.startVPNTunnel()
completion()
} catch {
print("can't connect VPN'")
}
}
}
}
}
I'm using keychain.getData("secretref"), because this field needs
A persistent keychain reference to a keychain item containing the IKE
shared secret.
What's more,
The persistent keychain reference must refer to a keychain item of
class kSecClassGenericPassword.
I'm not really sure, if I'm doing it right. I didn't subclass kSecClassGenericPassword or use it in any way.
When I'm using this function in code, a window shows with information, that there is no shared secret for this VPN. I think it means that this keychain doesn't work as it's supposed to.
In iPhone settings, it tries to connect, moves switch towards green and instantly the switch goes back to "off" state. When I put the same data as in code manually, the connection works.
What am I doing wrong? What should I correct?
Okay, I have the answer. In the query for the SecItemCopyMatching, I had to choose kSecReturnPersistentRef with kCFBooleanTrue - not kSecReturnData.

how to send through multiple dictionaries/ multiple 'application updates' with swift 2.2 watch connectivity

How can I send through several 'application updates' from my phone to my watch, (such as several different values from an array) with Watch Connectivity?
My application update worked successfully to send through the numberItem value from the selected cell in my table view, but I would like to also send through the userid value from the selected cell array.
Right now, it only recognizes one value, and doesn't update the other value, but displays 'please retry' as my label text.
How can I send through two or more application updates, for other additional values (such as userid, and username).
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let numberItem = number[indexPath.row]
print("tableview select #:")
print(numberItem)
do {
try WatchSessionManager.sharedManager.updateApplicationContext(["number" : numberItem])
} catch {
let alertController = UIAlertController(title: "Oops!", message: "Looks like your \(numberItem) got stuck on the way! Please send again!", preferredStyle: .Alert)
presentViewController(alertController, animated: true, completion: nil)
}
let uidItem = 15
//let uidDict = ["uidValue":uidItem]
print("the send UID is")
//print(uidItem)
do {
try WatchSessionManager.sharedManager.updateApplicationContext(["uidValue" : uidItem])
} catch {
let alertController = UIAlertController(title: "Oops!", message: "Looks like your \(uidItem) got stuck on the way! Please send again!", preferredStyle: .Alert)
presentViewController(alertController, animated: true, completion: nil)
}
}
My datasource.swift file is:
enum Item {
case Number(String)
case uidValue(String)
case Unknown
}
init(data: [String : AnyObject]) {
if let numberItem = data["number"] as? String {
item = Item.Number(numberItem)
print("enum item is")
print(numberItem)
} else if let uidItem = data["uidValue"] as? String {
item = Item.uidValue(uidItem)
print("enum item is")
print(uidItem)
} else {
item = Item.Unknown
}
}
and my interface controller on the watch (connected to my data labels) includes:
func dataSourceDidUpdate(dataSource: DataSource) {
switch dataSource.item {
// the first application update- commented out to try the 2nd update
//case .Number(let numberItem):
// titleLabel.setText(numberItem)
// print(numberItem)
// the second application update
case .uidValue(let uidItem):
uidLabel.setText(uidItem)
print(uidItem)
case .Unknown:
nidLabel.setText("please retry")
default:
print("default")
}
}
You can't send the items separately, as updateApplicationContext would have replaced any earlier application context data with the most recent data. This is briefly mentioned in two different spots in the documentation:
This method overwrites the previous data dictionary, ...
This method replaces the previous dictionary that was set, ...
Naturally, Apple optimizes the whole process for energy/memory efficiency. In this case, if the earlier application context data was still in the queue to be transmitted when the second data was queued for transmission, the earlier data can be discarded to save from having to unnecessarily transmit/store it. Your watch wouldn't even have received the first data.
Since your watch would have only received one of the two pieces of data, this explains why you'd see "please retry" when you checked the received dictionary for one key, but it only contained the data for the other key.
How to transmit more than one item at once
Include both items in the same dictionary, and transmit that dictionary using a single transfer.
let data = ["number" : numberItem, "uidValue" : uidItem]
try WatchSessionManager.sharedManager.updateApplicationContext(data)
...
On the watch side, you simply can update the title label and uid label at the same time, instead of conditionally updating only one or the other.
if let numberItem = data["number"] as? String {
titleLabel.setText(numberItem)
}
if let uidItem = data["uidValue"] as? String {
uidLabel.setText(uidItem)
}

CKSubscription error iOS10

My subscriptions were working properly with iOS 9, but since I updated, I have a very odd error. I have two subscription methods that are equal, except for the fields they manage. Here is the code:
let meetingSubscriptionPredicate = Predicate(format: "Users CONTAINS %#", (id?.recordName)!)
let meetingSubscription = CKQuerySubscription(recordType: "Meetings", predicate: meetingSubscriptionPredicate, options: .firesOnRecordCreation)
let notification = CKNotificationInfo()
notification.alertBody = "Meeting Created!"
notification.shouldBadge = true
notification.accessibilityPerformEscape()
meetingSubscription.notificationInfo = notification
database.save(meetingSubscription) { (result, error) -> Void in
if error != nil {
print(error!.localizedDescription)
}
}
let universitiesSubscriptionPredicate = Predicate(format: "Name = %#", self.UniversityTextField.text!)
let universitiesSubscription = CKQuerySubscription(recordType: "Universities", predicate: universitiesSubscriptionPredicate, options: .firesOnRecordCreation)
let universitiesNotification = CKNotificationInfo()
universitiesNotification.alertBody = "Your university is now on Meet'em!"
universitiesNotification.shouldBadge = true
universitiesNotification.accessibilityPerformEscape()
universitiesSubscription.notificationInfo = universitiesNotification
database.save(universitiesSubscription, completionHandler: { (saved, error) in
if error != nil {
print(error!.localizedDescription)
}
else {
print("University subscription created")
}
})
The odd thing is that the Meeting subscription is saved, and the University's subscription is not. I've double checked the names and they are all right at the Dashboard. Besides that, I'm not getting any notification on my phone when supposed to...
Found elsewhere online that you can try to reset your development environment. In my case, the predicate I was trying to use was not set to queryable. This is ticked where you define your record type. The reason it worked one day and not another is possibly due to moving from development to production. At that time you are asked to optimize indexes, and it is possibly here that the ability to search on a given predicate is dropped. That seemed to be the case for me anyway.

SWIFT: do I have someone set a record with different text every time?

So I made a chatroom and when someone sends a message they also add a Subscription in my cloud kit database but the problem is there cant be more then one of the same name that is a subscription and I want them to be able to set more subscriptions then one. Here is some code:
func setupCloudKitSubscription () {
let userDefaults = NSUserDefaults.standardUserDefaults()
if userDefaults.boolForKey("subscribed") == false {
let predicate = NSPredicate(format: "TRUEPREDICATE", argumentArray: nil)
let subscription = CKSubscription(recordType: "Extra1", predicate: predicate, options: CKSubscriptionOptions.FiresOnRecordCreation)
let notificationInfo = CKNotificationInfo()
notificationInfo.alertLocalizationKey = "New Sweet"
notificationInfo.shouldBadge = true
subscription.notificationInfo = notificationInfo
let publicData = CKContainer.defaultContainer().publicCloudDatabase
publicData.saveSubscription(subscription) { (subscription:CKSubscription?, error:NSError?) -> Void in
if error != nil {
print(error?.localizedDescription)
}else{
userDefaults.setBool(true, forKey: "subscribed")
userDefaults.synchronize()
You see how it says recordType: "Extra1" how can I made the "Extra1" different text every time someone makes a subscription? Thanks!
Your question is not completely clear. I think what you wanted to ask is that you want the subscription to send you a different message with each notification.
You could set it to display one or more fields of the record. For doing that you should use something like this:
notificationInfo.alertLocalizationKey = "Response: %1$#"
notificationInfo.alertLocalizationArgs = ["responseField"]
Then you also need this in your Localization.Strings file.
"Response: %1$#" = "Response: %1$#";