Общайтесь с другим приложением с помощью XPC

У меня есть оконное приложение, и для добавления некоторых функций мне нужно другое приложение, которое запускается при входе в систему и синхронизирует данные с сервером, если доступно.

Я пытался с NSDistributionNotification, но это практически бесполезно в изолированном приложении. Я посмотрел XPC и надеялся, что он будет работать, но я просто не знаю, как заставить его работать с помощником. До сих пор я сделал это с помощью XPC.

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

    NSXPCInterface *remoteInterface = [NSXPCInterface interfaceWithProtocol:@protocol(AddProtocol)];
    NSXPCConnection *xpcConnection = [[NSXPCConnection alloc] initWithServiceName:@"com.example.SampleService"];

    xpcConnection.remoteObjectInterface = remoteInterface;

    xpcConnection.interruptionHandler = ^{
        NSLog(@"Connection Terminated");
    };

    xpcConnection.invalidationHandler = ^{
        NSLog(@"Connection Invalidated");
    };

    [xpcConnection resume];

    NSInteger num1 = [_number1Input.stringValue integerValue];
    NSInteger num2 = [_number2Input.stringValue integerValue];

    [xpcConnection.remoteObjectProxy add:num1 to:num2 reply:^(NSInteger result) {
        NSLog(@"Result of %d + %d = %d", (int) num1, (int) num2, (int) result);
    }];

XPC Сервис

In main () ...
SampleListener *delegate = [[SampleListener alloc] init];
NSXPCListener *listener = [NSXPCListener serviceListener];
listener.delegate = delegate;
[listener resume];

// In delegate
-(BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
    NSXPCInterface *interface = [NSXPCInterface interfaceWithProtocol:@protocol(AddProtocol)];
    newConnection.exportedInterface = interface;
    newConnection.exportedObject = [[SampleObject alloc] init];
    [newConnection resume];
    return YES;
}

// In Exported Object class

-(void)add:(NSInteger)num1 to:(NSInteger)num2 reply:(void (^)(NSInteger))respondBack {
    resultOfAddition = num1 + num2;
    respondBack(resultOfAddition);
}

Это работает нормально, теперь мне нужно передать этот результат в приложение Helper. Как я могу это сделать? Если XPC не является ответом здесь, чтобы общаться, то какой я должен использовать? Любые указатели, пожалуйста?

2 ответа

Ладно, для всех, кто боролся с этим, я наконец смог на 100% установить связь между двумя процессами приложения, используя NSXPCConnection

Ключ к сведению, что вы можете только создать NSXPCConnection до трех вещей.

  1. XPCService. Вы можете подключиться к XPCService строго через имя
  2. Маха Сервис. Вы также можете подключиться к службе Mach строго через имя
  3. NSXPCEndpoint, Это то, что мы ищем, чтобы общаться между двумя прикладными процессами.

Проблема в том, что мы не можем напрямую передать NSXPCEndpoint из одного приложения в другое.

Он включал создание агента запуска machservice ( см. Этот пример, как это сделать), который содержал NSXPCEndpoint имущество. Одно приложение может подключиться к machservice и установить это свойство на свое собственное [NSXPCListener anonymousListener].endpoint

Затем другое приложение может подключиться к machservice и запросить эту конечную точку.

Затем, используя эту конечную точку, NSXPCConnection может быть создан, который успешно установил мост между двумя приложениями. Я проверил отправку объектов туда и обратно, и все работает как положено.

Обратите внимание, что если ваше приложение находится в "песочнице", вам придется создать XPCService как посредник между вашим Приложением и Machservice

Я очень рад, что у меня все получилось - я довольно активен в SO, поэтому, если кто-то заинтересован в исходном коде, просто добавьте комментарий, и я могу приложить усилия, чтобы опубликовать больше деталей

Некоторые препятствия, с которыми я столкнулся:

Вы должны запустить свой machservice, это строки:

   OSStatus                    err;
   AuthorizationExternalForm   extForm;

   err = AuthorizationCreate(NULL, NULL, 0, &self->_authRef);
   if (err == errAuthorizationSuccess) {
      NSLog(@"SUCCESS AUTHORIZING DAEMON");
   }
   assert(err == errAuthorizationSuccess);

   Boolean             success;
   CFErrorRef          error;

   success = SMJobBless(
                        kSMDomainSystemLaunchd,
                        CFSTR("DAEMON IDENTIFIER HERE"),
                        self->_authRef,
                        &error
                        );

Кроме того, каждый раз, когда вы перестраиваете своего демона, вы должны выгружать предыдущий агент запуска с помощью следующих команд bash:

sudo launchctl unload /Library/LaunchDaemons/com.example.apple-samplecode.EBAS.HelperTool.plist
sudo rm /Library/LaunchDaemons/com.example.apple-samplecode.EBAS.HelperTool.plist
sudo rm /Library/PrivilegedHelperTools/com.example.apple-samplecode.EBAS.HelperTool

(С вашими соответствующими идентификаторами, конечно)

Если вы ищете, как это сделать в Swift. Я написал руководство о том, как это сделать:

https://rderik.com/blog/creating-a-launch-agent-that-provides-an-xpc-service-on-macos/

Вы должны сначала создать Launch Agent (или демон, если вам нужны дополнительные привилегии), который предоставляет службу XPC. Служба XPC будет зарегистрирована как служба mach, которую предоставляет ваш агент. Таким образом, вашему агенту придется создать слушателя, подобного следующему:

let listener = NSXPCListener(machServiceName: "com.rderik.exampleXPC" )

И чтобы использовать эту услугу от другого клиента, вам нужно создатьNSXPCConnectionк тому сервису. Как это:

let connection = NSXPCConnection(machServiceName: "com.rderik.exampleXPC")

За кулисами, упрощение того, что происходит, заключается в том, что ваш агент зарегистрирует вашу службу mach в launchd. Когда ваш "клиент" хочет подключиться к сервису machlaunchd он уже будет зарегистрирован, поэтому он установит связь между ними.

Надеюсь, это поможет.

Я думаю, я понял, как это сделать. Все, что вам нужно сделать, это создать вспомогательный инструмент командной строки в XCode, установить его как задание Launchd (либо демон, либо агент в зависимости от требований привилегий). Вы можете использовать определенный протокол для связи с вспомогательным инструментом. Обратитесь к приведенному ниже образцу кода от Apple, чтобы понять, как это делается.

Образец кода от Apple: https://developer.apple.com/library/mac/samplecode/EvenBetterAuthorizationSample/Listings/Read_Me_About_EvenBetterAuthorizationSample_txt.html

Прочитайте приведенную ниже ссылку, чтобы понять, что вы действительно хотите, демон или агент: https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/DesigningDaemons.html

Другие вопросы по тегам