Macos开发:Finder Sync扩展的基本使用

文章目录

  • Finder Sync扩展介绍
  • Xcode新建工程
  • 新建Finder Sync扩展Target
  • 工具栏的变化
  • 调试运行显示右键菜单
  • 日志输出调试
  • 添加徽章

Finder Sync扩展介绍

当你用习惯了Windows,刚换到Mac会有各种不适应,比如右键菜单里不能新建txt文件,用惯了图形界面操作,svn、git都要使用命令行来操作,打开终端进入当前目录也要命令行,对于很多非开发人员来说这些操作很不友好,即使是开发人员我也想减少操作步骤,节省时间。

以上这些问题通过Finder Sync扩展都可以解决,你可以通过它来为你的右键菜单增加"新建txt"、“解压rar”、"当前目录打开终端"等功能项,你也可以把命令行使用的svn、git包装成图形界面工具,使用右键菜单和工具栏来灵活使用它。

总结Finder Sync扩展的使用场景:可以为你改造finder的右键菜单和工具栏菜单,至于点击菜单可以实现的功能你可以自由发挥,如果要上架到Appstore,功能设计上要考虑沙盒的局限性和权限的适用范围。

Xcode新建工程

Macos开发:Finder Sync扩展的基本使用_第1张图片Macos开发:Finder Sync扩展的基本使用_第2张图片

新建Finder Sync扩展Target

Macos开发:Finder Sync扩展的基本使用_第3张图片Macos开发:Finder Sync扩展的基本使用_第4张图片Macos开发:Finder Sync扩展的基本使用_第5张图片
Target会自动生成如下代码

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(sampleAction(_:)), keyEquivalent: "")
        return menu
    }
    
    @IBAction func sampleAction(_ sender: AnyObject?) {
        let target = FIFinderSyncController.default().targetedURL()
        let items = FIFinderSyncController.default().selectedItemURLs()
        
        let item = sender as! NSMenuItem
        NSLog("sampleAction: menu item: %@, target = %@, items = ", item.title as NSString, target!.path as NSString)
        for obj in items! {
            NSLog("    %@", obj.path as NSString)
        }
    }

}

这里设置你的FinderSync监控路径,finder处于如下路径及子路径中,你的扩展程序才会生效

var myFolderURL = URL(fileURLWithPath: "/Users/Shared/MySyncExtension Documents")

如果你要监控整个磁盘可以设置为

var myFolderURL = URL(fileURLWithPath: "/")

进入设置的监控路径及子路径触发

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)
}

工具栏的变化

Macos开发:Finder Sync扩展的基本使用_第6张图片
工具栏菜单项名称、鼠标悬停提示文字以及图标的设置在如下方法内

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)!
}

finder中的右键菜单以及工具栏菜单的显示都会在下面方法内处理

override func menu(for menuKind: FIMenuKind) -> NSMenu {
    let menu = NSMenu(title: "")
    //右键点击空白区域显示的菜单
    if(menuKind == FIMenuKind.contextualMenuForItems) {
        menu.addItem(withTitle: "Context Menu Item context", action: #selector(sampleAction(_:)), keyEquivalent: "")
    }
    //右键点击文件或文件夹显示的菜单
    else if(menuKind == FIMenuKind.contextualMenuForItems) {
        menu.addItem(withTitle: "Context Item Menu Item", action: #selector(sampleAction(_:)), keyEquivalent: "")
    }
    //点击工具栏图标显示的菜单
    else if(menuKind == FIMenuKind.toolbarItemMenu) {
        menu.addItem(withTitle: "Toolbar Menu Item", action: #selector(sampleAction(_:)), keyEquivalent: "")
    }
    //右键点击侧栏显示的菜单
    else if(menuKind == FIMenuKind.contextualMenuForSidebar) {
        menu.addItem(withTitle: "Sidebar Menu Item", action: #selector(sampleAction(_:)), keyEquivalent: "")
    }
    return menu
}

调试运行显示右键菜单

确保finder扩展已勾选
Macos开发:Finder Sync扩展的基本使用_第7张图片
运行和普通应用不同,需要选择一个应用,选择finder即可
Macos开发:Finder Sync扩展的基本使用_第8张图片
右键点击菜单如图
Macos开发:Finder Sync扩展的基本使用_第9张图片

日志输出调试

finder扩展程序的调试没办法运行断点调试,也不能控制台输出,调试是个很棘手的问题,添加如下方法把控制台输出写入日志文件,通过查看日志文件来一点点调试开发。如果某个操作后突然发现右键菜单消失了或者工具栏中的菜单项不见了,就去看日志吧,十之八九是异常退出了!

func initLogSetting(){
    let tmpPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL
    let fileName = "/out.log"// 注意不是NSData!
    let logFilePath = tmpPath.path!.appending(fileName)
    freopen(logFilePath.cString(using: .utf8), "a+", stdout)
    freopen(logFilePath.cString(using: .utf8), "a+", stderr);
    //writeLog(str: logFilePath)
}

修改override init()方法增加

override init() {
    super.init()
    initLogSetting()
    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")
}

输出日志目录,因为启用了沙盒,文件会创建到沙盒目录下,

/Users/{用户}/Library/Containers/com.test.Macos-FinderSyncExtension.FinderSyncExt/Data/Documents/out.log

添加徽章

徽章功能不太实用,太多应用为了把自己的功能增加到右键菜单或工具栏中都实现了Finder扩展,例如解压缩软件、有道词典之类,徽章是否能显示成功取决于你的finder启动顺序是否是第一个或干脆是唯一一个,实际中不手动干预扩展设置,基本没机会显示出来。
Macos开发:Finder Sync扩展的基本使用_第10张图片
指定可使用的徽章图标

// 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")

显示徽章,不是唯一的一个finder扩展或者启动顺序排第一个,就不要想进入这个方法了,都不会被调用到,鸡肋的功能

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) % 2
    let badgeIdentifier = ["One", "Two"][whichBadge]
    FIFinderSyncController.default().setBadgeIdentifier(badgeIdentifier, for: url)
}

你可能感兴趣的:(MacOS开发实例,macos,xcode,swiftui,ios)