Как должны взаимодействовать расширение Finder Sync и основное приложение?

Мой вариант использования: у меня есть «MainApp», который выполняет синхронизацию файлов. Я хотел бы, чтобы «MainApp» обрабатывал все вызовы сервера, касающиеся синхронизации и других вызовов REST API, таких как обмен документами и т. д.

С другой стороны, у меня было бы расширение Finder Sync, которое показывало бы наложения значков состояния синхронизации. Он также будет иметь элемент контекстного меню файла «Поделиться», который представит диалоговое окно «Поделиться», в котором пользователи могут выбрать, с кем поделиться файлом.

Вопросы:

  1. Как должны взаимодействовать FinderSyncExtension и MainApp? Следует ли использовать XCP, и если да, то нормально ли, что связь является двусторонней? Например, MainApp сообщает Finder, что он должен обновиться, поскольку некоторые файлы были синхронизированы, а Finder сообщает MainApp, что он должен выполнить операцию «Общий доступ».

  2. Кто должен представить диалоговое окно «Поделиться»? При выборе пункта меню «Поделиться» FinderSyncExtension должна отображаться форма «Поделиться». Должно ли это отображаться расширением Finder или MainApp (при условии, что FinderExtension сообщил ему, что элемент «Поделиться» был нажат).

Если расширение Finder должно представлять форму, то FinderExtension также должно получать данные с сервера (например, контакты и группы для совместного использования), и я не уверен, должно ли расширение Finder выполнять какие-либо сетевые вызовы к серверу.

Изучая тему, я нашел несколько подходов:

  1. FinderSyncExtension и MainApp не взаимодействуют напрямую. Вместо этого FinderExtension считывает данные из базы данных, чтобы правильно отображать значки. В этом сценарии неясно, как FinderExtension должен обновляться после завершения синхронизации или как он должен информировать MainApp о выполнении каких-либо действий.
  2. Связь ХПК. Я предполагаю, что FinderExtension может инициировать вызовы MainApp, но ожидается ли противоположное направление?
  3. Есть ли какой-то NotificationCenter между процессами macOS? Я пробовал с NSWorkspace.sharedWorkspace.notificationCenter и с NSDistributedNotificationCenter.defaultCenter, но они, похоже, не доставляют уведомления в MainApp.
  4. mach_ports как в проекте Seafile?

person mixtly87    schedule 07.12.2016    source источник


Ответы (2)


Мне удалось сделать это через CFMessagePort API. Чтобы иметь изолированное расширение и основное приложение для связи, группы приложений должны быть включены в возможностях Xcode. Кроме того, ключ группы приложений с суффиксом (по вашему выбору) необходимо использовать в качестве идентификатора порта сообщений.

Основное приложение

Где-то в основном приложении такой код будет прослушивать порт сообщений:

CFMessagePortRef port = CFMessagePortCreateLocal(nil, CFSTR("group.com.yourapp.mach_or_something"), Callback, nil,
                                                 nil);
CFRunLoopSourceRef runLoopSource = CFMessagePortCreateRunLoopSource(nil, port, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);

Callback - это метод, реализованный как:

static CFDataRef Callback(CFMessagePortRef port, SInt32 messageID, CFDataRef data, void* info)
{
    NSData* objcData = (__bridge NSData*) data;
    NSLog(@"Message received: %@", [NSString.alloc initWithData:objcData encoding:NSASCIIStringEncoding]);
    return data;
}

Расширение синхронизации Finder

И затем где-то в расширении (т.е. когда пользователь нажимает на пункт меню):

CFDataRef data = CFDataCreate(NULL, (const UInt8*) "somedata", 8);
SInt32 messageID = 0x1111; // Arbitrary
CFTimeInterval timeout = 1;

CFMessagePortRef remotePort = CFMessagePortCreateRemote(nil, CFSTR("group.com.yourapp.mach_or_something"));

SInt32 status = CFMessagePortSendRequest(remotePort, messageID, data, timeout, timeout, NULL, NULL);
if (status == kCFMessagePortSuccess)
{
    NSLog(@"SUCCESS STATUS");
}
else
{
    NSLog(@"FAIL STATUS");
}

Это отправит сообщение в основное приложение.

person mixtly87    schedule 15.12.2016
comment
Хм, кажется, с этим подходом в macOS Sierra произошел сбой. На Эль-Капитане работает нормально. Я отправил сообщение об ошибке в Apple относительно. - person mixtly87; 04.03.2017
comment
Я не думаю, что это проблема с Sierra. Я изменил вашу функцию обратного вызова на что-то вроде это, и затем она работала в Сьерре без каких-либо проблем. - person hklel; 19.04.2017
comment
Это работает! Я изменю ответ, чтобы отразить правильное решение. Спасибо, Алекс. - person mixtly87; 21.04.2017
comment
@AlexLing Также работает, если NSData * приводится к «__bridge» вместо «__bridge_transfer». '__bridge_transfer' заставляет ARC освобождать параметр данных при возврате обратного вызова. Вместо этого должно быть (__bridge NSData*) без _transfer. Это изменение устраняет сбой. - person mixtly87; 03.05.2017
comment
@ mixtly87, я получаю сообщение об отказе в разрешении в приложении песочницы, вы знаете, как его решить? *** CFMessagePort: bootstrap_register(): сбой 1100 (0x44c) «Отказано в доступе», порт = 0x7c0f, имя = - person jimwan; 02.08.2018

Документация Apple о изолированной среде Mach Inter-Process Communication:

https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24

Семафоры IPC и POSIX и общая память

Обычно изолированные приложения не могут использовать Mach IPC, семафоры POSIX и общую память или сокеты домена UNIX (полезно). Однако, указав разрешение, которое запрашивает членство в группе приложений, приложение может использовать эти технологии для связи с другими членами этой группы приложений.

Любой семафор или порт Mach, к которому вы хотите получить доступ в изолированном приложении, должен быть назван в соответствии со специальным соглашением:

  • Имена семафоров POSIX и разделяемой памяти должны начинаться с идентификатора группы приложений, за которым следует косая черта (/) и имя по вашему выбору. Имена портов Mach должны начинаться с идентификатора группы приложений, за которым следует точка (.), а затем имя по вашему выбору.

  • Например, если имя вашей группы приложений Z123456789.com.example.app-group, вы можете создать два семафора с именами Z123456789.myappgroup/rdyllwflg и Z123456789.myappgroup/bluwhtflg. Вы можете создать порт Mach с именем Z123456789.com.example.app-group.Port_of_Kobe.

Примечание. Максимальная длина имени семафора POSIX составляет всего 31 байт, поэтому, если вам нужно использовать семафоры POSIX, имена групп приложений должны быть короткими.

person pkamb    schedule 19.10.2018