4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

macOSアプリで通知バナーを表示

Last updated at Posted at 2022-02-08

概要

image

参考

実装

ユーザへ許可を求める

  • 最初にユーザに許可を求め、通知を許可してもらう必要があります。
  • 許可しない限り下記のauthorizedはfalseが返ってきます。
import UserNotifications

let userNotificationCenter = UNUserNotificationCenter.current()

userNotificationCenter.requestAuthorization(options: [.alert, .sound]) { authorized, error in
    guard authorized else {
        print("Not authorized")
        return
    }
}
  • 下記のように通知が表示され、クリックすると設定画面が表示されます。
image

通知の作成

  • まず通知が許可されているかをgetNotificationSettings(completionHandler:)で確認します。
  • 具体的な通知の値はUNMutableNotificationContentオブジェクトを使います。
  • let image = NSImage(contentsOf: imageUrl)の部分はメインスレッドだとUIが止まってしまうので、DispatchQueue.global().asyncを使用しています。
  • (試した所通知はサブスレッドのままで動作したのですが、恐らくメインスレッドで呼ぶべきだと思うのでそうしています。)
userNotificationCenter.getNotificationSettings { settings in
    guard settings.authorizationStatus == .authorized else {
        return
    }
    
    let content = UNMutableNotificationContent()
    content.title = "Title Sample"
    content.subtitle = "Subtitle Sample"
    content.body = "Body sample"
    content.sound = UNNotificationSound.default
    
    /*
     // プロジェクトのResourceファイルを使用する場合
     guard let fileUrl = Bundle.main.url(forResource: "sampleImage1", withExtension: ".png"),
     let attachment = try? UNNotificationAttachment(identifier: fileUrl.lastPathComponent, url: fileUrl, options: nil)
     else {
     return
     }
     */
    
    // ファイルをダウンロードする場合
    DispatchQueue.global().async {
        guard let imageUrl = URL(string: "https://i.imgur.com/tanIcMA.png"),
              let image = NSImage(contentsOf: imageUrl),
              let attachment = UNNotificationAttachment.create(identifier: "attachment",
                                                               image: image,
                                                               options: .none)
        else {
            return
        }
        
        content.attachments = [attachment]
        let request = UNNotificationRequest(identifier: imageUrl.lastPathComponent, content: content, trigger: nil)
        
        DispatchQueue.main.async {
            userNotificationCenter.add(request) { error in
                if error != nil {
                    print(error?.localizedDescription as Any)
                }
            }
        }
    }
    
}
  • 通知に画像を添付したい場合、ローカルPC上にファイルが存在する必要があります。
  • 画像をNSImageで指定できるよう、下記のextensionを利用します。
  • Tempフォルダを作ってそこに画像を保存して、UNNotificationAttachmentを返しています。
extension UNNotificationAttachment {
    
    static func create(identifier: String,
                       image: NSImage,
                       options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
        let fileManager = FileManager.default
        let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
        let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)
        do {
            try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)
            let imageFileIdentifier = identifier + ".png"
            let fileURL = tmpSubFolderURL.appendingPathComponent(imageFileIdentifier)
            let imageData = image.tiffRepresentation
            try imageData?.write(to: fileURL)
            let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier,
                                                                    url: fileURL,
                                                                    options: options)
            return imageAttachment
        } catch {
            print("error " + error.localizedDescription)
        }
        return nil
    }
}

フォアグラウンド時の通知表示

import Cocoa
import UserNotifications

@main
class AppDelegate: NSObject, NSApplicationDelegate {

    


    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Insert code here to initialize your application
        UNUserNotificationCenter.current().delegate = self
    }

    // (略)

}

extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        return completionHandler([.list, .banner, .sound])
    }
}

システム設定の通知設定を開く

guard let url = URL(string: "x-apple.systempreferences:com.apple.preference.notifications") else {
    return
}
NSWorkspace.shared.open(url)

システム設定の通知設定の値の保存場所

  • ~/Library/Preferences/com.apple.ncprefs.plistに保存されています。

デバッグ時のTips

  • 通知バナーにアイコンが表示されない場合
    • 設定画面から一度削除する
  • 設定画面にアプリが表示されない
    • 一度設定画面を閉じて再度開く

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?