Search code examples
iosswiftswiftuiios-app-extension

iOS - Ship Widget Extension with app having deployment target < 14


Is it possible to include a widget extension into the host app which deployment target is for example 10.3.2?

The idea is - if a device supports extensions (ie has iOS >= 14) it should use the widget, else not (iOS < 14).

The problem is it's even not possible to compile the widget target if its deployment version differs from the host's one - they should be equal (>= 14).

If not than we have errors like that, I suppose because of different Swift versions used to compile older and newer deployment targets. Extensions require at least Swift 5.1 that supports Opaque Types (some attribution) used in widgets.

Undefined symbol: _swift_getOpaqueTypeConformance
Undefined symbol: _swift_getTypeByMangledNameInContextInMetadataState

The above obstacle seems to be the most important that prevents building my SwiftUI extension for an older runtime, because else I could use @available(iOS 14.0, *) for the whole extension to suppress errors about incompatibility.

So my other idea was to build the widget with an other host target having iOS 14 and then copy resulting appex bundle to the real target supporting iOS 10.3.2, but I still don't know if it would work and worth to try.

Any suggestions are welcome

UPD

Found this thread with a solution like that

Xcode was auto-resolving WidgetKit and implicitly adding it as a required framework. Adding it manually as an optional framework fixed the issue.

But I actually do not understand where should I add WidgetKit "manually as an optional framework"?

UPD 2

I added WidgetKit manually to host target too using Link Binary With Libraries build phase with Optional status and made the same for widget target, it did not help either, errors stay the same.

Curious point: if I clean the project and rebuild it, it gets compiled successfully, but only first time, if I run building second time, above errors occur again.

UPD 3

OK nearing the heart of darkness. Created a test project from scratch with Objective C (just like in my main project) host 10.3.2 target and a widget 14.1 target and it just works without additional setup.

Problem seems to be in Cocoapods where I initially used nested target like this

target 'Host' do
    shared_pods

    target 'Widget' do
        inherit! :search_paths
    end
end

What I did is to move out widget target romoving prefs inheritance, and it builds now (but without pods!)

target 'Host' do
    shared_pods
end

target 'Widget' do
    shared_pods # another errors uhhh
end

Next challenge is to make widget use pods that host app uses

UPD 4

Tried to add/remove $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) in various combinations to all affected targets - no success. Some people add swift-5.2 but how should it work if such directory does not exist inside $(TOOLCHAIN_DIR)/usr/lib.

swift -version gives me Apple Swift version 5.3.2, but some people say it's not necessary this version will be used in my project


Solution

  • Solved by upgrading Xcode from 12.4 to 12.5 and system to Big Sur (because Xcode required it). Don't know what magic is behind this, maybe something with Swift version.

    • no need for $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
    • no need for @available(iOS 14.0, *) for widget code
    • no need to use config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.1' for widget pod target in Podfile post_install hook