# @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

### 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).
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