Unreal 5.6, IOS Subsystem->GetStoreV2Interface() failing on majority of devices

Unreal 5.6, IOS Subsystem->GetStoreV2Interface() failing on some devices.

We have traced it so far : OnlineSubsystemIOS seems to be initialized :

[UE] LogOnline: Display: OSS: FOnlineSubsystemIOSModule::StartupModule()
[UE] LogOnlineSession: Display: OSS: FOnlineSessionIOS::FOnlineSessionIOS(FOnlineSubsystemIOS* InSubsystem)
[UE] LogOnline: OSS: Created online subsystem instance for: IOS
[UE] LogOnline: OSS: TryLoadSubsystemAndSetDefault: Loaded subsystem for type [IOS]

but we do NOT see this line in the log ( on a working device )

[UE] LogOnlineSession: Display: OSS: FOnlineSessionIOS::FOnlineSessionIOS(FOnlineSubsystemIOS* InSubsystem)

Continuing onwards, in the game we proceed to check that things are ok :

const IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());that is fine, but

const IOnlineStoreV2Ptr Store = Subsystem->GetStoreV2Interface();this GetStoreV2Interface fails silently ( no errors or warnings ).

Included are 2 full log files, one which works and one which fails. ( The one which works is far more verbose due to being QA device with logs from 3uTools, not xcode )

Our current devices, OS and test results : NO = not working

iPad 8 | iPad 18.1.1 | NO

iPhone 11 Pro | 18.3.1 | NO

iPad 9 | iPad 17.6.1 | NO

iPhone 13 mini | iOS 26.1 | NO

iPhone 11 ProMax | iOS 15 | YES

iPhone 8 | iOS 16.7.7 | YES

We have tried updating OS on some of the failing devices to no avail. Looking at the devices, it seems that older OS are working, newer ones failing.

Here’s the function code, where we hit

StoreV2_QueryOffers: Subsystem->GetStoreV2Interface() Store was invalid."));:

Proceeding to make a small test project repro…

bool UStoreSubsystem::StoreV2_QueryOffers()
{
	TArray<FString> OfferIds;
	OffersByCheckoutId.GenerateKeyArray(OfferIds);
 
	const IOnlineSubsystem* Subsystem = Online::GetSubsystem(GetWorld());
	if (!Subsystem)
	{
		UE_LOG(LogStore, Log, TEXT("TRACE StoreV2_QueryOffers: Subsystem was invalid."));
	}
	
	if (Subsystem)
	{
		UE_LOG(LogStore, Log, TEXT("TRACE StoreV2_QueryOffers: proceeding."));
		
		const IOnlineStoreV2Ptr Store = Subsystem->GetStoreV2Interface();
		if (!Store.IsValid())
		{
			UE_LOG(LogStore, Log, TEXT("TRACE StoreV2_QueryOffers: Subsystem->GetStoreV2Interface() Store was invalid."));
		}
		
		const IOnlineIdentityPtr IdentityInterface = Subsystem->GetIdentityInterface();
		if (!IdentityInterface.IsValid())
		{
			UE_LOG(LogStore, Log, TEXT("TRACE StoreV2_QueryOffers: Subsystem->GetIdentityInterface() IdentityInterface was invalid."));
		}
		
		if (Store.IsValid() && IdentityInterface.IsValid())
		{
			UE_LOG(LogStore, Log, TEXT("TRACE StoreV2_QueryOffers: Store + IdentityInterface were valid."));
			auto AccountId = IdentityInterface->GetUniquePlayerId(0);
			if (!AccountId.IsValid())
			{
				UE_LOG(LogStore, Log, TEXT("TRACE StoreV2_QueryOffers: AccountId was invalid."));
				AccountId = FUniqueNetIdString::EmptyId();
			}
 
			UE_LOG(LogStore, Log, TEXT("TRACE StoreV2_QueryOffers: Query about to begin."));
			
			Store->QueryOffersById(*AccountId, OfferIds,
			                       FOnQueryOnlineStoreOffersComplete::CreateUObject(
				                       this, &UStoreSubsystem::StoreV2_OnQueryOffersComplete));
			UE_LOG(LogStore, Log, TEXT("QUERY: Query started."));
			return true;
		}
	}
	
	UE_LOG(LogStore, Log, TEXT("QUERY: No store on this platform."));
	bIsQueryOffersComplete = true;
	OnQueryOffersComplete.Broadcast();
	return false;
}

Reproed on Test Project, 5.7 Stock Engine. Will attach the full test project soon, need to clean out some cruft

Here is a 5.7 project where we reproduce the issue by clicking the “Store” button at the bottom center of the screen, with the resulting output:

“GetStoreV2Interface is NOT valid.”

Adding a packaging log for completeness:

The fact we are missing this line in the logs seems to indicate something deeply wrong, should be happening in OnlineSubsystemIOS.cpp FOnlineSubsystemIOS::Init() function:

OSS: FOnlineSessionIOS::FOnlineSessionIOS(FOnlineSubsystemIOS* InSubsystem)

Proceeding to add more logs to our source fork…

Tracing via source fork: we hit this point:

OSS: TRACE IsInAppPurchasingEnabled FMarketplaceKitModule != EMarketplaceType::AppStore

