본문 바로가기
#컴퓨터 과학 [Computer Science]/운영체제 (Operating System)

[OS - 🍎 macOS] Finder Sync Extensions

by cy_mos 2020. 2. 28.
반응형

[OS - 🍎 macOS] Finder Sync Extensions

🗂 Finder Sync Extension

  • In OS X, the Finder Sync extension point lets you cleanly and safely modify the Finder’s user interface to express file synchronization status and control. Unlike most extension points, Finder Sync does not add features to a host app. Instead, it lets you modify the behavior of the Finder itself.
  • macOS에서, Finder Sync Extension 중점은 분명하고 그리고 안전하게 수정을 수행할 수 있도록 Finder's 사용자 인터페이스를 통하여 파일의 동기화 상태 및 조작을 표현할 수 있도록 수행하여야 합니다. 대부분의 Extension 중점과는 다르게, Finder Sync 호스트 앱의 특징을 가지지 않습니다. 대신에, Finder 스스로가 수정 작업을 수행할 수있습니다.

→ Finder Sync Extension Feature

[영문]

  • Register a set of folders to monitor.
  • Receive notifications when the user starts or stops browsing the content of a monitored folder.
    • For example, the extension receives notification when the user opens a monitored folder in the Finder or in an Open or Save dialog.
  • Add, remove, and update badges and labels on items in a monitored folder.
  • Display a contextual menu when the user Control-clicks an item inside a monitored folder.
  • Add a custom button to the Finder’s toolbar.
  • Unlike badges and contextual menu items, this button is always available, even when the user is not currently browsing a monitored folder.

[국문]

  • 폴더들을 감시할 수 있도록 설정하여 등록할 수 있습니다.
  • 감시되고 있는 폴더 속의 내용들을 사용자가 탐색을 시작하거나 중단하였을 경우에 알림을 받을 수 있습니다.
    • 예를들어, 사용자가 Finder 또는 열기 및 저장 Dialog를 통하여 감시되고 있는 폴더를 열었을 경우에 알림을 받습니다.
  • 감시되고 있는 폴더 내부에 항목들에 대하여 레이블 그리고 배지들을 추가, 삭제, 갱신을 할 수 있습니다.
  • 감시되고 있는 폴더 내부에 항목을 사용자가 클릭하였을 경우에 컨텍스트 메뉴를 표시합니다.
  • Finder's 툴바에 특정 기능을 수행하는 사용자 정의 버튼을 할 수 있습니다.
    • 컨텍스트 메뉴 그리고 배지들과는 달리, Finder's 툴바 버튼은 항상 사용자에게 표시가 되며, 감시되고 있는 폴더가 아닌 다른 폴더를 탐색하고 있는 중에도 표시됩니다.

🗂 Finder Sync Extension 확장프로그램 권한 설정방법

시스템 환경 설정 → 확장 프로그램 → Finder 확장 프로그램에서 각 Finder Sync Extension 기능을 사용하는 애플리케이션을 설정하고자 하는 경우에는 체크, 그렇지 않은 경우에는 체크해제를 수행합니다.

 

🗂 Finder Sync Extension 확장프로그램 권한 설정방법

+ Setting Extensions Permission Source Code By Swift

 let process = Process()
 process.launchPath = "/usr/bin/pluginkit"
 process.arguments = ["-e", "use", "-i", "<FINDER_EXTENSION_IDENTIFICATION>"]
 process.launch()

+ Append FinderSync Extension Terminal Command

pluginkit -a <FINDER_EXTENSION_APPEX_FILE_NAME>

+ Enable FinderSync Extension Terminal Command

pluginkit -e use -i <FINDER_EXTENSION_BUNDLE_ID>

+ Disable FinderSync Extension Terminal Command

pluginkit -e ignore -i <FINDER_EXTENSION_BUNDLE_ID>

+ Show FinderSync Extension List Terminal Command

pluginkit -v -m -i <FINDER_EXTENSION_BUNDLE_ID>

🗂 Finder Sync Extension Human Interface Guidelines

[영문]

Apps that sync local and remote files should include a Finder Sync extension. For example, if your app syncs a folder within the user's Home folder, the Finder Sync extension can relay status information to the user within the Finder.

 

Through a Finder Sync extension, an app can:

 

  • Display badges in the Finder to indicate the sync status of items.
  • Provide custom contextual menu items that perform file and folder management tasks, like favoriting and adding password-protection.
  • Provide custom toolbar buttons that perform global actions, like forcing a sync operation.

 

→ Minimize badging. To avoid cluttering Finder windows with badges, consider badging items that aren’t synced rather than every item.

 

[국문]

