Unity IAP not working on iPhone 12

Hello!

I have a problem with in app purchases, it could be bound to the recent release of iOS 15, I still don’t know.
I’m using Easy Mobile Pro as plugin to cross platform easily. Unity IAP and Easy Mobile Pro are both updated to last release.
The very odd thing is that IAP work on every Android device AND every Apple device, except for iPhone 12 pro max. I tested it on iPhone 6, SE, X, 11, 11 pro…so I really don’t think it’s related to EMP plugin or to my code, just because it’s working like a charm on every other platform. On iPhone 12 doesn’t work ( I tested with iOS 14.8 before the update of iOS 15, both don’t work).
Also, I noted that face id is not being called and the old UI with password check si called instead. Could be necessary to install some sort of face detection package? Is someone else experiencing this issue?
I’ve been rejected three time from App review on Apple Store and our client is very disappointed for having it only on Android.
Please I need some kind of help, I’ve been working on it from 4 days and still nothing. Thanks a lot

When you say “doesn’t work”, can you elaborate? Is IAP initialization failing? Or is it a purchase that is failing? It appears that you can reproduce, so please provide the XCode logs which should help to troubleshoot https://discussions.unity.com/t/700551

1 Like

Hi Jeff,
Sorry for the lack of information, I was a bit worried. I put some alerts log to see what was happening, the initialization is done correctly, otherwise I should see an alert on screen. The strange behaviour is the “BuyOffer” button: once tapped the offer to buy, it simply does nothing. On other devices it shows correctly the password check to buy the IAP, on iPhone 12 nothing at all (consumable and not). I put alerts in every check, null product, incorrect product id, ecc…it does not show anything, so it looks like InitiatePurchase is being called ( but I’m not sure ).
Unfortunately we don’t have a Mac, I build on MacInCloud with XCode 13. Is there another method to see logs? Thanks

You would need to instrument your build and test yourself, or release to TestFlight with limited testers. Write the debug output to the UI, perhaps into a top layer text element. This is what I do in the Sample IAP Project here. It’s handy for debugging when you don’t have access to the device logs, I place a MyDebug() statement in every purchasing method so I can properly debug. https://discussions.unity.com/t/700293/3

  1. Drop a text object into your scene, perhaps on the current canvas
  2. Make it big enough to fit several lines of debug output
  3. Pass this object into the purchasing script
public Text myText;
...

public void OnInitializeFailed(InitializationFailureReason error)
    {
        // Purchasing set-up has not succeeded. Check error for reason. Consider sharing this reason with the user.
        MyDebug("OnInitializeFailed InitializationFailureReason:" + error);
    }

private void MyDebug(string debug)
    {
      
        Debug.Log(debug);
        myText.text += "\r\n" + debug;
    }

Thanks for advice Jeff. I will work on it and see if initialization is done properly. By the way, I just tested on a friend’s iPhone 12 with TestFlight and it works with iOS 14.8. He’s updating to iOS 15 to re-test, I must know if it’s related to iOS 15 release as I think.
I’m going to share the results as soon as I have them.

I just updated my iPhone 12 to iOS 15 and IAP 4.0.3 is working for me. I was able to make a purchase. Are you using Scripted or Codeless IAP? I’m testing with Scripted IAP (the Sample IAP Project v2)

It’s very very odd. The other iPhone 12 of my friend, after iOS 15, still works, as yours. BUT, he did not turn on face detection. Is your phone using it? It looks like the only difference.
However, I tried testing with alert and logs and everything is fine, I put an alert just before InitiatePurchase and it shows up, for every product. So IAP is being initialized correctly, it loads products correctly and InitiatePurchase correctly. Then, there is a veeeery long waiting to show password check after an offer button is tapped ( 20 seconds and it shows up rarely ).
For IAP version, I’m not sure but I think I’m using scripted one, because I use the plugin Easy Mobile Pro to simplify cross platform for a lot of things.