So… what does this mean now.

#if UE_WITH_STORE_KIT
		if (IsInAppPurchasingEnabled())
		{
			UE_LOG_ONLINE(Log, TEXT("TRACE IsInAppPurchasingEnabled is TRUE"));
#if !PLATFORM_TVOS && !PLATFORM_VISIONOS		// tvOS & VisionOS ONLY support AppStore
			if (FMarketplaceKitModule::GetCurrentTypeStatic() == EMarketplaceType::AppStore)
#endif
			{
				UE_LOG_ONLINE(Log, TEXT("TRACE IsInAppPurchasingEnabled is TRUE and makeShareable commences"));
				StoreV2Interface = MakeShareable(new FOnlineStoreIOS(this));
				PurchaseInterface = MakeShareable(new FOnlinePurchaseIOS(this));
			}
			else
			{
				UE_LOG_ONLINE(Warning, TEXT("TRACE IsInAppPurchasingEnabled FMarketplaceKitModule != EMarketplaceType::AppStore"));
			}
		}
		else
		{
			UE_LOG_ONLINE(Warning, TEXT("TRACE IsInAppPurchasingEnabled is FALSE"));
		}
#endif

So, we are still building to verify, but I strongly believe this line is messing things up :

  1. #if !PLATFORM_TVOS && !PLATFORM_VISIONOS // tvOS & VisionOS ONLY support AppStore
  2. if (FMarketplaceKitModule::GetCurrentTypeStatic() == EMarketplaceType::AppStore)
  3. #endif

Maybe it was meant to be checking PLATFORM_TVOS || PLATFORM_VISIONOS ?

Now with IOS, there seems to be also EMarketplaceType::Testflight

Anyhow, I am hopeful that this is the problem, and will report back once verified.

Confirmed. So, notes:

!PLATFORM_TVOS && !PLATFORM_VISIONOS <<< This is never going to work. You can’t AND two NOT booleans… even if it is TVOS, then it’s not going to be VISIONOS.

Also, if we indeed have both AppStore and Testflight EMarketplaceTypes, I do hope they are not mixed up anywhere else in code, as they should both work.

Hi Tuomas,

Regarding ‘!PLATFORM_TVOS && !PLATFORM_VISIONOS’, this looks fine as it excludes a code path for either TVOS or VISIONOS which do not support multiple marketpaces.

As for the issue at hand, it appears you have unveiled an Xcode bug whereby the deployment marketplace despite showing as ‘App Store’ in the scheme UI doesn’t deploy the application to the device as such. The reason you are seeing this on devices with iOS 18 and higher is that multiple MarketPlace iOS support didn’t exist before this. To work around the issue, edit the Launch Scheme from Xcode, go to the Options tab, go to the Distribution setting (already set to App Store), select and pick App Store from the drop down again and relaunch. This should result in the distribution to be properly set and the code should follow the proper AppStore branches on iOS 18 and higher devices. Note that this would function as expected in production environments.

[Image Removed] [Image Removed]

We will look into workarounds that would resolve this out of the box for future releases of UE.

Best regards.

Hi Tuomas,

The comment reads tvOS & visionOS ONLY support AppStore to indicate that there is no need to check for current marketplace on those platforms, unlike iOS which supports outside of App Store distribution.

We’ve provided a fix to address the initial issue that works around the Xcode/xcrun defaults and launches the app under AppStore conditions rather than Other marketplace. See CL 48772731.

Best regards

No problem at all, thank you for bringing this issue to our attention.

Reproed on our Test Project, 5.6 Stock Engine

Interesting, thank you.

Just to sanity check this tvos/visionos thing:

#if !PLATFORM_TVOS && !PLATFORM_VISIONOS // tvOS & VisionOS ONLY support AppStore

if (FMarketplaceKitModule::GetCurrentTypeStatic() == EMarketplaceType::AppStore)

#endif

  • // tvOS & VisionOS ONLY support AppStore

The comment indicates that the if statement should be run if the project is TVOS or VISIONOS.

It doesn’t make sense to me to then run the == check for all platforms OTHER than TVOS/VISIONOS.

In any case, we are now proceeding by disabling that check in our source fork, since we cannot be fidding with xcode everytime project is regenerated.

Thank you, I reckon the ticket can be closed.

Super thanks!

We have added https://github.com/EpicGames/UnrealEngine/commit/4a917150c4071d3ec571a0e2eb5f9509cf8d6831

to our source fork, but the problem remains. Are you certain this has been tested in your internal QA?

( Note we are still fine with our hacky workaround, no emergency for us )

Hi Tuomas,

This was confirmed working when launching the project from Xcode or from the UE project launcher/QuickLaunch. However, this would indeed not cover the case of an installed package user launched on an iOS device. Which case wasn’t working for you?

Best regards.

Testflight builds, added logging current type:

LogOnline: OSS: TRACE IsInAppPurchasingEnabled EMarketplaceType: TestFlight

Hi Tuomas,

Yes, it would make sense to enable that path for both the AppStore and TestFlight distributor for IAP testing in the IAP sandbox. Will follow up with a CL to cover that case as follows:

[Image Removed]Many Thanks.