Mac OS?-Finder Sync使用入門

1. 初識(shí)Finder Sync

借助Finder Sync擴(kuò)展购公,您可以注冊(cè)一個(gè)或多個(gè)文件夾進(jìn)行監(jiān)控秉继。接下來,您可以在監(jiān)控項(xiàng)目中設(shè)置標(biāo)記并為其創(chuàng)建上下文菜單(contextual menus)糙俗。使用來自該應(yīng)用擴(kuò)展的API垃瞧,您也能在Finder窗體中增加工具欄按鈕。

Finder Sync支持可同步本地文件夾與遠(yuǎn)程數(shù)據(jù)源內(nèi)容的應(yīng)用程序船庇。它直接在Finder中提供即時(shí)的視覺反饋以改善用戶體驗(yàn)吭产。標(biāo)記顯示了每個(gè)項(xiàng)目的同步狀態(tài),上下文菜單讓用戶可以管理文件夾內(nèi)容溢十,自定義工具欄按鈕能調(diào)用全局操作垮刹,比如打開一個(gè)受監(jiān)視的文件夾或者進(jìn)行同步操作。

提示:Finder Sync擴(kuò)展僅能讓您修改用戶界面张弛。它不進(jìn)行實(shí)際的同步操作荒典。您需要負(fù)責(zé)創(chuàng)建自己的同步組件。

Finder Sync擴(kuò)展有如下功能:

(1).注冊(cè)一組用于監(jiān)視的文件夾吞鸭。

(2).當(dāng)用戶開始或停止瀏覽受監(jiān)視文件夾的內(nèi)容時(shí)收到通知寺董。

比方說,當(dāng)用戶在Finder或在打開/保存對(duì)話框中打開了受監(jiān)視的文件夾時(shí)刻剥,擴(kuò)展將會(huì)收到消息通知遮咖。

(3).在受監(jiān)視文件夾中添加、移除以及更新項(xiàng)目上的標(biāo)記造虏。

(4).當(dāng)用戶在受監(jiān)視文件夾中右鍵單擊了一個(gè)項(xiàng)目時(shí)御吞,顯示一個(gè)上下文菜單。

(5).在Finder工具欄上添加自定義按鈕漓藕。

和標(biāo)記以及上下文菜單不同陶珠,即使用戶當(dāng)前沒有瀏覽受監(jiān)視的文件夾,這種按鈕仍然是始終可視的享钞,

2. 指定受監(jiān)視的文件夾

Finder Sync應(yīng)用擴(kuò)展的init方法中指定想要監(jiān)視的文件夾揍诽,默認(rèn)使用FIFinderSyncController對(duì)象。在絕大多數(shù)情況下,讓用戶在關(guān)聯(lián)應(yīng)用程序提供的用戶界面中指定受監(jiān)視的文件夾暑脆。您可以在關(guān)聯(lián)應(yīng)用程序和共享了用戶默認(rèn)設(shè)置的Finder Sync應(yīng)用擴(kuò)展之間使用這個(gè)數(shù)據(jù)渠啤。

激活共享用戶設(shè)置,首先在Finder Sync應(yīng)用擴(kuò)展和其關(guān)聯(lián)應(yīng)用程序中都添加一個(gè)應(yīng)用程序組(Group)添吗。這個(gè)組創(chuàng)建了應(yīng)用擴(kuò)展和其關(guān)聯(lián)應(yīng)用程序都可以訪問沥曹、共享的容器。打開Xcode中每一個(gè)對(duì)象的Capabilities窗格根资,并激活A(yù)pp Groups架专。 然后對(duì)共享組提供唯一標(biāo)識(shí)符同窘。請(qǐng)務(wù)必對(duì)Finder Sync擴(kuò)展和其關(guān)聯(lián)應(yīng)用程序使用同一個(gè)標(biāo)識(shí)符玄帕。

image.png
image.png