Finder Sync Extension로컬 원격 파일들을 동기화하는 macOS 애플리케이션을 구현하는데 있어서 필수적으로 구현하여야 합니다. 예를들어, 만약 애플리케이션이 사용자 홈 폴더 내부의 폴더를 동기화를 하고자 한다면, Finder 애플리케이션 내의 사용자에게 Finder Sync Extension은 파일 및 폴더에 대한 상태 정보를 전달할 수 있습니다.

 

Finder Sync Extension을 통하여, 애플리케이션은 아래와 같은 기능을 수행할 수 있습니다.

 

  • 파일 및 폴더의 동기화 상태를 표시하는 배지를 Finder을 통하여 표시할 수 있습니다.
  • 파일 및 폴더 관리, 즐겨찾기, 암호 보호 기능 등의 작업을 수행하는 메뉴 항목들을 컨텍스트 메뉴를 통하여 사용자에게 제공할 수 있습니다.
  • 동기화 작업, 외부 작업을 수행하는 툴바 버튼을 제공할 수 있습니다.

 

→ Minimize badging. 배지로 인해서 Finder Window 어수선함을 피하기 위해서는, 모든 항목에 배지를 표시하기 보다는 동기화 작업이 수행되지 않은 항목들에 대해서만 배지를 표시하여야 합니다.


🗂 Finder Sync Extension Source Code

import Cocoa
import FinderSync

class FinderSync: FIFinderSync {

    var myFolderURL = URL(fileURLWithPath: "/Users/Shared/MySyncExtension Documents")
    
    override init() {
        super.init()
        
        NSLog("FinderSync() launched from %@", Bundle.main.bundlePath as NSString)
        
        // Set up the directory we are syncing.
        FIFinderSyncController.default().directoryURLs = [self.myFolderURL]
        
        // Set up images for our badge identifiers. For demonstration purposes, this uses off-the-shelf images.
        FIFinderSyncController.default().setBadgeImage(NSImage(named: NSImage.colorPanelName)!, label: "Status One" , forBadgeIdentifier: "One")
        FIFinderSyncController.default().setBadgeImage(NSImage(named: NSImage.cautionName)!, label: "Status Two", forBadgeIdentifier: "Two")
    }
    
    // MARK: - Primary Finder Sync protocol methods
    
    override func beginObservingDirectory(at url: URL) {
        // The user is now seeing the container's contents.
        // If they see it in more than one view at a time, we're only told once.
        NSLog("beginObservingDirectoryAtURL: %@", url.path as NSString)
    }
    
    
    override func endObservingDirectory(at url: URL) {
        // The user is no longer seeing the container's contents.
        NSLog("endObservingDirectoryAtURL: %@", url.path as NSString)
    }
    
    override func requestBadgeIdentifier(for url: URL) {
        NSLog("requestBadgeIdentifierForURL: %@", url.path as NSString)
        
        // For demonstration purposes, this picks one of our two badges, or no badge at all, based on the filename.
        let whichBadge = abs(url.path.hash) % 3
        let badgeIdentifier = ["", "One", "Two"][whichBadge]
        FIFinderSyncController.default().setBadgeIdentifier(badgeIdentifier, for: url)
    }
    
    // MARK: - Menu and toolbar item support
    
    override var toolbarItemName: String {
        return "FinderSy"
    }
    
    override var toolbarItemToolTip: String {
        return "FinderSy: Click the toolbar item for a menu."
    }
    
    override var toolbarItemImage: NSImage {
        return NSImage(named: NSImage.cautionName)!
    }
    
    override func menu(for menuKind: FIMenuKind) -> NSMenu {
        // Produce a menu for the extension.
        let menu = NSMenu(title: "")
        menu.addItem(withTitle: "Example Menu Item", action: #selector("HERE_SELECTOR_METHOD"), keyEquivalent: "")
        
        return menu
    }

}

A Typical Finder Sync Use Case

[영문]

  • The system calls beginObservingDirectoryAtURL: when the user first opens the monitored folder or one of its subfolders.
  • The system calls requestBadgeIdentifierForURL: for each item that is currently being drawn onscreen. Inside this method, do the following:
    1. Check the state of the item and set its badge by calling setBadgeIdentifier:forURL:.
      Your app is responsible for defining the states and their corresponding badges. For example, a typical syncing app might have badges that indicate unsynced local changes, syncing operations in progress, successfully synced items, and items with syncing errors or conflicts.
    2. Record the URL of every item that has received a badge.
      Your app must to continue to monitor the state of these items and update their badges as necessary. When an item’s state changes, update its badge by calling setBadgeIdentifier:forURL:.
  • The system calls endObservingDirectoryAtURL: when the user closes the folder. Delete all the URLs for the badged items inside that folder and stop monitoring their state.

 

[국문]

