StoreKit 2 linking fails in iOS 14.5 simulators

Originator:andy
Number:rdar://FB9634656 Date Originated:September 17, 2021
Status:Open Resolved:
Product:StoreKit Product Version:15.0
Classification:Application Crash Reproducible:Yes
 
In iOS 14.5 simulator, if an instance of StoreKit.Product is saved to a local property, linking fails with the error: 

```
dyld: lazy symbol binding failed: Symbol not found: _$s8StoreKit7ProductVMa
```

I’m including a sample project that demonstrates this. 
To reproduce, just open RevenueCat.xcodeproj, select the RevenueCat scheme, and run tests on a simulator on iOS 14.5 or lower. 
You’ll experience a crash right away, in `BreakLinkingFor14_5.swift`. 

If the file gets commented out, the crash disappears. The file only contains a single property, a StoreKit.Product.

Note that the file does have the correct `@available` checks for iOS 15.0. 

This makes it nearly impossible to even reference StoreKit 2’s features on an app with a deployment target lower than iOS 15, even when API availability checks are in place. 

The sample project is also available at https://github.com/RevenueCat/purchases-ios/tree/storekit_2_linking_issue_demo.

Comments

Apple feedback:

After reviewing your feedback, we have some additional information for you, or some additional information, or action is necessary for this issue:

XCTest is locating test classes by fetching all loaded classes with objc_copyClassList, then searching for XCTest subclasses. Unfortunately, the ObjC and Swift runtimes don't handle availability properly in this case, and this call attempts to provide the SK2ProductDetails class even though it's not available on the current OS. Setting up this class requires fetching the type metadata for StoreKit.Product, which crashes since that type isn't present in the OS.

There are two ways to work around this:

  1. Use Any as the type of the stored property, and cast with as! StoreKit.Product when retrieving the value. Referencing StoreKit.Product in code that doesn't execute is safe, it just needs to not be the type of a stored property.
  2. Hide the class from the ObjC runtime by adding a generic parameter. For example:

public class SK2ProductDetails: NSObject { ...

Then use SK2ProductDetails (or or anything else) to refer to the type in code. This means that the class can't be @objc as it is in the example, so this may not be workable here.


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!