接下來,通過調(diào)用initWithSuiteName:方法以及使用共享組中的標(biāo)識(shí)符來實(shí)例化一個(gè)新的NSUserDefaults對(duì)象想邦。這種init方法將創(chuàng)建一個(gè)默認(rèn)的用戶對(duì)象裤纹,用來加載和保存數(shù)據(jù)到共享容器中。

3. 代碼比較直觀

//
//  FinderSync.m
//  ZZXFinderSync
//
//  Created by  on 2021/11/11.
//

#import "FinderSync.h"

@interface FinderSync ()

@property NSURL *myFolderURL;

@end

@implementation FinderSync

- (instancetype)init {
    self = [super init];

    NSLog(@"%s launched from %@ ; compiled at %s", __PRETTY_FUNCTION__, [[NSBundle mainBundle] bundlePath], __TIME__);

    // Set up the directory we are syncing.
    self.myFolderURL = [NSURL fileURLWithPath:@"/Users/Shared/MySyncExtension Documents"];
    [FIFinderSyncController defaultController].directoryURLs = [NSSet setWithObject:self.myFolderURL];

    // Set up images for our badge identifiers. For demonstration purposes, this uses off-the-shelf images.
    [[FIFinderSyncController defaultController] setBadgeImage:[NSImage imageNamed: NSImageNameColorPanel] label:@"Status One" forBadgeIdentifier:@"One"];
    [[FIFinderSyncController defaultController] setBadgeImage:[NSImage imageNamed: NSImageNameCaution] label:@"Status Two" forBadgeIdentifier:@"Two"];
    [[FIFinderSyncController defaultController] setBadgeImage:[NSImage imageNamed: NSImageNameCaution] label:@"Status Two" forBadgeIdentifier:@"Three"];
    
    [self writeToFile];
    return self;
}

#pragma mark - 徽章處理 文件同步的代理

- (void)beginObservingDirectoryAtURL:(NSURL *)url {
    NSLog(@"beginObservingDirectoryAtURL:%@", url.filePathURL);
    /*
     當(dāng)用戶開始查看受監(jiān)視文件夾或其子文件夾的內(nèi)容時(shí)丧没,系統(tǒng)將會(huì)調(diào)用此方法鹰椒。它將當(dāng)前打開文件夾的URL作為參數(shù)。
     對(duì)于每個(gè)唯一的URL呕童,系統(tǒng)只調(diào)用此方法一次漆际。
     只要這些內(nèi)容仍然在至少一個(gè)Finder窗口中可見,任何額外打開相同URL的Finder窗口的操作將被忽略夺饲。
     系統(tǒng)為所有打開和保存對(duì)話框額外創(chuàng)建您擴(kuò)展的實(shí)例奸汇。
     這些擴(kuò)展將自己調(diào)用beginObservingDirectoryAtURL:方法,即使該文件夾已經(jīng)在Finder窗口中打開往声。
     */
}

- (void)endObservingDirectoryAtURL:(NSURL *)url {
    NSLog(@"endObservingDirectoryAtURL:%@", url.filePathURL);
    /*
     當(dāng)用戶不再查看給定URL中的內(nèi)容時(shí)擂找,系統(tǒng)將會(huì)調(diào)用此方法.
     與beginObservingDirectoryAtURL方法一樣,打開和保存對(duì)話框分別在Finder中被額外創(chuàng)建擴(kuò)展實(shí)例浩销。
     */
}