  • 사용자가 처음으로 감시 대상이 된 폴더 또는 폴더 내의 하나의 서브 폴더들을 열었을 경우에 System Call을 통하여 beginObservingDirectoryAtURL: 함수를 호출합니다.
  • 각 항목의 아이템이 화면상에 나타날 때 마다 System Call을 통하여 requestBadgeIdentifierForURL: 함수를 호출합니다. 또한, requestBadgeIdentifierForURL: 메서드는 아래의 작업을 수행합니다.
    1. 항목 상태에 대한 상태를 확인하고 setBadgeIdentifier:forURL:. 메서드를 호출하여 배지를 설정합니다. 애플리케이션은 항목에 상태에 따른 적합한 배지를 표시하여야 합니다. 예를들면, 보통적으로 동기화 애플리케이션은 항목에 대한 수정이 되었지만 동기화되지 않은 경우, 동기화 작업을 수행하는 경우, 성공적으로 동기화 작업을 수행한 경우 그리고 동기화 과정에서 발생한 오류 및 충돌에 대한 배지를 사용자에게 표시할 수 있도록 해당 관련 된 이미지를 포함하여야 합니다.
    2. 배지가 표시 된 모든 항목에 대한 URL을 기록합니다. 애플리케이션은 연속적으로 반드시 항목에 대하여 상태를 감시하고 배지를 업데이트 필수적으로 하여야 합니다. 항목들의 상태 변화가 변경이 되었을 경우, setBadgeIdentifier:forURL:.메서드 호출을 통하여 배지를 갱신합니다.
  • 사용자가 폴더를 닫은 경우, System Call을 통하여 endObservingDirectoryAtURL 함수를 호출함으로써 항목에 대한 상태 감시를 중단하고 폴더 내부의 항목들에 배지가 표시 된 항목들의 URL을 모두 제거합니다.

Finder Sync Specify Which Folders to Monitor

[영문 - ObjectiveC]

You specify the folders you want to monitor in your Finder Sync extension’s init method, using the default FIFinderSyncController object. In most cases, you want to let the user specify these folders in UI provided by the containing app. You can pass this data between the containing app and your Finder Sync extension using shared user defaults.

 

// Set up the folder we are syncing.
NSUserDefaults *sharedDefaults =
[[NSUserDefaults alloc] initWithSuiteName:@"com.example.domain.MyFirstFinderSyncExtension"];
 
self.myFolderURL = [sharedDefaults URLForKey:MyFolderKey];
 
if (self.myFolderURL == nil) {
    self.myFolderURL = [NSURL fileURLWithPath:[@"~/Documents/MyFirstFinderSyncExtension Documents" stringByExpandingTildeInPath]];;
}
 
[FIFinderSyncController defaultController].folderURLs = [NSSet setWithObject:self.myFolderURL];

 

[국문 - Swift]

기본적으로 FIFinderSyncController 객체를 사용하여 Finder Sync Extension's init 메서드에서 감시하고자 하는 폴더를 지정 할 수 있습니다. 대부분의경우에는, Finder Sync Extension을 포함하는 앱을 통하여 사용자에게 구체적인폴더의 경로를 지정 할 수 있도록 제공하여야합니다. 또한, User Defaults를 사용하여 Finder Sync Extension와 Finder Sync Extension을 포함하는 앱 사이의 데이터를 주고 받도록 할 수 있습니다.

 

var myFolderURL = URL(fileURLWithPath: "/Users/Shared/MySyncExtension Documents")
    
    override init() {
        super.init()
        
        NSLog("FinderSync() launched from %@", Bundle.main.bundlePath as NSString)
        
        // Set up the directory we are syncing.
        FIFinderSyncController.default().directoryURLs = [self.myFolderURL]
    }

→ 서브메뉴 추가방법 (Set Submenu of NSMenuItem) Source Code

override func menuForMenuKind(menuKind: FIMenuKind) -> NSMenu! {
    let main = NSMenu()
    let submenu = NSMenu()
    let mainDropdown = NSMenuItem(title: "Some option group", action: nil, keyEquivalent: "")
    main.addItem(mainDropdown)
    m.setSubmenu(submenu, forItem: mainDropdown)


    submenu.addItem(NSMenuItem(title: "Option 1", action: nil, keyEquivalent: ""))
    submenu.addItem(NSMenuItem(title: "Option 2", action: nil, keyEquivalent: ""))
    return main
}

🚀 REFERENCE

 

Unable to set submenu for NSMenuItem (FinderSync extension)

I'm trying to create a cascade submenu for a Finder Sync extension in Swift/Cocoa. I have the following code: override func menuForMenuKind(menuKind: FIMenuKind) -> NSMenu! { let m = NSMenu...

stackoverflow.com

 

Mac Finder extension to manage all cloud storages from one place

Mac OS X app extension for Finder that allows mounting cloud storages and web services as local disks - CloudMounter.

www.eltima.com

반응형

댓글