I was wrong, after iOS 15 update every in app purchase stopped working. It’s very strange that every iPhone works and the two that updated to iOS 15 stopped working with the same build.
I will try to test with your Sample IAP project V2 as you said. I really hope to solve this problem :frowning:

Please provide the device logs with the additional Debug.Log output as mentioned.

Is there a method to have logs without an iPhone plugged in a Mac?
Also, do you have an idea on why face ID is not used and the IAP still uses password?
Thank you

Yes, please see this previous post https://discussions.unity.com/t/856595/4 Apple probably doesn’t use FaceID because you would likely be logging in with a separate Sandbox account, not the phone profile account associated with FaceID on the device.

Ok thank you Jeff! I’ll update as soon as I have news!

Hi @PopsawayGames ,

Have you resolved your problem yet?
My game also has problems with IAP (v3.1.0, v3.2.3 & v4.0.3) on iOS 15.
IAP always fails to initialize.

Hi @JeffDUnity3D ,
This is my log:

2021-10-01 01:16:51.334103+0700 sniperzombies[1966:338835] UnityIAP UnityEarlyTransactionObserver: Created
2021-10-01 01:16:51.334889+0700 sniperzombies[1966:338835] UnityIAP UnityEarlyTransactionObserver: Registered for lifecycle events
2021-10-01 01:16:51.426958+0700 sniperzombies[1966:338835] FCM: Loading UIApplication FIRFCM category
2021-10-01 01:16:51.505529+0700 sniperzombies[1966:338835] FIID: Loading UIApplication FIRIID category
2021-10-01 01:16:51.951184+0700 sniperzombies[1966:338835] You've implemented -[<UIApplicationDelegate> application:didReceiveRemoteNotification:fetchCompletionHandler:], but you still need to add "remote-notification" to the list of your supported UIBackgroundModes in your Info.plist.
2021-10-01 01:16:52.752986+0700 sniperzombies[1966:338835] UnityIAP UnityEarlyTransactionObserver: Added to the payment queue
Main Thread Checker: UI API called on a background thread: -[UIApplication statusBarOrientation]
a background thread: -[UIApplication statusBarOrientation]
Main Thread Checker: UI API called on a background thread: -[UIApplication delegate]
2021-10-01 01:17:20.533391+0700 sniperzombies[1966:339391] [reports] Main Thread Checker: UI API called on a background thread: -[UIApplication delegate]
Main Thread Checker: UI API called on a background thread: -[UIApplication setDelegate:]
2021-10-01 01:17:21.315742+0700 sniperzombies[1966:339391] [reports] Main Thread Checker: UI API called on a background thread: -[UIApplication setDelegate:]
IAPManager: Init product
IAPManager:InitProducts()
2021-10-01 01:17:23.256265+0700 sniperzombies[1966:338835] UnityIAP: Requesting 66 products
2021-10-01 01:17:23.263578+0700 sniperzombies[1966:338835] UnityIAP: Requesting product data...
2021-10-01 01:17:58.266975+0700 sniperzombies[1966:338835] [BackgroundTask] Background Task 9 ("SKProductsRequest"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(_:) for your task in a timely manner to avoid this.

Could you please take a look?
The IAP work well on iOS < 15.

Thank you so much,
Huy

I’m not seeing any errors that I recognize? How do the non-iOS15 logs compare? Is OnInitializedFailed being called?

Sorry @JeffDUnity3D ,
I will update more detail for log.

Hello!
I finally solved my problem. My company provided me a Mac Mini to debug my build.
This is what happened to me: at initialization, Unity IAP recovers the products from Apple.
This is a strange and unexpected behavious for me, because the products are somehow purchased, in fact OnPurchaseComplete was called for every product in my logs.
Since I have some logic there that is bound to the offer to be bought (this is very bad and I will solve it), at initialization on app start, let’s say, this logic was not valued and throwed a damned NullPointer (on the first product).
That exception caused the cycle on products to be stopped, so when tester tapped on an offer button, the app was in a strange loop of never receiving the password field input panel.
After catching exception, everything worked!
I don’t know why but on iOS 15 this bug caused every IAP to stop working, on older versions of iOS instead it worked ONLY on first app start, that’s why I didn’t notice it.
As always, logs saved my life. Thanks a lot for help @JeffDUnity3D ! I hope this will help you too @Huy_Ng

Hi @JeffDUnity3D

After I put some logs, I get result as image below:

And when I make a purchase, nothing happens because m_StoreController and m_StoreExtensionProvider are null.
And of course OnInitialized & OnInitializedFailed are not called.

Hi @PopsawayGames
In my case, I don’t get any exception :frowning:

Where are you initializing IAP in your code? Please post code with Code tags here (the Code: button in the edit ribbon), not as images, thanks. IAP initializes on non iOS12 devices for you? I have an iOS 12 device here and IAP work fine.

Hi @JeffDUnity3D ,

In my game:
IAP does not initialize on iOS15. It works fine on iOS14.x, 13.x, …
The problem only occurred when Apple released iOS15.

Here are my code:

public class IAPManager : MonoBehaviour, IStoreListener, IEventSender
{
    private static IAPManager _Instance;
    public static IAPManager Instance
    {
        get
        {
            if (_Instance == null)
            {
                GameObject gameObject = new GameObject("IAPManager");
                _Instance = gameObject.AddComponent<IAPManager>();
            }
            return _Instance;
        }
        set
        {
            _Instance = value;
        }
    }

    private IStoreController m_StoreController;
    private IExtensionProvider m_StoreExtensionProvider;
    private IAppleExtensions m_AppleExtensions;
    private IGooglePlayStoreExtensions m_GooglePlayStoreExtensions;

    private IAPInitStatus m_IAPInitStatus = IAPInitStatus.None;
    public IAPInitStatus Status
    {
        get
        {
            return m_IAPInitStatus;
        }
        set
        {
            m_IAPInitStatus = value;
        }
    }

    private void Start()
    {
        DontDestroyOnLoad(gameObject);
    }

    public void Init()
    {
        InitProducts();
    }

    void InitProducts()
    {
        Debug.Log("IAPManager: Init product");

        m_IAPInitStatus = IAPInitStatus.None;

        var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());

        foreach(var iap in ConfigIAPProduct.Instance.dataArray)
        {
            string productid = iap.ID;
            ProductType producttype = iap.Type;
            builder.AddProduct(productid, producttype, new IDs() { { productid, AppleAppStore.Name}, {productid, GooglePlay.Name}});
        }

        UnityPurchasing.Initialize(this, builder);
    }

    public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
    {
        // Purchasing has succeeded initializing. Collect our Purchasing references.
        Debug.Log("OnInitialized: PASS");

        // Overall Purchasing system, configured with products for this application.
        m_StoreController = controller;
        // Store specific subsystem, for accessing device-specific store features.
        m_StoreExtensionProvider = extensions;

        m_AppleExtensions = extensions.GetExtension<IAppleExtensions>();
        m_GooglePlayStoreExtensions = extensions.GetExtension<IGooglePlayStoreExtensions>();

        // On Apple platforms we need to handle deferred purchases caused by Apple's Ask to Buy feature.
        // On non-Apple platforms this will have no effect; OnDeferred will never be called.
        m_AppleExtensions.RegisterPurchaseDeferredListener(OnDeferred);

        m_IAPInitStatus = IAPInitStatus.Successed;
    }

    public void OnInitializeFailed(InitializationFailureReason error)
    {
        // Purchasing set-up has not succeeded. Check error for reason. Consider sharing this reason with the user.
        Debug.Log("OnInitializeFailed InitializationFailureReason:" + error);

        if (waitProductId != "")
        {
            GameUtilities.HidePopupWaiting();
        }

        m_IAPInitStatus = IAPInitStatus.Failed;
    }

    public bool IsInitialized()
    {
        // Only say we are initialized if both the Purchasing references are set.
        return m_StoreController != null && m_StoreExtensionProvider != null;
    }
}

Tomorrow, I will try your IAP with an empty project on iOS15.

Thanks,
Huy