- (void)requestBadgeIdentifierForURL:(NSURL *)url {
    NSLog(@"requestBadgeIdentifierForURL:%@", url.filePathURL);
    /*
     當(dāng)受監(jiān)視文件夾中的一個(gè)新項(xiàng)目變得對(duì)用戶可見時(shí)贯涎,系統(tǒng)將會(huì)調(diào)用此方法。當(dāng)每個(gè)文件首次在Finder視圖中顯示慢洋,這個(gè)方法就會(huì)被調(diào)用一次塘雳。每當(dāng)新文件滾動(dòng)到視圖中,系統(tǒng)也會(huì)繼續(xù)調(diào)用此方法普筹。

     您通常執(zhí)行此方法來檢查所提供URL對(duì)應(yīng)項(xiàng)目的狀態(tài)败明,然后調(diào)用Finder Sync控制器的setBadgeIdentifier:forURL:方法來設(shè)置相應(yīng)的標(biāo)記。您可能還想要跟蹤這些URL斑芜,只要它們的狀態(tài)發(fā)生變化就更新他們的標(biāo)記肩刃。
     */
    NSString *nsFilePath = [url.filePathURL path];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    // 文件夾不處理。
    BOOL isDir;
    [fileManager fileExistsAtPath:nsFilePath isDirectory:&isDir];
    if (isDir) return;
    
    // 獲取文件的修改時(shí)間。
    NSDictionary *attrDict = [fileManager attributesOfItemAtPath:nsFilePath error:nil];
    NSDate *modDate = [attrDict objectForKey:NSFileModificationDate];
    NSLog(@"??????   修改時(shí)間 ----%@",modDate);
    // /private/var/folders/kt/k000ltc54fz78ffbxjdvg63w0000gn/T/com.zzx.MacWithXPC.ZZXFinderSync
    
    //徽章處理
    NSInteger whichBadge = [url.filePathURL hash] % 3;
    NSString* badgeIdentifier = @[@"One", @"Two", @"three"][whichBadge];
    [[FIFinderSyncController defaultController] setBadgeIdentifier:badgeIdentifier forURL:url];
}

#pragma mark - 菜單處理 添加上下文菜單欄
/// 新增選項(xiàng)
- (NSString *)toolbarItemName {
    return @"ZZXFinderSync";
}
/// 新增選項(xiàng) -簡(jiǎn)介
- (NSString *)toolbarItemToolTip {
    return @"ZZXFinderSync: Click the toolbar item for a menu.";
}
/// 新增選項(xiàng) - icon
- (NSImage *)toolbarItemImage {
    return [NSImage imageNamed:NSImageNameCaution];
}

