7

We can use Framework SwiftUI only from iOS 13.0+. So how to incorporate this framework from the deployment Target 10.0 or at least 12.0.

enter image description here

Shamil
  • 727
  • 1
  • 9
  • 17
  • 7
    Doesn't your first sentence basically answer the second? – rmaddy Jun 06 '19 at 21:39
  • @maddy, No. there should be a way. Some thing like #available 13.0 – Shamil Jun 06 '19 at 21:41
  • 4
    How do you plan to use a UI made from SwiftUI if your app is running on an iOS 12 device? Since you can't, do you plan on writing two completely separate UIs for your app? One in UIKit and one in SwiftUI? That's a painful plan. – rmaddy Jun 06 '19 at 21:43

3 Answers3

12

Although @DenFav is absolutely right - supporting deployment target below iOS 13 with SwiftUI is a pain, but it is possible.

Steps:

  1. Link the framework weakly (I used this answer):

    Adding -weak_framework SwiftUI to Other Linker Flags fixed my issue

  2. Wrap all SwiftUI calls with canImport (see answer):

    #if canImport(SwiftUI) && canImport(Combine)

This will allow you to build and archive with deployment target < iOS 13.

Optional:

Now the question is: how to deal with viewModels. I solved this with my own implementation. You can check the solution in the public repo of Ruuvi Station. Note: the code is complex (VIPER), that's why I'll shortly describe the main ideas.

The viewModel implementation is in Classes/Presentation/Binding.

I'm using these viewModels, wrapping them with ObservableObject for SwiftUI.

You can still observe changes made in SwiftUI code.

The result is: iOS 13 uses SwiftUI code for Presentation Layer, while iOS 12 and lower is using traditional UIKit code.

The viewController is responsible for determining if SwiftUI code can be used.

Community
  • 1
  • 1
Renatus
  • 1,123
  • 13
  • 20
  • After trying this , it will compile and able to execute on Simulator. But failing to archive :( – Badrinath Jan 29 '20 at 04:33
  • I also tried the above plus `@available(iOS 13.0, iOSApplicationExtension 13.0, *)` and got the following error messages when trying to Archive: `Use of undeclared type 'View'`, `Use of undeclared type 'AnyView'`, etc. Pretty much anything coming from SwiftUI. Any ideas? – Jose Santos Mar 05 '20 at 22:47
  • 1
    I finally made it work after hours of research and settings tweaking. It turns out that my iOS Deployment Target was set at 10.0 but the above recommendations work for 11.0 and later. So, for those that still can't make it work in spite of the recommendations, check your iOS Deployment Target – Jose Santos Mar 07 '20 at 06:09
2

Build Phases → Link Binary With Libraries → Add SwiftUI.framework (Status: Optional)

import SwiftUI

@available(iOS 13.0, *)
struct SwiftUIView : View {
    var body: some View {
        Text("Hello World!")
    }
}

@available(iOS 13.0, *)
struct SwiftUIView_Previews : PreviewProvider {
    static var previews: some View {
        SwiftUIView()
    }
}

etc.

SwiftUI preview for this target doesnʼt work, but you can add a special target “SwiftUI Preview”.

  • This doesn't seem to be working. I have an iOS project targeting iOS 11, but I wanna build around with SwiftUI and re-build one of my UIKit views, only making it available for iOS 13 users. Im trying to use this method but getting a few errors. Were you ever able to get this to work? – MikeG Sep 13 '19 at 17:02
  • @MikeG, this works in my current iOS project targeting iOS 12. What errors are you getting? – Roman Kerimov Sep 14 '19 at 18:31
  • 4 different errors 1) `Inheritance from non-protocol type 'View'` 2) `Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type` 3) `Cannot convert return expression of type 'Text' to return type 'some View` 4) `Type 'SwiftUIView_Previews' does not conform to protocol 'PreviewProvider` – MikeG Sep 16 '19 at 14:41
  • @MikeG, I checked again on a new project targeting iOS 11. It works and I do not have such errors. Do you added @available(iOS 13.0, *) for all views and preview providers in your project? – Roman Kerimov Sep 16 '19 at 18:06
  • Thanks for checking. All i did to test was add a new file, copy paste the code you have above, and add `SwiftUI.framework (Status: Optional)` to the build phases "Link Binaries with Libraries" section. I have lots of other views in my app but those are all `UIView` built with `UIKit` and shouldn't need any changing. There are no other preview providers in my app. – MikeG Sep 16 '19 at 20:37
  • @MikeG, then I do not know what might be causing the errors in your case. – Roman Kerimov Sep 16 '19 at 23:46
0

There is no reasonable way to do that. #available or @available allow you to differentiate some pieces of code or whole classes but not app itself.

You can use @available to silence warnings of SwiftUI structure or classes with 12.0 Deployment target but in this case you need to completely duplicate UI from storyboards(.xib, whatever) using Swift UI. Moreover, completely different "binding" approach will also require you to reimplement existing logic across that app(doesn't matter what kind of architecture you have used before). Any VIPER, VIP, MVC is aimed to send some data change notifications to a ViewController(View)? in Swift UI you need to use Bindable objects. It also causes you to create duplicates of ViewModels(if you have such) because they will be different.

Result? You have second implementation of UI, second implementation of view models, additional 80% of implementation of presenter(or what do you use). Only database and rest managers will be reused. And this is valid if you have very good architecture. Don't forget that you need to support two branches of UI and logic.

There is two ways: redevelop almost full application to support SwiftUI and UIKit or, if you don't want to have only one iOS 13 supported, wait until iOS 14 will be released and then support both of them with SwiftUI

DenFav
  • 2,683
  • 1
  • 18
  • 27