Unity IAP .isSubscribed() is always true?

Unity IAP, latest Unity, latest IAP… it seems .isSubscribed() is always true? How does one find out whether a user has actually subscribed to an IAP product?

for(int i = 0; i < subscription_product_id.Length; i++){
SubscriptionInfo si = new SubscriptionInfo(subscription_product_id_*);*_
_*print(si.isSubscribed() + " " + si.isCancelled()); // this returns true undefined for all products even ones that are not subscribed*_ 
_*}*_
_*```*_

Have you subscribed to this product, what type is it? What is subscription_product_id.Length coming from? You’re not using the value of i in you for loop, I’m not sure what this code is supposed to be doing.

Hi! I simplified the code and forgot to include the index. Corrected. It’s simply to check the subscription true state - of which every single product is true somehow.

AFAIK I did not subscribe to the product. It returns true for every single subscription product, even when both 1 month and 1 year subscriptions are different products.

I also sanity checked in an empty project.

Got it, it sounds like an issue at our end that we will look into.

This seems pretty major. Is there another solution to checking if a user has a valid subscription or not?

You can check the receipt directly, it’s readable text that you can print out and examine the properties.

Hmm, do you know what isSubscribed() corresponds to on receipt check?

Also, for some reason GooglePlayTangle and AppleTango aren’t resolvable in Unity 2020.3 IAP
https://docs.unity3d.com/Packages/com.unity.purchasing@3.1/api/UnityEngine.Purchasing.Security.CrossPlatformValidator.html

Can you share one of your receipts? One that you know has as subscription, and another that does not, then compare.

I’m trying to understand what your documented but not implemented feature .isSubscribed() is meant to do, when it gets fixed. What it is fixed, what are you guys checking for?

I believe it’s the isSubscribed property in the receipt, I would need to check. Have you generated the tangle files (menu Services/In-App Purchasing/Receipt Validation Obfuscator)? To be clear, it was working at one point, but needs checking again since we’ve started using Google Billing Library v3. And v4 is just around the corner, as is StoreKit2.

Please show your full code. If there is a receipt, generally there is a subscription. Did you issue a refund? You said earlier “I did not subscribe to the product”. That would mean the receipt is still null, are you checking? You need to check for a non-null receipt before you do anything else. Please share your full purchasing script

Are you saying that .isSubscribed() works (?)

In that case, should my snippet above return false when an account has not subscribed to a product?

So far I am testing in editor only set to iOS. It returns true always, even for an account that does not have anything subscribed. Only the AppStore subscription products have been setup.

No, you shouldn’t even be running that code. If there has been no purchase, the receipt is null. Please show your full code, as requested. You need to check for a null receipt before you run your code. Put in an “if” statement prior to your code.

if (item.receipt != null)
{
//your code goes here
}
else
{
// no purchase!
}

@ina Please check out the Sample IAP Project v2 Sample IAP Project

 public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    {
        MyDebug("OnInitialized: PASS");

        m_StoreController = controller;
        m_StoreExtensionProvider = extensions;
        m_AppleExtensions = extensions.GetExtension<IAppleExtensions>();
        m_GoogleExtensions = extensions.GetExtension<IGooglePlayStoreExtensions>();

        Dictionary<string, string> dict = m_AppleExtensions.GetIntroductoryPriceDictionary();
        
        foreach (UnityEngine.Purchasing.Product item in controller.products.all)
        {
            if (item.receipt != null)
            {
                string intro_json = (dict == null || !dict.ContainsKey(item.definition.storeSpecificId)) ? null : dict[item.definition.storeSpecificId];

                if (item.definition.type == ProductType.Subscription)
                {
                    SubscriptionManager p = new SubscriptionManager(item, intro_json); //or just pass null for intro_json on Google
                    SubscriptionInfo info = p.getSubscriptionInfo();
                    MyDebug("SubInfo: " + info.getProductId().ToString());
                    //Debug.Log(info.getPurchaseDate());
                    MyDebug("getExpireDate: " + info.getExpireDate().ToString());
                    MyDebug("isSubscribed: " + info.isSubscribed().ToString());
                    //Debug.Log(info.isExpired());
                    //Debug.Log(info.isCancelled());
                    //Debug.Log(info.isFreeTrial());
                    //Debug.Log(info.isAutoRenewing());
                    //Debug.Log(info.getRemainingTime());
                    //Debug.Log(info.isIntroductoryPricePeriod());
                    //Debug.Log(info.getIntroductoryPrice());
                    //Debug.Log(info.getIntroductoryPricePeriod());
                    //Debug.Log(info.getIntroductoryPricePeriodCycles());
                }
            }
        }
    }

I think I might be not setting things up properly - also tried downloading the Sample IAP Project 2. Is Google Tangle obfuscator required for this to work in editor?

Error is The type initializer for ‘UnityEngine.Purchasing.Security.GooglePlayTangle’ threw an exception.

Already replied on your other post. You need to generate the tangle files. Separate issue.

@JeffDUnity3D So I checked out the samples included in IAP 4.1.1, but they don’t seem to include how to validate without the user having made a purchase. (For example, Restore, or on Application start.)

So the loop in my snippet above was what I thought a method to check for .isSubscribed(), but it seems to return true for all. What is the right way to check if a product has been subscribed (regardless of whether a purchase transaction has occurred)?

Yes, a user of course needs to make a purchase before you can validate the purchase receipt. Once purchased, the receipt is always available, including on their next session. ProcessPurchase is triggered during Restore, the receipt is available then also. As mentioned, if the receipt is null, no purchase has (ever) been made. The code above would be used on application start, that’s when you initialize IAP. You only initialize IAP once.