Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Swift UIで始めるmacOSメニューバーアプリ
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
株式会社ヌーラボ
PRO
April 22, 2022
Technology
1.2k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Swift UIで始めるmacOSメニューバーアプリ
株式会社ヌーラボ
PRO
April 22, 2022
More Decks by 株式会社ヌーラボ
See All by 株式会社ヌーラボ
The_Evolution_of_Bits_AI_SRE.pdf
nulabinc
PRO
0
340
進化するBits AI SREと私と組織
nulabinc
PRO
4
780
実践 Datadog MCP Server
nulabinc
PRO
4
790
全社横断PjM⽀援チーム “PEaS”の取り組みと プロジェクトマネジメント でのAI活⽤について
nulabinc
PRO
0
190
Datadog の RBAC のすべて
nulabinc
PRO
4
840
Datadog Live Tokyo 2025登壇資料
nulabinc
PRO
0
170
How to Migrate Your Backlog Free Plan
nulabinc
PRO
0
250
チームワークマネジメント Bar #5
nulabinc
PRO
0
93
Geeks Who Drink Fukuoka - 202508
nulabinc
PRO
0
71
Other Decks in Technology
See All in Technology
デジタル・デザイン構想 by Sayaka Ishizuka
y150saya
0
170
打造你的 AI 工作流:Agent Skill + MCP 實戰工作坊
appleboy
0
340
そのタスクオンスケですか?
poropinai1966
0
110
IaC コードを資産へ:AWS CDK 社内ライブラリと横断展開 / aws-summit-japan-2026
gotok365
10
1.7k
時期が悪い!それでもRaspberry Piを買って遊んで活用するには / 20260627-osc26do-rpi-jikigawarui
akkiesoft
1
960
デジタル・デザイン:次の50年を描く「進化する青写真」
y150saya
0
740
From Prompt Engineering to Loop Engineering
shibuiwilliam
1
320
フルAIで個人開発して学んだあれこれ / yuruai vol.1
isaoshimizu
0
160
LiDAR SLAMの実装とセンサ融合 ~Lie群からContinuous-Time LIOまで~
naokiakai
1
790
勉強会企画をアプリで構造化してみた 〜そこで見えた、AIとの付き合い方〜 / I've structured a study group plan using an app.
pauli
0
270
SRE歴2ヶ月でも開発6年の知見を活かして、チームで止まっていた環境改善を前に進めた話
a_ono
0
170
GitHub Copilot運用のリアル ~AI Credit時代にどう向き合うか~
takafumisu2uk1
0
590
Featured
See All Featured
How to build a perfect <img>
jonoalderson
1
5.8k
Designing for Performance
lara
611
70k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
250
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
190
AI: The stuff that nobody shows you
jnunemaker
PRO
8
760
Optimising Largest Contentful Paint
csswizardry
37
3.7k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
270
Imperfection Machines: The Place of Print at Facebook
scottboms
270
14k
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.7k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
118
120k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
300
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Transcript
20224݄22 NuCon 2022 Spring দຊ༟ೋ Swift UIͰ࢝ΊΔ macOSϝχϡʔόʔΞϓϦ
ͭͬͨ͘ΞϓϦ
FreeeͷۈଵΞϓϦ ग़ۈͱୀۈΛߦ͏͚ͩͷγϯϓϧͳΞϓϦ (ψʔϥϘ͚ࣾͩͰத)
SwiftUI
SwiftUI • એݴܕγϯλοΫεͳUIϑϨʔϜϫʔΫ • macOS, iOS, iPadOS, tvOS, watchOSͰ͑Δ •
XcodeͰͷϓϨϏϡʔσβΠϯαϙʔτ AppKit • MVCͳUIϑϨʔϜϫʔΫ • macOSͰ͑Δ • NSʙͱ͍͏pre fi x͕͍͍ͯΔ NBD04ʙ NBD04ʙ /FYU4UFQʜ
Ψϫͷ෦4XJGU6*Ͱ࡞Εͳ͍ /41PQPWFS 4XJGU6*Ͱ࡞Εͳ͍ /44UBUVT*UFN/44UBUVT#BS#VUUPO 7JFX 1PQPWFS
ϝχϡʔόʔͷΫϦοΫͰ SwiftUIͷϏϡʔΛϙοϓΞοϓͤ͞Δ·Ͱ
None
DemoApp.swift import SwiftUI @main struct DemoApp: App { var body:
some Scene { WindowGroup { ContentView() } } } import SwiftUI struct ContentView: View { var body: some View { Text("Hello, world!") .padding() } } ContentView.swift
@NSApplicationDelegateAdaptor import SwiftUI @main struct DemoApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) var
delegate var body: some Scene { WindowGroup { ContentView() } } } class AppDelegate: NSObject, NSApplicationDelegate { } ΞϓϦͷىಈޙʹݺΕΔϝιουͳͲ͕͑ΔΑ͏ʹͳΔ
class AppDelegate: NSObject, NSApplicationDelegate { } private var statusItem: NSStatusItem?
func applicationDidFinishLaunching(_ notification: Notification) { statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) let button = statusItem!.button! button.image = NSImage(systemSymbolName: "leaf", accessibilityDescription: nil) } 4'4ZNCPMT͕͑Δ ΞϓϦͷىಈޙʹݺΕΔϝιου
class AppDelegate: NSObject, NSApplicationDelegate { } private var statusItem: NSStatusItem?
private var popover: NSPopover? func applicationDidFinishLaunching(_ notification: Notification) { statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) let button = statusItem!.button! button.image = NSImage(systemSymbolName: "leaf", accessibilityDescription: nil) button.action = #selector(showPopover) } @objc func showPopover(_ sender: NSStatusBarButton) { if popover == nil { let popover = NSPopover() popover.contentViewController = NSHostingController(rootView: ContentView()) self.popover = popover } popover?.show(relativeTo: sender.bounds, of: sender, preferredEdge: NSRectEdge.maxY) } 4XJGU6*Λϗετͯ͘͠ΕΔ"QQ,JUͷίϯτϩʔϥ
class AppDelegate: NSObject, NSApplicationDelegate { } private var statusItem: NSStatusItem?
private var popover: NSPopover? func applicationDidFinishLaunching(_ notification: Notification) { NSApp.windows.forEach{ $0.close() } NSApp.setActivationPolicy(.accessory) statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) let button = statusItem!.button! button.image = NSImage(systemSymbolName: "leaf", accessibilityDescription: nil) button.action = #selector(showPopover) } @objc func showPopover(_ sender: NSStatusBarButton) { if popover == nil { let popover = NSPopover() popover.contentViewController = NSHostingController(rootView: ContentView()) popover.behavior = .transient popover.animates = false self.popover = popover } popover?.show(relativeTo: sender.bounds, of: sender, preferredEdge: NSRectEdge.maxY) NSApp.activate(ignoringOtherApps: true) } ΞϓϦىಈதʹ%PDL͔ΒΞΠίϯΛফ͢ ΞϓϦىಈޙͷΟϯυΛશ෦ফ͢ ΞϓϦҎ֎ͷྖҬͷΫϦοΫͰϙοϓΞοϓ͕ด͡ΔΑ͏ʹ͢Δ ΞϓϦΛΞΫςΟϒʹ͠ͳ͍ͱ͏·͘ด͡ͳ͍
private var statusItem: NSStatusItem? @main struct DemoApp: App { #if
os(macOS) @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate #endif var body: some Scene { WindowGroup { ContentView() } } } #if os(macOS) class AppDelegate: NSObject, NSApplicationDelegate { … } #endif
SwiftUIΛ؆୯ʹհ
ContentView.swift import SwiftUI struct ContentView: View { var body: some
View { Text("Hello, world!") .padding() } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
struct ContentView: View { var body: some View { Button
{ print("pushed") } label: { HStack { Image(systemName: "face.smiling") Text("Hello, world!") } } .padding() } }
struct ContentView: View { @State var point: CGFloat = -1
var body: some View { let gradient = LinearGradient(gradient: Gradient(colors: [.blue, .green, .blue]), startPoint: UnitPoint(x: point, y: 0), endPoint: UnitPoint(x: 1.0 + point, y: 0)) VStack { Capsule() .fill(gradient) .animation(Animation.linear(duration: 2) .repeatForever(autoreverses: false), value: point) .onAppear { point = 1 } .frame(width: 200, height: 10, alignment: .leading) .padding() Button { print("pushed") } label: { HStack { Image(systemName: "face.smiling") Text("Hello, world!") } } } .padding() } }
Tips
ӈΫϦοΫϝχϡʔΛͭ͘Δ @objc func showPopover(_ sender: NSStatusBarButton) { guard let event
= NSApp.currentEvent else { return } if event.type == NSEvent.EventType.rightMouseUp { let menu = NSMenu() menu.addItem( withTitle: NSLocalizedString("Preference", comment: "Show preferences window"), action: #selector(openPreferencesWindow), keyEquivalent: "" ) menu.addItem(.separator()) menu.addItem( withTitle: NSLocalizedString("Quit", comment: "Quit app"), action: #selector(terminate), keyEquivalent: "" ) statusItem?.popUpMenu(menu) return } ɿ ࣄલʹ button.sendAction(on: [.leftMouseUp, .rightMouseUp]) ͕ඞཁ
TextFieldͳͲͰΩʔϘʔυγϣʔτΧοτΛ༗ޮʹ͢Δ @main struct FreeeApp: App { #if os(macOS) @NSApplicationDelegateAdaptor(AppDelegate.self) var
delegate #endif var body: some Scene { #if os(macOS) WindowGroup { // empty }.commands { TextEditingCommands() } Settings { SettingsView() } #else WindowGroup { ContentView(store: AppStore()) } #endif } } ςΩετฤूܥͷϏϧτΠϯίϚϯυ܈
ΞϓϦͷ (ඇAppStore) • macOS 10.15 (Catalina) Ҏ߱Appleͷެূ (Notarization) Λ͚ ͍ͯͳ͍ΞϓϦىಈͤͮ͞Β͘ͳ͍ͬͯΔ
• XcodeͰProduct→Archive • OrganizerΛ։͘ • Distribute App → Developer ID → Upload • ͠Βͭ͘ • Distribute App → Developer ID • Successfully notarizedͱݴΘΕΔͷͰExportΛΫϦοΫ
ඇදࣔAppͷ৴ • Unlisted app distribution • AppStoreʹ͋Δ͚ͲϦϯΫΛΒͳ͍ͱ͑ͳ͍ • 20221݄͝Ζ͔Β͑ΔΑ͏ʹͳͬͨ •
ࢼͯ͠Έ͍ͨ https://developer.apple.com/jp/support/unlisted-app-distribution/
4XJGU6*ͰϝχϡʔόʔΞϓϦΛ࡞ΕΔ