Friday, March 24, 2023
Learning Code
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#
No Result
View All Result
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#
No Result
View All Result
Learning Code
No Result
View All Result
Home Swift

How to build macOS apps using only the Swift Package Manager?

learningcode_x1mckf by learningcode_x1mckf
September 18, 2022
in Swift
0
How to build macOS apps using only the Swift Package Manager?
74
SHARES
1.2k
VIEWS
Share on FacebookShare on Twitter


You might also like

Encoding and decoding data using the Hummingbird framework

Hummingbird routing and requests – The.Swift.Dev.

Building a Scrollable Custom Tab Bar in SwiftUI

Swift scripts and macOS apps

Swift compiler 101, you may create, construct and run a Swift file utilizing the swiftc command. Think about the simplest Swift program that we will all think about in a major.swift file:

print("Hiya world!")

In Swift if we wish to print one thing, we do not even must import the Basis framework, we will merely compile and run this piece of code by operating the next:

swiftc major.swift 	# compile major.swift
chmod +x major 		# add the executable permission
./major 			# run the binary

The excellent news that we will take this one step additional by auto-invoking the Swift compiler below the hood with a shebang.

#! /usr/bin/swift

print("Hiya world!")

Now when you merely run the ./major.swift file it’s going to print out the well-known “Hiya world!” textual content. 👋

Because of the program-loader mechanism and naturally the Swift interpreter we will skip an additional step and run our single-source Swift code as simple as a daily shell script. The excellent news is that we will import all form of system frameworks which might be a part of the Swift toolchain. With the assistance of Basis we will construct fairly helpful or utterly ineffective command line utilities.

#!/usr/bin/env swift

import Basis
import Dispatch

guard CommandLine.arguments.depend == 2 else 
    fatalError("Invalid arguments")

let urlString =  CommandLine.arguments[1]
guard let url = URL(string: urlString) else 
    fatalError("Invalid URL")   


struct Todo: Codable 
    let title: String
    let accomplished: Bool


let job = URLSession.shared.dataTask(with: url)  information, response, error in 
    if let error = error 
        fatalError("Error: (error.localizedDescription)")
    
    guard let response = response as? HTTPURLResponse, response.statusCode == 200 else 
        fatalError("Error: invalid HTTP response code")
    
    guard let information = information else 
        fatalError("Error: lacking response information")
    

    do 
        let decoder = JSONDecoder()
        let todos = attempt decoder.decode([Todo].self, from: information)
        print("Listing of todos:")
        print(todos.map  " - [" + ($0.completed ? "✅" : "❌") + "] ($0.title)" .joined(separator: "n"))
        exit(0)
    
    catch 
        fatalError("Error: (error.localizedDescription)")
    

job.resume()
dispatchMain()

Should you name this instance with a URL that may return a listing of todos it’s going to print a pleasant listing of the objects.

./major.swift https://jsonplaceholder.typicode.com/todos

Sure, you may say that this script is totally ineffective, however in my view it is a tremendous demo app, because it covers how one can test command line arguments (CommandLine.arguments), it additionally exhibits you how one can wait (dispatchMain) for an async job, equivalent to a HTTP name by way of the community utilizing the URLSession API to complete and exit utilizing the appropriate technique when one thing fails (fatalError) or when you attain the top of execution (exit(0)). Only a few traces of code, but it surely comprises a lot information.

Have you ever seen the brand new shebang? When you have a number of Swift variations put in in your system, you need to use the env shebang to go along with the primary one which’s out there in your PATH.

It isn’t simply Basis, however you may import AppKit and even SwiftUI. Effectively, not below Linux in fact, since these frameworks are solely out there for macOS plus you will have Xcode put in in your system, since some stuff in Swift the toolchain remains to be tied to the IDE, however why? 😢

Anyway, again to the subject, this is the boilerplate code for a macOS software Swift script that may be began from the Terminal with one easy ./major.swift command and nothing extra.

#!/usr/bin/env swift

import AppKit
import SwiftUI

@out there(macOS 10.15, *)
struct HelloView: View 
    var physique: some View 
        Textual content("Hiya world!")
    


@out there(macOS 10.15, *)
class WindowDelegate: NSObject, NSWindowDelegate 

    func windowWillClose(_ notification: Notification) 
        NSApplication.shared.terminate(0)
    