- (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu {
    /*
     打開文件夾時(shí)刷新
     選中文件時(shí)也會(huì)刷新
     */
    
    /*
     下面這個(gè)不知道怎么用盈包?
     實(shí)現(xiàn)menuForMenuKind:方法以提供一個(gè)自定義的上下文菜單沸呐。
     該menu參數(shù)指明了您的應(yīng)用擴(kuò)展應(yīng)該創(chuàng)建的菜單類型。每個(gè)菜單類型對(duì)應(yīng)不同的用戶交互類型呢燥。

     FIMenuKindContextualMenuForItems
     用戶右鍵單擊單個(gè)或多個(gè)受監(jiān)控文件夾內(nèi)的項(xiàng)目崭添。您的應(yīng)用擴(kuò)展應(yīng)當(dāng)顯示影響所選項(xiàng)目的菜單項(xiàng)。

     FIMenuKindContextualMenuForContainer
     當(dāng)用戶瀏覽受監(jiān)控文件夾時(shí)右鍵單擊Finder窗口的空白處叛氨。您的擴(kuò)展應(yīng)當(dāng)顯示影響當(dāng)前文件夾內(nèi)容的菜單項(xiàng)呼渣。

     FIMenuKindContextualMenuForSidebar
     用戶右鍵單擊顯示受監(jiān)控文件夾及其部分內(nèi)容的側(cè)邊欄。您的擴(kuò)展應(yīng)當(dāng)顯示影響所選項(xiàng)內(nèi)容的菜單項(xiàng)寞埠。

     FIMenuKindToolbarItemMenu
     用戶單擊擴(kuò)展提供的導(dǎo)航欄按鈕屁置。由于導(dǎo)航欄按鈕始終可見,用戶此時(shí)有可能沒在瀏覽受監(jiān)控的文件夾仁连。您的擴(kuò)展或許要顯示能始終讓用戶可見的全局操作的菜單欄蓝角。如果存在某個(gè)菜單項(xiàng),其仍然可以影響在受監(jiān)控文件夾中所選的項(xiàng)目饭冬。
     */

    NSMenu *mainMenu = [[NSMenu alloc] init];
    NSMenuItem *menuItem1 = [[NSMenuItem alloc] initWithTitle:@"菜單1" action:nil keyEquivalent:@""];
    NSMenuItem *menuItem2 = [[NSMenuItem alloc] initWithTitle:@"菜單2" action:nil keyEquivalent:@""];
    [mainMenu addItem:menuItem1];
    [mainMenu insertItem:menuItem2 atIndex:0];
    
    
    //當(dāng)前選中的文件
    NSURL* target = [[FIFinderSyncController defaultController] targetedURL];
    NSArray* items = [[FIFinderSyncController defaultController] selectedItemURLs];
    if (items.count > 0) {
        //單獨(dú)設(shè)置菜單的顯示
        NSString *nsFilePath = [items.firstObject path];
        NSLog(@"??????   nsFilePath ----%@----%@",nsFilePath,target.path);
    }
    
    
    NSInteger indexItem = 0;

    NSMenu *subMenu1 = [[NSMenu alloc] init];
    //-*開始 測(cè)試用
    NSMenuItem *restoreItem = [[NSMenuItem alloc] initWithTitle:@"選項(xiàng)1" action:@selector(restoreFile:) keyEquivalent:@""];
    [restoreItem setTarget:self];
    [restoreItem setEnabled:YES];
    [subMenu1 insertItem:restoreItem atIndex:indexItem];
    indexItem++;

    NSMenuItem *decryptItem = [[NSMenuItem alloc] initWithTitle:@"選項(xiàng)2" action:@selector(decryptFile:) keyEquivalent:@""];
    [decryptItem setTarget:self];
    [decryptItem setEnabled:YES];
    [subMenu1 insertItem:decryptItem atIndex:indexItem];
    indexItem++;

    NSMenuItem *encryptItem = [[NSMenuItem alloc] initWithTitle:@"選項(xiàng)3" action:@selector(encryptFile:) keyEquivalent:@""];
    [encryptItem setTarget:self];
    [encryptItem setEnabled:YES];
    [subMenu1 insertItem:encryptItem atIndex:indexItem];
    indexItem++;

    NSMenu *subMenu2 = [[NSMenu alloc] init];
    
    NSMenuItem *encryptItem1 = [[NSMenuItem alloc] initWithTitle:@"選項(xiàng)4" action:@selector(encryptFile:) keyEquivalent:@""];
    [encryptItem1 setTarget:self];
    [encryptItem1 setEnabled:YES];
    [subMenu2 insertItem:encryptItem1 atIndex:0];
    indexItem++;
    
    NSMenuItem *encryptItem2 = [[NSMenuItem alloc] initWithTitle:@"選項(xiàng)5" action:@selector(encryptFile:) keyEquivalent:@""];
    [encryptItem2 setTarget:self];
    [encryptItem2 setEnabled:YES];
    [subMenu2 insertItem:encryptItem2 atIndex:1];
    indexItem++;
    
    
    [mainMenu setSubmenu:subMenu1 forItem:menuItem1];
    [mainMenu setSubmenu:subMenu2 forItem:menuItem2];
    return mainMenu;
}

- (IBAction)sampleAction:(id)sender {
    NSURL* target = [[FIFinderSyncController defaultController] targetedURL];
    NSArray* items = [[FIFinderSyncController defaultController] selectedItemURLs];

    NSLog(@"sampleAction: menu item: %@, target = %@, items = ", [sender title], [target filePathURL]);
    [items enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"文件路徑:%@", [obj path]);
        
        //設(shè)置徽標(biāo)
        NSString *filePath = [obj path];
        [[FIFinderSyncController defaultController] setBadgeIdentifier:@"Three" forURL:[NSURL fileURLWithPath:filePath]];
        
    }];
}

