Support for SKPaymentTransactionObserver for iOS IAPs

Hi, are there any plans to add support for this in the IAP processing or is it something we should handle ourselves?

thx

bump

Bump…

Did you ever figure this out?

Haven’t looked into it any further as of yet, was hoping the Juce guys would sort it out…

@ed95 @t0m - any comments on this?

Bump…could the paymentQueue:shouldAddStorePayment:forProduct: method be implemented?

I can add this to our backlog but it’s not a particularly high priority I’m afraid. Perhaps moving this to the “Feature Requests” category would be helpful - if it gets a good number of votes over there that would increase its priority.

Wouldn’t you think that being able to promote an IAP on the AppStore, especially for sales, would kinda be a priority?

For us yes…

1 Like

Any progress on getting this implemented?

Hi Ed, any news on where this is on the backlog? This feature is now 18 months old, would be good if we could take advantage of it.

thx

@ed95 - any chance of some kind of update on this please???

Which method is missing specifically? If you click on the warning message it should display it. If you add a default implementation that does nothing for that method to SKDelegateAndPaymentObserver::Class in juce_ios_InAppPurchases.cpp does the warning go away?

optional func paymentQueue(_ queue: SKPaymentQueue, 
     shouldAddStorePayment payment: SKPayment, 
                       for product: SKProduct) -> Bool

Try replacing Class with the following:

struct Class   : public ObjCClass<NSObject<SKProductsRequestDelegate, SKPaymentTransactionObserver>>
{
    //==============================================================================
    Class()  : ObjCClass<NSObject<SKProductsRequestDelegate, SKPaymentTransactionObserver>> ("SKDelegateAndPaymentObserverBase_")
    {
        addIvar<SKDelegateAndPaymentObserver*> ("self");

        addMethod (@selector (productsRequest:didReceiveResponse:),                       didReceiveResponse,                          "v@:@@");
        addMethod (@selector (requestDidFinish:),                                         requestDidFinish,                            "v@:@");
        addMethod (@selector (request:didFailWithError:),                                 requestDidFailWithError,                     "v@:@@");
        addMethod (@selector (paymentQueue:updatedTransactions:),                         updatedTransactions,                         "v@:@@");
        addMethod (@selector (paymentQueue:restoreCompletedTransactionsFailedWithError:), restoreCompletedTransactionsFailedWithError, "v@:@@");
        addMethod (@selector (paymentQueueRestoreCompletedTransactionsFinished:),         restoreCompletedTransactionsFinished,        "v@:@");
        addMethod (@selector (paymentQueue:updatedDownloads:),                            updatedDownloads,                            "v@:@@");
       #if JUCE_IOS && defined (__IPHONE_11_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0
        addMethod (@selector (paymentQueue:shouldAddStorePayment:forProduct:),            shouldAddStorePayment,                       "c@:@@@");
       #endif

        registerClass();
    }

    //==============================================================================
    static SKDelegateAndPaymentObserver& getThis (id self)           { return *getIvar<SKDelegateAndPaymentObserver*> (self, "self"); }
    static void setThis (id self, SKDelegateAndPaymentObserver* s)   { object_setInstanceVariable (self, "self", s); }

    //==============================================================================
    static void didReceiveResponse (id self, SEL, SKProductsRequest* request, SKProductsResponse* response)      { getThis (self).didReceiveResponse (request, response); }
    static void requestDidFinish (id self, SEL, SKRequest* request)                                              { getThis (self).requestDidFinish (request); }
    static void requestDidFailWithError (id self, SEL, SKRequest* request, NSError* err)                         { getThis (self).requestDidFailWithError (request, err); }
    static void updatedTransactions (id self, SEL, SKPaymentQueue* queue, NSArray<SKPaymentTransaction*>* trans) { getThis (self).updatedTransactions (queue, trans); }
    static void restoreCompletedTransactionsFailedWithError (id self, SEL, SKPaymentQueue* q, NSError* err)      { getThis (self).restoreCompletedTransactionsFailedWithError (q, err); }
    static void restoreCompletedTransactionsFinished (id self, SEL, SKPaymentQueue* queue)                       { getThis (self).restoreCompletedTransactionsFinished (queue); }
    static void updatedDownloads (id self, SEL, SKPaymentQueue* queue, NSArray<SKDownload*>* downloads)          { getThis (self).updatedDownloads (queue, downloads); }
   #if JUCE_IOS && defined (__IPHONE_11_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0
    static BOOL shouldAddStorePayment (id, SEL, SKPaymentQueue*, SKPayment*, SKProduct*)                         { return true; }
   #endif
};

ok, thx - no warnings now. I don’t really know if there’s any way of testing this so I guess I’ll have to release it onto the app store and see if the stuff appears as it’s supposed to.

1 Like

AFAICT this method is called when the user tries to purchase an one of your app’s in-app purchases from the app store, so just returning true here should probably be OK. It’ll just start handling the purchase as if the user had initiated it from inside your app.

Let us know if it’s working OK for you and we can add it to JUCE.

2 Likes

thx - once the app is released I’ll report back.

1 Like

Wondering if this is in fact working?