@out there(macOS 10.15, *)
class AppDelegate: NSObject, NSApplicationDelegate 
    let window = NSWindow()
    let windowDelegate = WindowDelegate()

    func applicationDidFinishLaunching(_ notification: Notification) 
        let appMenu = NSMenuItem()
        appMenu.submenu = NSMenu()
        appMenu.submenu?.addItem(NSMenuItem(title: "Stop", motion: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
        let mainMenu = NSMenu(title: "My Swift Script")
        mainMenu.addItem(appMenu)
        NSApplication.shared.mainMenu = mainMenu
        
        let measurement = CGSize(width: 480, top: 270)
        window.setContentSize(measurement)
        window.styleMask = [.closable, .miniaturizable, .resizable, .titled]
        window.delegate = windowDelegate
        window.title = "My Swift Script"

        let view = NSHostingView(rootView: HelloView())
        view.body = CGRect(origin: .zero, measurement: measurement)
        view.autoresizingMask = [.height, .width]
        window.contentView!.addSubview(view)
        window.middle()
        window.makeKeyAndOrderFront(window)
        
        NSApp.setActivationPolicy(.common)
        NSApp.activate(ignoringOtherApps: true)
    


let app = NSApplication.shared
let delegate = AppDelegate()
app.delegate = delegate
app.run()

Particular thanks goes to karwa for the original gist. Additionally if you’re into Storyboard-less macOS app growth, it’s best to positively check out this article by @kicsipixel. These sources helped me so much to place collectively what I wanted. I nonetheless needed to prolong the gist with a correct menu setup and the activation coverage, however now this model acts like a real-world macOS software that works like a appeal. There is just one situation right here… the script file is getting crowded. 🙈

Swift Package deal Supervisor and macOS apps

So, if we comply with the identical logic, which means we will construct an executable bundle that may invoke AppKit associated stuff utilizing the Swift Package deal Supervisor. Straightforward as a pie. 🥧

mkdir MyApp
cd MyApp 
swift bundle init --type=executable

Now we will separate the parts into standalone information, we will additionally take away the supply checking, since we’ll add a platform constraint utilizing our Package deal.swift manifest file. If you do not know a lot about how the Swift Package deal Supervisor works, please learn my SPM tutorial, or if you’re merely curious concerning the construction of a Package deal.swift file, you may learn my article concerning the Swift Package manifest file. Let’s begin with the manifest updates.


import PackageDescription

let bundle = Package deal(
    identify: "MyApp",
    platforms: [
        .macOS(.v10_15)
    ],
    dependencies: [
        
    ],
    targets: [
        .target(name: "MyApp", dependencies: []),
        .testTarget(identify: "MyAppTests", dependencies: ["MyApp"]),
    ]
)

Now we will place the HelloView struct into a brand new HelloView.swift file.

import SwiftUI

struct HelloView: View 
    var physique: some View 
        Textual content("Hiya world!")
    

The window delegate can have its personal place inside a WindowDelegate.swift file.

import AppKit

class WindowDelegate: NSObject, NSWindowDelegate 

    func windowWillClose(_ notification: Notification) 
        NSApplication.shared.terminate(0)
    

We will apply the identical factor to the AppDelegate class.

import AppKit
import SwiftUI

class AppDelegate: NSObject, NSApplicationDelegate 
    let window = NSWindow()
    let windowDelegate = WindowDelegate()

    func applicationDidFinishLaunching(_ notification: Notification) 
        let appMenu = NSMenuItem()
        appMenu.submenu = NSMenu()
        appMenu.submenu?.addItem(NSMenuItem(title: "Stop", motion: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
        let mainMenu = NSMenu(title: "My Swift Script")
        mainMenu.addItem(appMenu)
        NSApplication.shared.mainMenu = mainMenu
        
        let measurement = CGSize(width: 480, top: 270)
        window.setContentSize(measurement)
        window.styleMask = [.closable, .miniaturizable, .resizable, .titled]
        window.delegate = windowDelegate
        window.title = "My Swift Script"

        let view = NSHostingView(rootView: HelloView())
        view.body = CGRect(origin: .zero, measurement: measurement)
        view.autoresizingMask = [.height, .width]
        window.contentView!.addSubview(view)
        window.middle()
        window.makeKeyAndOrderFront(window)
        
        NSApp.setActivationPolicy(.common)
        NSApp.activate(ignoringOtherApps: true)
    

Lastly we will replace the primary.swift file and provoke every part that must be executed.

import AppKit

let app = NSApplication.shared
let delegate = AppDelegate()
app.delegate = delegate
app.run()

The excellent news is that this strategy works, so you may develop, construct and run apps domestically, however sadly you may’t submit them to the Mac App Retailer, for the reason that ultimate software bundle will not appear like an actual macOS bundle. The binary shouldn’t be code signed, plus you may want an actual macOS goal in Xcode to submit the applying. Then why trouble with this strategy?

Effectively, simply because it’s enjoyable and I may even keep away from utilizing Xcode with the assistance of SourceKit-LSP and a few Editor configuration. The perfect half is that SourceKit-LSP is now part of Xcode, so you do not have to put in something particular, simply configure your favourite IDE and begin coding.

You can even bundle resources, since this function is obtainable from Swift 5.3, and use them by way of the Bundle.module variable if wanted. I already tried this, works fairly effectively, and it’s so a lot enjoyable to develop apps for the mac with out the additional overhead that Xcode comes with. 🥳





Source link

Share30Tweet19
learningcode_x1mckf

learningcode_x1mckf

Recommended For You

Encoding and decoding data using the Hummingbird framework

by learningcode_x1mckf
March 22, 2023
0
Encoding and decoding data using the Hummingbird framework

HTTP is all about sending and receiving information over the community. Initially it was solely utilized to switch HTML paperwork, however these days we use HTTP to switch...

Read more

Hummingbird routing and requests – The.Swift.Dev.

by learningcode_x1mckf
March 17, 2023
0
Hummingbird routing and requests – The.Swift.Dev.

Routing on the server facet means the server goes to ship a response primarily based on the URL path that the consumer referred to as when firing up...

Read more

Building a Scrollable Custom Tab Bar in SwiftUI

by learningcode_x1mckf
March 10, 2023
0
Building a Scrollable Custom Tab Bar in SwiftUI

Whether or not you’re making a social media app or a productiveness device, the tab bar interface can improve the consumer expertise by making it extra intuitive and...

Read more

Beginner’s guide to server-side Swift using the Hummingbird framework

by learningcode_x1mckf
March 8, 2023
0
Beginner’s guide to server-side Swift using the Hummingbird framework

Swift on the Server in 2023 Three years in the past I began to focus on Vapor, the preferred web-framework written in Swift, which served me very...

Read more

What’s new in Swift 5.8 – Hacking with Swift

by learningcode_x1mckf
March 8, 2023
0
What’s new in Swift 5.8 – Hacking with Swift

Though many main Swift modifications are at present percolating by way of Swift Evolution, Swift 5.8 itself is extra of a clear up launch: there are additions, sure,...

Read more
Next Post
JavaScript Slows Progress, Should be Retired, Argues JSON Creator

JavaScript Slows Progress, Should be Retired, Argues JSON Creator

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Related News

How to Heapify a Heap Tree in C++: A Tutorial With Examples

How to Heapify a Heap Tree in C++: A Tutorial With Examples

September 4, 2022
Using Python’s pathlib Module – Real Python

Using Python’s pathlib Module – Real Python

November 29, 2022
Java Scanner import

Java Scanner import

November 7, 2022

Browse by Category

  • C#
  • C++
  • Java
  • JavaScript
  • Python
  • Swift

RECENT POSTS

  • Java Developer Survey Reveals Increased Need for Java … – PR Newswire
  • What You Should Definitely Pay Attention to When Hiring Java Developers – Modern Diplomacy
  • Java Web Frameworks Software Market Research Report 2023 … – Los Alamos Monitor

CATEGORIES

  • C#
  • C++
  • Java
  • JavaScript
  • Python
  • Swift

© 2022 Copyright Learning Code

No Result
View All Result
  • Home
  • JavaScript
  • Java
  • Python
  • Swift
  • C++
  • C#

© 2022 Copyright Learning Code

Are you sure want to unlock this post?
Unlock left : 0
Are you sure want to cancel subscription?