macOS开发笔记(1)

旧坑不填,喜开新坑。这两天又计划开发一款macOS应用,之前开发的速记完全是练手,反正现在是不想填坑了,索性再开一个。实际做一个项目,是学习的最佳途径。本文记录了我在开发中遇到的各种问题,以及找到的解决办法,权当以后查阅的笔记。如果能给某位朋友带来帮助,是我的荣幸。如果发现问题,敬请评论吐槽。

开发环境:Xcode 9.1 + Swift4

StatusBar

设置按钮

applicationDidFinishLaunching方法中调用下面代码,设置StatusBar按钮

1
2
3
4
5
6
7
8
9
10
11
12
13
func createButtonStatusBar() {
let statusBar = NSStatusBar.system
let item = statusBar.statusItem(withLength: NSStatusItem.squareLength)
item.button?.target = self
item.button?.action = #selector(itemActionShowView(_:))
let image:NSImage = NSImage(named: NSImage.Name(rawValue: "mremindbaricon"))!
image.isTemplate = true
item.button?.image = image
statusItem = item;
}
@objc func itemActionShowView(_ sender: NSStatusBarButton) {
print("点击")
}

itemActionShowView是实现的点击方法,Swift4.0之后,必须增加@objc修饰符,是因为Swift4.0之后去掉了Swift3.x对隐式类型推断的特性,必须手动管理@objc,保证oc和Swift代码能互相调用。

设置菜单

Main.storyboardApplication Scene中拖入NSMenu,将NSMenu拖线到AppDelegate中。如同上面设置statusBar按钮一样,不需要设置按钮的targetaction,需要设置menu

1
2
3
4
5
@IBOutlet weak var toolMenu: NSMenu!
...
item.menu = toolMenu

添加NSMenu

添加NSMenu的点击事件,直接拖线action即可。

Dock和Window

隐藏Dock上的应用图标

开发statusBar应用,不需要弹出Window界面,可以在Main.storyboard中的Window Controller Scene中取消Is Initial Controller的勾选。

不需要在Dock上出现应用图标,Info.plist中添加Key - Value:Application is agent (UIElement) - YES

Window居中

1
window.center()//居中

Window的层级关系

Window有一个level属性,标识Window的层级关系。设置Window的level

1
self.window?.level = .floating //Window设置为浮动的

还有好多其他层级关系,诸如normalsubmenutornOffMenu……

启动Window

弹出一个Window页面,并将其设置为keyWindow(第一响应者的Window窗口):

1
2
//将addWindowController.window启动,并设置为keyWindow
addWindowController.window!.makeKeyAndOrderFront(self)

有时候该方法只能将Window显示出来,并不能设置为keyWindow,如果是normal层级的Window,Window都不能覆盖其他应用窗口,只会在其他应用窗口下面显示。特别是statusBar应用,在其他应用窗口为keyWindow时,点击工具条上的statusBar,启动Window,无法完成keyWindow设置。

需要调用下面代码,将其他应用都取消keyWindow

1
NSApp.activate(ignoringOtherApps: true)

NSTextField

输入时隐藏蓝色边框

xib中在Focus Ring中选择None

隐藏蓝色边框

或者在代码中执行:

1
textField.focusRingType = .none

文本框第一响应者

1
2
self.window?.makeFirstResponder(textField)//设置为第一响应者
self.window?.makeFirstResponder(nil) //取消第一响应者

获取版本号

macOS版本号

macOS10.10及以上,使用下面的方法:

1
2
let version = ProcessInfo.processInfo.operatingSystemVersion
print("\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)")

还有如下方式(已弃用)

1
2
3
4
5
6
7
#import <CoreServices/CoreServices.h>
SInt32 major, minor, bugfix;
Gestalt(gestaltSystemVersionMajor, &major);
Gestalt(gestaltSystemVersionMinor, &minor);
Gestalt(gestaltSystemVersionBugFix, &bugfix);
print("\(major).\(minor).\(bugfix)")

其他方式请见:查找Mac OS X版本号

app版本号

1
2
let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")
let bundle = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion")

设置快捷键和关闭退出应用

快捷键

xib或storyboard设置快捷键很方便,直接在Key Equivalend输入快捷键即可。

设置快捷键

退出应用

action拖线到Application,选择stop:方法即可:

拖线到Application

选择stop:方法

或者拖线到First Responder,选择terminate:方法

拖线到First Responder

或者调用代码:

1
NSApplication.shared().terminate(self)

关闭应用

拖线到First Responder,选择performClose:方法

其他操作

发送邮件

使用NSSharingService调用macOS邮件应用,发送邮件。

1
2
3
4
5
6
7
8
let emailService = NSSharingService(named: NSSharingService.Name.composeEmail)!
emailService.recipients = ["i@markmiao.com"]
emailService.subject = "邮件内容"
if emailService.canPerform(withItems: ["邮件内容"]) {
emailService.perform(withItems: ["邮件内容"])
} else {
print("没配置邮件账户")
}

在浏览器中打开网页

1
NSWorkspace.shared.open(URL(string: "http://markmiao.com")!)
打赏作者一杯咖啡
显示 Gitment 评论