- (IBAction)restoreFile:(id)sender {
    NSURL* target = [[FIFinderSyncController defaultController] targetedURL];
    NSArray* items = [[FIFinderSyncController defaultController] selectedItemURLs];

    NSLog(@"sampleAction: menu item: %@, target = %@, items = ", [sender title], [target filePathURL]);
    [items enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"    %@", [obj filePathURL]);
    }];
}

- (IBAction)decryptFile:(id)sender {
    NSURL* target = [[FIFinderSyncController defaultController] targetedURL];
    NSArray* items = [[FIFinderSyncController defaultController] selectedItemURLs];

    NSLog(@"sampleAction: menu item: %@, target = %@, items = ", [sender title], [target filePathURL]);
    [items enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"    %@", [obj filePathURL]);
    }];
}
- (IBAction)encryptFile:(id)sender {
    NSURL* target = [[FIFinderSyncController defaultController] targetedURL];
    NSArray* items = [[FIFinderSyncController defaultController] selectedItemURLs];

    NSLog(@"sampleAction: menu item: %@, target = %@, items = ", [sender title], [target filePathURL]);
    [items enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"    %@", [obj filePathURL]);
    }];
}

-(void)writeToFile{
    NSString *tmpPath = NSTemporaryDirectory();
    NSString *fileName = [NSString stringWithFormat:@"ZZXFinderSync.log"];// 注意不是NSData!
    NSString *logFilePath = [tmpPath stringByAppendingPathComponent:fileName];
    
//    NSString *logFilePath = @"/Users/mac/Desktop/ZZX/ZZXFinderSync.log";
    // 將log輸入到文件
    freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stdout);
    freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);
}
@end

4. 運(yùn)行

選擇ZZXFinderSync來運(yùn)行使鹅,依附于Finder,然后Run:

image.png
image.png

運(yùn)行成功后昌抠,打開一個(gè)文件夾患朱,就可以看到效果,點(diǎn)擊菜單打印結(jié)果炊苫。

image.png

或者


image.png

4. 調(diào)試

可以將控制臺(tái)打印寫到文件中方便調(diào)試

-(void)writeToFile{
    NSString *tmpPath = NSTemporaryDirectory();
    NSString *fileName = [NSString stringWithFormat:@"ZZXFinderSync.log"];// 注意不是NSData!
    NSString *logFilePath = [tmpPath stringByAppendingPathComponent:fileName];

    // 將log輸入到文件
    freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stdout);
    freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末裁厅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子劝评,更是在濱河造成了極大的恐慌姐直,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蒋畜,死亡現(xiàn)場(chǎng)離奇詭異声畏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)姻成,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門插龄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人科展,你說我怎么就攤上這事均牢。” “怎么了才睹?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵徘跪,是天一觀的道長(zhǎng)甘邀。 經(jīng)常有香客問我,道長(zhǎng)垮庐,這世上最難降的妖魔是什么松邪? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮哨查,結(jié)果婚禮上逗抑,老公的妹妹穿的比我還像新娘。我一直安慰自己寒亥,他們只是感情好邮府,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著溉奕,像睡著了一般褂傀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腐宋,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天紊服,我揣著相機(jī)與錄音檀轨,去河邊找鬼胸竞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛参萄,可吹牛的內(nèi)容都是我干的卫枝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼讹挎,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼校赤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起筒溃,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤马篮,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后怜奖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浑测,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年歪玲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了迁央。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡滥崩,死狀恐怖岖圈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情钙皮,我是刑警寧澤蜂科,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布顽决,位于F島的核電站,受9級(jí)特大地震影響导匣,放射性物質(zhì)發(fā)生泄漏擎值。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一逐抑、第九天 我趴在偏房一處隱蔽的房頂上張望鸠儿。 院中可真熱鬧,春花似錦厕氨、人聲如沸进每。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽田晚。三九已至,卻和暖如春国葬,著一層夾襖步出監(jiān)牢的瞬間贤徒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工汇四, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留接奈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓通孽,卻偏偏與公主長(zhǎng)得像序宦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子背苦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容