j3k0 / cordova-plugin-purchase

In-App Purchase for Cordova on iOS, Android and Windows
https://purchase.cordova.fovea.cc
1.29k stars 529 forks source link

Crash when trying to purchase #389

Closed mparpaillon closed 5 years ago

mparpaillon commented 8 years ago

Hi ! :)

When I launch my app on iPhone 6 simulator (iOS 9) I can't purchase my item.

Here are the logs:

InAppPurchase[objc]: Purchasing...
InAppPurchase[objc]: State: PaymentTransactionStatePurchasing
-[__NSArrayI JSONRepresentation]: unrecognized selector sent to instance 0x7fb209754cd0
*** WebKit discarded an uncaught exception in the webView:decidePolicyForNavigationAction:request:frame:decisionListener: delegate: <NSInvalidArgumentException> -[__NSArrayI JSONRepresentation]: unrecognized selector sent to instance 0x7fb209754cd0

Any idea ?

Thanks a lot

davidzas commented 8 years ago

Hi, I'm also having this issue with a real device with IOS 9.2. Is there a chance to get this fixed soon or maybe a solution that we can implement?

davidzas commented 8 years ago

i could solve it y my self. Just change this line

NSString *js = [NSString stringWithFormat:@"window.storekit.updatedTransactionCallback.apply(window.storekit, %@)", [callbackArgs JSONSerialize]];

with NSString *js = [NSString stringWithFormat:@"window.storekit.updatedTransactionCallback.apply(window.storekit, %@)", [callbackArgs componentsJoinedByString:@", "]];

Hope it helps :D

mparpaillon commented 8 years ago

Oh I'll try this later. Can you make a PR please ?

davidzas commented 8 years ago

Actually doing it that way the exception isn't throwed but it cannot be parsed by the javascript. I'm working on it currently. Wait for a new update soon.

mparpaillon commented 8 years ago

Arf. I really need this fix... Anyone ?

davidzas commented 8 years ago

I made it work adding some validations. Please use the code below under your own responsibility.

replace: NSString *js = [NSString stringWithFormat:@"window.storekit.updatedTransactionCallback.apply(window.storekit, %@)", [callbackArgs JSONSerialize]];

with: NSString *js = [NSString stringWithFormat:@"window.storekit.updatedTransactionCallback.apply(window.storekit, ['%@'])", [callbackArgs componentsJoinedByString:@"','"]];

And hope it helps. Worked for me.

mparpaillon commented 8 years ago

If it works it's awesome. Thanks a lot !

mparpaillon commented 8 years ago

The error is gone but I still get ERROR 6777010: Cannot connect to iTunes Store. Any idea ?

mparpaillon commented 8 years ago

Nope, forget it. It works \o/ Thanks mate

mparpaillon commented 8 years ago

Well I shouldn't close it since the fix should be added to the plugin @j3k0

j3k0 commented 8 years ago

Can you please submit a Pull Request if there's any code to merge into the codebase?

While I haven't been handling GitHub issues for a while, I still maintain the plugin's code by reviewing and merging pull requests when appropriate.

On Wed, Feb 3, 2016 at 11:40 PM Michel Parpaillon notifications@github.com wrote:

Reopened #389 https://github.com/j3k0/cordova-plugin-purchase/issues/389 .

— Reply to this email directly or view it on GitHub https://github.com/j3k0/cordova-plugin-purchase/issues/389#event-538248231 .

mparpaillon commented 8 years ago

Well I can if you want, but I'm not a iOS developer. I honestly don't know how @davidzas fix works

Maybe there's a cleaner/smarter way of doing it. If it's good enough for you I'll make a PR

thomasMary commented 8 years ago

This fix is working for me

mlmassey commented 8 years ago

We are testing the fixes provided by @davidzas and @electronicmax to see if it helps the crash issue we are seeing in our app. The thing that is confusing is why I don't see the problem on my local phone builds, but it is seen on other phone builds (iPhone5 vs. iPhone6 with iOS8 vs. iOS9). I will let you guys know if it addresses our problems.

The problem is stemming from here in InAppPurchase.m:

// To avoid compilation warning, declare JSONKit and SBJson's
// category methods without including their header files.
@interface NSArray (StubsForSerializers)
- (NSString *)JSONString;
- (NSString *)JSONRepresentation;
@end

// Helper category method to choose which JSON serializer to use.
@interface NSArray (JSONSerialize)
- (NSString *)JSONSerialize;
@end

@implementation NSArray (JSONSerialize)
- (NSString *)JSONSerialize {
    return [self respondsToSelector:@selector(JSONString)] ? [self JSONString] : [self JSONRepresentation];
}
@end

The main issue is the line: return [self respondsToSelector:@selector(JSONString)] ? [self JSONString] : [self JSONRepresentation];

The respondsToSelector evaluates to FALSE because it cannot find the selector JSONString in the NSDictionary type. NSDictionary would not have this type unless you are including the SBJson json-framework in the app (which we are not). Since it evaluates to FALSE, it then assumes JSONRepresentation is present, which it also is not if you have not installed json-framework.

My questions are:

  1. Why declare and mention SBJSon functions in the code, but then not mention this as a dependency of your plugin?
  2. Why not use the built-in NSJSONSerialization framework built into iOS?
mlmassey commented 8 years ago

In our testing, if you take the official version of the plugin (via cordova plugin add cc.fovea.cordova.purchase), then there is no problem. We only saw this issue when taking master from git.

jlake commented 8 years ago
// Helper category method to choose which JSON serializer to use.
@interface NSArray (JSONSerialize)
- (NSString *)JSONSerialize;
@end

@implementation NSArray (JSONSerialize)
- (NSString *)JSONSerialize {
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self
                                                       options:(NSJSONWritingOptions)0
                                                         error:&error];

    if (! jsonData) {
        NSLog(@"JSONSerialize: error: %@", error.localizedDescription);
        return @"{}";
    } else {
        return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }

    //return [self respondsToSelector:@selector(JSONString)] ? [self JSONString] : [self JSONRepresentation];
}
@end
j3k0 commented 8 years ago

So what is the definite fix for this? Would anyone mind to create a pull request?

mlmassey commented 8 years ago

@j3k0 Could you see my questions above? The proposed fix may address the issue, but I'm a bit concerned on why this code was there in the first place and how it was working before (but not now)

mlmassey commented 8 years ago

@j3k0 See Pull request #408 to fix the issue. The problem was Cordova iOS 4.0 broke your code. Note that the PR won't work on someone running a version earlier than 4.0, so not sure how you want to manage this

mlmassey commented 8 years ago

The offender: [https://issues.apache.org/jira/browse/CB-8270]

rafaellop commented 8 years ago

Thanks @mlmassey! The json error is gone. However I've got the same error as @mparpaillon mentioned above in the 9.2 simulator:

ERROR 6777010: Cannot connect to iTunes Store.

The store is properly initiated in the app and I can see all data are correctly downloaded from the appstore. The error happens when I try to use an existing AppleID (tap the menu item) or try to create a new one. Any ideas please? I'm a newbie on iOS.

mlmassey commented 8 years ago

I don't think you can test in-app purchase in the simulator. You need to use a real phone

rafaellop commented 8 years ago

Thanks @mlmassey. When I saw the app in simulator gets info from the Appstore I thought purchases would also work. I tested on iPhone device and everything works perfectly. Thank you!

steffanolesen commented 8 years ago

Why not just use Apple own JSON routines. Then the code will work with both old and new Cordova. See Pull request #419 for a fix.

mlmassey commented 8 years ago

@steffanolesen Yupper. That is the proper fix. Nicely done.

stale[bot] commented 6 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.