# @nativescript/swift-ui Use SwiftUI with NativeScript. ## Contents - [@nativescript/swift-ui](#nativescriptswift-ui) - [Contents](#contents) - [Installation](#installation) - [Usage](#usage) - [1. Create your SwiftUI view](#1-create-your-swiftui-view) - [2. Create your SwiftUI view Provider](#2-create-your-swiftui-view-provider) - [3. Register your SwiftUI with an identifier and use it in markup](#3-register-your-swiftui-with-an-identifier-and-use-it-in-markup) - [Core](#core) - [Generate Types](#generate-types) - [SwiftUI with Angular](#swiftui-with-angular) - [SwiftUI with Vue](#swiftui-with-vue) - [SwiftUI with React](#swiftui-with-react) - [Open Multiple Scenes](#open-multiple-scenes) - [Passing contextual data to scenes](#passing-contextual-data-to-scenes) - [Closing windows](#closing-windows) - [Use NativeScriptView inside SwiftUI](#use-nativescriptview-inside-swiftui) - [Credits](#credits) - [License](#license) ## Installation ```cli npm install @nativescript/swift-ui ``` > **Note**: you will need to target iOS 13 at a minimum. For example, you can add this line to your `App_Resources/iOS/build.xcconfig`: ``` IPHONEOS_DEPLOYMENT_TARGET = 13.0 ``` > **Note**: If you would like to use `NativeScriptView` inside SwiftUI, you should target 14.0 minimum. ## Usage ![SwiftUI Source Files Example](/packages/swift-ui/swift-ui-source-files-example.png) ### 1. Create your SwiftUI view This can be any SwiftUI view you'd like to create. ```swift import SwiftUI struct SampleView: View { var body: some View { VStack { Text("Hello World") .padding() } } } ``` ### 2. Create your SwiftUI view Provider This will prepare your SwiftUI for two-way data bindings to NativeScript and follows the plugins' `SwiftUIProvider` protocol to standardize all SwiftUI bindings. ```ts import SwiftUI @objc class SampleViewProvider: UIViewController, SwiftUIProvider { // MARK: INIT required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } required public init() { super.init(nibName: nil, bundle: nil) } public override func viewDidLoad() { super.viewDidLoad() setupSwiftUIView(content: swiftUIView) } // MARK: PRIVATE private var swiftUIView = SampleView() /// Receive data from NativeScript func updateData(data: NSDictionary) { // can be empty } /// Allow sending of data to NativeScript var onEvent: ((NSDictionary) -> ())? } ``` ### 3. Register your SwiftUI with an identifier and use it in markup This can be done in the bootstrap file (often `app.ts` or `main.ts`) or even the view component that needs it. #### Core ```typescript import { registerSwiftUI, UIDataDriver } from "@nativescript/swift-ui"; // A. You can generate types for your own Swift Provider with 'ns typings ios' // B. Otherwise you can ignore by declaring the class name you know you provided declare const SampleViewProvider: any; registerSwiftUI("sampleView", (view) => new UIDataDriver(SampleViewProvider.alloc().init(), view) ); registerSwiftUI("barChart", (view) => new UIDataDriver(BarChartProvider.alloc().init(), view) ); ``` Then insert it in any layout as follows: ```xml ``` #### Generate Types 1. To generate types for your SwiftUI code, run `ns typings ios`. 2. Locate the `objc!nsswiftsupport.d.ts` file in `typings/x86_64` and reference it in the `references.d.ts`. #### SwiftUI with Angular Register SwiftUI follows: ```ts import { registerElement } from '@nativescript/angular' import { SwiftUI } from '@nativescript/swift-ui' registerElement('SwiftUI', () => SwiftUI) registerSwiftUI("sampleView", (view) => new UIDataDriver(SampleViewProvider.alloc().init(), view) ); registerSwiftUI("barChart", (view) => new UIDataDriver(BarChartProvider.alloc().init(), view) ); ``` It can now be used within any Angular component, eg: ```html ``` #### SwiftUI with Vue Register SwiftUI follows: ```ts registerElement("SwiftUIView", ()=> require("@nativescript/swift-ui").SwiftUI) registerSwiftUI("sampleView", (view) => new UIDataDriver(SampleViewProvider.alloc().init(), view) ); registerSwiftUI("barChart", (view) => new UIDataDriver(BarChartProvider.alloc().init(), view) ); ``` Then use it in markup as follows: ```xml ``` #### SwiftUI with React Register SwiftUI follows: ```ts registerSwiftUI("sampleView", (view) => new UIDataDriver(SampleViewProvider.alloc().init(), view) ); registerSwiftUI("barChart", (view) => new UIDataDriver(BarChartProvider.alloc().init(), view) ); interface SwiftUIViewAttributes extends ViewAttributes{ swiftId: string } declare global { module JSX { interface IntrinsicElements { swiftUIView: NativeScriptProps } } } registerElement("swiftUIView", ()=> require("@nativescript/swift-ui").SwiftUI) ``` Then use it in markup as follows: ```xml ``` ## Open Multiple Scenes When using a SwiftUI App Lifecycle setup for your NativeScript app, *the default with* [visionOS](https://docs.nativescript.org/guide/visionos) *development*, you can enable multiple scenes in your `Info.plist` with the following: ```xml UIApplicationSceneManifest UIApplicationPreferredDefaultSceneSessionRole UIWindowSceneSessionRoleApplication UIApplicationSupportsMultipleScenes UISceneConfigurations ``` You can now use `WindowManager` (for use with standard Windows) or `XR` (for use with immersive spaces) to interact with multiple scenes, for example: ```swift @main struct NativeScriptApp: App { @State private var immersionStyle: ImmersionStyle = .mixed var body: some Scene { NativeScriptMainWindow() WindowGroup(id: "NeatView") { NeatView() } .windowStyle(.plain) ImmersiveSpace(id: "NeatImmersive") { NeatImmersive() } .immersionStyle(selection: $immersionStyle, in: .mixed, .full) } } ``` You could open the `WindowGroup` with: ```ts import { WindowManager } from "@nativescript/swift-ui"; WindowManager.getWindow("NeatView").open(); }); ``` And you could open the `ImmersiveSpace` with: ```ts import { XR } from "@nativescript/swift-ui"; XR.requestSession("NeatImmersive"); ``` You could update either scene with: ```ts import { WindowManager } from "@nativescript/swift-ui"; // Option A: inline WindowManager.getWindow("NeatView").update({ title: 'Updated Title' }); // Option B: reference const neatView = WindowManager.getWindow("NeatView"); neatView.update({ title: 'Updated Title' }); // Both options work with XR/Immersive Spaces as well, for example: WindowManager.getWindow("NeatImmersive").update({ salutation: 'Hello World' }); ``` ### Passing contextual data to scenes You can use the `onReceive` modifier in SwiftUI to handle any data passed to your windows. For example, anytime `WindowManager.getWindow("Window_ID").update(...)` is called, a Notification is dispatched which can be picked up for data to be handled: ```swift struct NeatView: View { @State var context: NativeScriptWindowContext? var body: some View { ZStack { // more neat views here }.onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("NativeScriptWindowUpdate")), perform: { obj in context = NativeScriptWindowFactory.shared.getContextForId(id: "NeatView") let title = context!.data["title"] as! String // use your updated title! }) } } ``` ### Closing windows `WindowManager.getWindow("NeatView").close()` for a Window which is already open will close it. `XR.endSession()` for an Immersive Space which is already open will close it. ## Use NativeScriptView inside SwiftUI You can also use NativeScript view layouts and components inside SwiftUI when targeting iOS 14.0 minimum. Add this line to your `App_Resources/iOS/build.xcconfig`: ``` IPHONEOS_DEPLOYMENT_TARGET = 14.0 ``` You can now register as many NativeScript views by an id for usage: ```ts import { SwiftUIManager } from '@nativescript/swift-ui'; SwiftUIManager.registerNativeScriptViews({ Video: SceneVideoComponent }); ``` This will allow `SceneVideoComponent`, a NativeScript view component, to be used inside any SwiftUI component: ```swift struct ContentView: View { var body: some View { ZStack { NativeScriptView(id: "Video") } } } ``` ## Credits - WindowManager and XR APIs were established with the Callstack team. Shoutout to: [Oskar Kwaƛniewski](https://github.com/okwasniewski). Valor Software NativeScript is proudly supported by Valor Software as an official partner. We are proud to offer guidance, consulting, and development assistance in all things NativeScript. [Contact Valor for assistance](https://valor-software.com/). ## License MIT