/SwiftUI-Simulator

:iphone: Simulate device configurations in real-time. (and useful tools for development)

Primary LanguageSwiftMIT LicenseMIT

SwiftUI-Simulator

Simulate device configurations in real-time. (and useful tools for development)

2022-04-14.15.16.50.mov

Feature

Simulation

  • Any device screen
  • Light/Dark mode
  • Locale
  • Calendar
  • TimeZone
  • Dynamic Type Sizes (iOS 15+)
  • Rotate
  • Legibility Weight (Not working in latest iOS and Xcode preview)

Note: This is only a simulation and may differ from how it looks on a simulator or real device.

UserDefaults browser

You can browse and edit UserDefaults.

Browse Edit (as JSON) Edit (Date) Export
image image image image

Supported types:

  • Property list types
    • String
    • Bool
    • Int
    • Float
    • Double
    • URL
    • Date
    • [Any]
    • [String: Any]
  • JSON encoded types
    • Data
    • String

The AppGroup (UserDefaults(suiteName: "xxx")) was supported, please see Configurations.

Quick Start

  1. Install via Swift Package Manager.
let package = Package(
    dependencies: [
        .package(url: "https://github.com/YusukeHosonuma/SwiftUI-Simulator.git", from: "1.6.0"),
    ],
    targets: [
        .target(name: "<your-target-name>", dependencies: [
             .product(name: "SwiftUISimulator", package: "SwiftUI-Simulator"),
        ]),
    ]
)
  1. Surround the your app's root view with SimulatorView.
#if DEBUG
import SwiftUISimulator
#endif

@main
struct ExampleApp: App {
    var body: some Scene {
        WindowGroup {
            #if DEBUG
            SimulatorView { // ✅ Please surround the your app's root view with `SimulatorView`.
                ContentView()
            }
            #else
            ContentView()
            #endif
        }
    }
}
  1. Launch on any simulator or device. (Large screen is recommended)
iPhone 13 Pro Max iPad Pro (12.9-inch)
image image

Requirements

  • iOS 14+ (iPhone / iPad)
    • Dynamic Type Sizes is supports in iOS 15+

Limitation

  • This OSS supports SwiftUI app only.
    • For example, it may not work if you have resolve locale by yourself. (e.g. use SwiftGen)
  • sheet() and fullScreenCover() are not working currently. #37

Custom Debug Menu

You can add custom debug menu.

SimulatorView {
    // 💡 Add custom debug menu.
    Button {
        print("Hello!")
    } label: {
        Label("Custom Debug", systemImage: "ant.circle")
    }
} content: {
    ContentView()
}

This makes it easy to run custom debug action.

image

Built-in Modifier (Experimental)

As a built-in, we provide a modifier that displays the file name of the View.

Debug enabled Debug disabled
image image

The installation procedure is as follows. (recommended)

  1. Add View+Debug.swift.
import SwiftUI

#if DEBUG
import SwiftUISimulator
#endif

public extension View {
    func debugFilename(_ file: StaticString = #file) -> some View {
        // ✅ Enabled when debug build only.
        #if DEBUG
        simulatorDebugFilename(file) // 💡 or any `String`.
        #else
        self
        #endif
    }
}
  1. Add custom debug menu and environment.
struct ExampleApp: App {
    //
    // ✅ To show/hide
    //
    #if DEBUG
    @State private var isEnabledDebugFilename = false
    #endif

    var body: some Scene {
        WindowGroup {
            #if DEBUG
            SimulatorView {
                //
                // ✅ Add debug menu.
                //
                Menu {
                    Toggle(isOn: $isEnabledDebugFilename) {
                        Label("Filename", systemImage: "doc.text.magnifyingglass")
                    }
                } label: {
                    Label("Debug", systemImage: "ant.circle")
                }
            } content: {
                RootView()
                    //
                    // ✅ Add `simulatorDebugFilename` environment value to root view.
                    //
                    .environment(\.simulatorDebugFilename, isEnabledDebugFilename)
            }
            #else
            ContentView()
            #endif
        }
    }
}
  1. Add debugFilename() modifier to any views. (where you needed)
struct FooView: View {
    var body: some View {
        Text("Foo")
            .debugFilename() // ✅
    }
}

Note:
As you can probably imagine, it is easy to make this yourself. Please refer to DebugFilenameModifier.swift).

Configurations

You can specify default devices, locale identifiers, calendar identifiers and timezone.

SimulatorView(
    defaultDevices: [.iPhone11, .iPhone13ProMax],       // Set<Device>
    defaultLocaleIdentifiers: ["it", "fr"],             // Set<String>
    defaultCalendarIdentifiers: [.gregorian, .iso8601], // Set<Calendar.Identifier>
    defaultTimeZones: [.europeParis, .europeBerlin],    // Set<TimeZones>
    accentColorName: "MyAccentColor",                   // when not use default accent color name in Assets.
    userDefaultsSuiteNames: ["someDomain"]              // [String]
) {
    RootView()
}

This is useful if you want to share with your team.

Contributions

Issues and PRs are welcome, even for minor improvements and corrections.

FAQ

Q. How it works?
A. Perhaps as you might imagine, this is achieved by overriding SwiftUI's Environment.

Q. How to disable this simulator?
A. Disable Simulator in setting menu.

image

Author

Yusuke Hosonuma / @tobi462