Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Swift UIで始めるmacOSメニューバーアプリ
Search
株式会社ヌーラボ
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 株式会社ヌーラボ
FinOps in practice for growth and scale
nulabinc
PRO
0
43
成長と拡大を支える FinOps 実践記
nulabinc
PRO
0
47
製造業の設計・生産技術向け Backlog入門
nulabinc
PRO
0
37
配布資料_ヌーラボの情シスがおすすめする_問い合わせ対応を削減するBacklog活用術.pdf
nulabinc
PRO
0
130
Bits Agent Builder の⼊⾨と活⽤事例
nulabinc
PRO
0
3.3k
Getting Started with Bits Agent Builder: Real-World Use Cases
nulabinc
PRO
0
89
The_Evolution_of_Bits_AI_SRE.pdf
nulabinc
PRO
0
440
進化するBits AI SREと私と組織
nulabinc
PRO
4
1.3k
実践 Datadog MCP Server
nulabinc
PRO
4
1k
Other Decks in Technology
See All in Technology
Autonomous AI Lakehouse - Live AI Hubから始めるセキュアなAIデータ活用 -
oracle4engineer
PRO
3
190
AI AgentによるEmbedded SREの取り組み
tgidgd
1
340
Gifu WordPress Meetup #200 に向けて、私たちには何ができるだろうか?/ 2026-11-07 Gifu WordPress Meetup
torounit
0
110
Microsoft Entra Kerberos で実現するクラウド デバイス管理
tamaiyutaro
1
410
Copilot Coworkで「みのるん式」やってみた
minorun365
PRO
2
1.5k
2拠点SRE活動始めてみた | sogaoh's LT @ ホンマでっかSRE勉強会 #3
sogaoh
PRO
0
240
re:Invent の去年のスケジュールを公開します!
miu_crescent
PRO
0
280
Oracle Database Security 詳細解説
oracle4engineer
PRO
2
250
Flutter Widget Previewerで始めるUIプレビューとVRTの自動化
sakusaku3939
0
210
企画からFlutter実装まで、1つの機能を一貫して開発したプロセスと成果物
khiroyuki1003
1
150
令和の今、あらためて IAM を考える。アクセスキーを「無くせない現実」との向き合い方
kazzpapa3
0
150
あなたのDartコードは丸見えかもしれない ~reFlutterで暴くFlutterアプリの中身と多層防御~
zozotech
PRO
0
770
Featured
See All Featured
New Earth Scene 8
popppiees
4
2.8k
Paper Plane (Part 1)
katiecoart
PRO
2
12k
WENDY [Excerpt]
tessaabrams
14
40k
A Tale of Four Properties
chriscoyier
163
24k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
660
Crafting Experiences
bethany
1
420
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.7k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
370
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
650
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.4k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.4k
How Software Deployment tools have changed in the past 20 years
geshan
2
35k
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*ͰϝχϡʔόʔΞϓϦΛ࡞ΕΔ