Issue with Apple Pay / Stripe integration - ios

I have followed Stripe's documentation and Example App on integrating Apple Pay.
In the handlePaymentAuthorizationWithPayment method, under createTokenWithPayment, I am getting the error:
Error Domain=com.stripe.lib Code=50 "Your payment information is formatted improperly. Please make sure you're correctly using the latest version of our iOS library. For more information see https://stripe.com/docs/mobile/ios ." UserInfo=0x170261b40 {com.stripe.lib:ErrorMessageKey=Your payment information is formatted improperly. Please make sure you're correctly using the latest version of our iOS library. For more information see https://stripe.com/docs/mobile/ios ., NSLocalizedDescription=Your payment information is formatted improperly. Please make sure you're correctly using the latest version of our iOS library. For more information see https://stripe.com/docs/mobile/ios .}
Anyone know how to resolve this? I am using the latest Stripe library.
Thanks.

This little bit of RnD helped me. Digging into the CustomSampleProject provided by Stripe themselves, ApplePayStubs works pretty well when the STPCard is recognized when the delegate
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
didAuthorizePayment:(PKPayment *)payment
completion:(void (^)(PKPaymentAuthorizationStatus))completion
of PKPaymentAuthorizationViewControllerDelegate is called. The sample code here checked if the code was run in debug that is for ApplePayStubs, the (PKPayment *)payment in the delegate is converted to a STPCard and is launched to the STPAPIClient for STPToken generation. Following is the body of the above mentioned delegate:
#if DEBUG // This is to handle a test result from ApplePayStubs
if (payment.stp_testCardNumber)
{
STPCard *card = [STPCard new];
card.number = payment.stp_testCardNumber;
card.expMonth = 12;
card.expYear = 2020;
card.cvc = #"123";
[[STPAPIClient sharedClient] createTokenWithCard:card
completion:^(STPToken *token, NSError *error)
{
if (error)
{
completion(PKPaymentAuthorizationStatusFailure);
[[[UIAlertView alloc] initWithTitle:#"Error"
message:#"Payment Unsuccessful! \n Please Try Again"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
return;
}
/*
Handle Token here
*/
}];
}
#else
[[STPAPIClient sharedClient] createTokenWithPayment:payment
completion:^(STPToken *token, NSError *error)
{
if (error)
{
completion(PKPaymentAuthorizationStatusFailure);
[[[UIAlertView alloc] initWithTitle:#"Error"
message:#"Payment Unsuccessful!"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil] show];
return;
}
/*
Handle Token here
*/
}];
#endif
This worked for me. With ApplePayStubs (on Simulator) and without them (on Device) Hope this Helps :)

I think I know what happened here. Leaving this up in case it helps anybody.
When I initially set up Stripe / Apple Pay into my app, I kept getting numerous errors when I attempted to implement STPTestPaymentAuthorizationController. I found the exact problem described here (Stripe payment library and undefined symbols for x86_64).
I replicated the solution defined above by commenting out part of Stripe's code, which maybe (?) produced the Error Domain=com.stripe.lib Code=50 error.
I fixed this by not using STPTestPaymentAuthorizationController at all, just replacing that with PKPaymentAuthorizationViewController in #DEBUG mode.
tl:dr Not completely sure why STPTestPaymentAuthorization didn't work; avoided situation completely by running PKPaymentAuthorizationViewController with my iPhone and Stripe dashboard in test mode.

Related

productsRequest seems to return empty set for one app while non-empty for another

dear all:
I inherited a program that can be compiled to two iOS apps, one for traditional Chinese and one for simplified Chinese.
The apps have inAppPurchase and worked fine in the last version.
Then this year, I revised the program without changing the inAppPurchase process.
But after the submissions, apple rejected the traditional Chinese app saying that it would be stuck in the inAppPurchase page.
But the simplified Chinese app was approved.
I then traced the program to the following code.
It seems that my apps always get the empty response set for productsRequest.
However, I must say that I did not do sandbox testing since I don't know how.
I am not sure why it worked fine in last year's version but failed in this year's.
Is there change to some default assumption on bundle id, application id, .. etc.
I checked all my program and could not find where I can set up the app id for the productsRequest statement.
My program is just standard as follows.
Any help will be appreciated.
// determine whether payments can be made
if (![SKPaymentQueue canMakePayments]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"warning" message:#"ineffective" delegate:nil cancelButtonTitle:#"OK?" otherButtonTitles:nil];
[alert show];
}
else {
[buttonPrice setTitle:#"waiting for price" forState:UIControlStateNormal];
[buttonPriceAll setTitle:#"waiting for price" forState:UIControlStateNormal];
// Request product data
productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObjects:bookProductIds[0], bookProductIds[purchaseVolume-1], nil]];
productsRequest.delegate = self;
[productsRequest start];
[self operationStarted];
}

_UIViewServiceInterfaceErrorDomain

I'm having a problem with MFMailComposeViewController
I'm getting this error
viewServiceDidTerminateWithError: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "The operation couldn’t be completed. (_UIViewServiceInterfaceErrorDomain error 3.)" UserInfo=... {Message=Service Connection Interrupted}
with this code
- (IBAction) mailbutton:(id)sender
{
if([MFMailComposeViewController canSendMail])
{
[MSAPP.globalMailComposer setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentViewController:MSAPP.globalMailComposer animated:YES completion:nil];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Unable to mail. No email on this device?"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[MSAPP cycleTheGlobalMailComposer];
}
}
This is a known issue with the iOS 8 simulator. Please see this post for a possible workaround.
You MUST allocate and initiate MFMailComposeViewController in an
earlier stage, and hold it in one static variable, whenever it's
needed, get the static MFMailComposeViewController instance and
present it.
AND you will almost certainly have to "cycle" the global
MFMailComposeViewController after each use. It is not reliable to
"re-use" the same one. Have a global routine which release and then
re-initializes the singleton MFMailComposeViewController. Call it each
time after you are finished with it
Credit goes to "Joe Blow" for the post. Judging by your code, you have already declared global mail composer. Try "recycling" it as the post suggests to see if that solves your problem. I am having the same issue and unfortunately this solution doesn't fix mine. I can confirm this solution works on the iOS 7.1 simulator but not iOS 8, although it has been suggested it will work on a physical iOS 8 device.

Observe NSLog messages in Xcode

I'm debugging a 3rd party SDK which puts lot of useful information into the console.
I used to display some messages in tooltips (for our tester), which I'm receiving from SDK delegate.
But delegate methods don't include many details and sometimes it turns helpless, otherwise console includes much more helpful information (especially if the SDK's log level is set to DEBUG_ALL or something like that).
So, my question - is it possible to observe NSLog messages and to be notified in some way when they are printed to console? Of course I would like to have string message as a parameter?
I would like to display it on device/simulator screen, so that the tester doesn't have to run XCode or view the device's console.
I'm using iConsole for the same purpose. It's quite useful.
What SDK? If the SDK supports CocoaLumberjack, then I suggest installing that, and configuring the loggers to do what you want -- even route somewhere else.
CocoaLumberjack gives you a lot of power and configurability when it comes to logging.
If your SDK uses NSLog to print the details in the console, then you can use macros to redefine the NSLog.
#define NSLog(FORMAT, ...) ShowLogInAlert(FORMAT);
void ShowLogInAlert(NSString *format, ...){
//show the log in the alert here.
va_list ap;
va_start (ap, format);
format = [format stringByAppendingString:#"\n"];
NSString *msg = [[NSString alloc] initWithFormat:[NSString stringWithFormat:#"%#",format] arguments:ap];
// NSLog(#"%#", msg);
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:msg message:#"" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
va_end (ap);
}

Issue when using MFMailComposeViewController

I have a tricky problem. In one of my app, with over 150.000 downloads... I have a problem which seldom occurs and which I can't seem to figure out.
The problem is the following:
In a view where the user can share a list via email, I open the mail window using MFMailComposeViewController. However, in some few cases the app seems to get a problem using the mail composer. The user presses the share button, the mail windows slides up, waits about 1-2 sec and then closes again. No content in the mail window, although I do send data to it.
I myself have not been able to re-create the problem on any device or in the simulator, however one colleague has.
I ran the app using XCode on his phone and got the following in the logs:
2013-03-01 14:43:39.604 appname[318:907] <MFMailComposeRemoteViewController: 0x1ebfb100> timed out waiting for fence barrier from com.apple.MailCompositionService
2013-03-01 14:43:39.631 appname[318:907] viewServiceDidTerminateWithError: Error Domain=XPCObjectsErrorDomain Code=2 "The operation couldn’t be completed. (XPCObjectsErrorDomain error 2.)"
I googled the error "timed out waiting for fence barrier from com.apple.MailCompositionService" but can't really find any help.
Does anybody have any experience with this? How can I solve it?
My code for opening the view:
-(void)displayComposerSheetWithBodyString:(NSString *)aBody
{
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc]init];
picker.mailComposeDelegate = self;
[picker setSubject:#"Lista"];
NSString *emailBody = aBody;
[picker setMessageBody:emailBody isHTML:NO];
[self.navigationController presentModalViewController:picker animated:YES];
}
else
{
[[[UIAlertView alloc]initWithTitle:NSLocalizedString(#"Din enhet är inte redo att skicka e-post. Kontrollera dina inställningar", nil)
message:nil
delegate:self
cancelButtonTitle:NSLocalizedString(#"OK", nil)
otherButtonTitles:nil]
show];
}
}
Not sure if you have fixed the problem, but I have met it recently in my project.
A workaround I did was to allocate and initiate MFMailComposeViewController in an earlier stage, and hold it in one static variable, whenever it's needed, get the static MFMailComposeViewController instance and present it.
It seems working for me, hope it will work for you, too.
a had the same issue, and this fixe helped me:
https://twitter.com/christian_beer/statuses/321295533077565440
"#nathangaskin well… that was long ago :) But if I remember correctly, it worked after I removed the custom fonts from my UIAppearance code"
It works fine for me.
Also, second option is to simply wrap displaying call into
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
block
I have exactly the same issue. I think I have nailed it down to the time it takes to formulate the message body string.
Content from comment
//Message Body
NSString *msgBody = [NSString stringWithFormat:
#"I noticed these results in pocketKPI. The %# was at %# which is a variance of %#(or %#) to the target defined as %#. When you have some time let's discuss.",
self.itemToView.kpiName,
[DFSKpiFormatter formatNumberAsString:self.itemToView.currentValue], [self.itemToView determineVarianceLabelText],
[self.itemToView determineVariancePercentLabelText],
[DFSKpiFormatter formatNumberAsString:self.itemToView.targetValue]];

ios 6.0 new addressbook ABAddressBookRequestAccessWithCompletion

I want to ask that how I can detect whether my AddressBook was first accessed by an app on ios6.0. I have learnt that no matter an app was reinstalled or not , the system only thinks that the first installation an first launch is the first time an app launched. the question is that I want to remind an user to allow the app access AddressBook with an UIAlertView,but this alertview will appear shortly after the system's alertview .How can I avoid this condition. Any help will be greatly appreciated.
You should basically ignore ABAddressBookRequestAccessWithCompletion. It is useless. If you want to know whether you have access to the database, call ABAddressBookGetAuthorizationStatus().
Further Discussion
ABAddressBookRequestAccessWithCompletion is said by the docs to request address book access from the user. But it doesn't. I will now demonstrate that ABAddressBookRequestAccessWithCompletion is useless. There are two situations:
(1) If this is a completely unknown new app, ABAddressBookRequestAccessWithCompletion is otiose: access will be requested from the user automatically when the app tries to access the address book, so there is no need for ABAddressBookRequestAccessWithCompletion.
(2) If the user has either denied or granted access, ABAddressBookRequestAccessWithCompletion is a no-op! Calling it does nothing; it does not put up the access request alert!
So ABAddressBookRequestAccessWithCompletion is just a bug and should be ignored.
A Major Correction
EDIT In iOS 6.1, this behavior appears to have changed. (I am assuming that my tests on iOS 6.0 were valid, but I have every reason to believe they were.) Now, however, in iOS 6.1, ABAddressBookCreateWithOptions never causes the authorization alert to appear. The only way to make it appear is with ABAddressBookRequestAccessWithCompletion! Thus this function is now essential; if ABAddressBookGetAuthorizationStatus that access is undetermined, you must call ABAddressBookRequestAccessWithCompletion or you won't get access.
I have solved it by this way.
__block BOOL accessGranted;
- (IBAction)accessAddressBook:(id)sender {
CFErrorRef error;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL,&error);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
// accessGranted = granted;
if (!accessGranted && !granted) {
UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:#"Deny Access" message:#"Deny" delegate:self cancelButtonTitle:nil otherButtonTitles:#"cancel", nil];
[alertView show];
[alertView release];
}
});
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if ([alertView.message isEqualToString:#"use contact"] || alertView.message == #"use contact") {
accessGranted = YES;
}
}
The system already shows an alert when you call ABAddressBookRequestAccessWithCompletion()
just augment the system app with your own string.
You should have in your InfoPlist.strings:
"NSContactsUsageDescription" = "Tap 'OK' or this app is useless.";

Resources