Пример скриптового приложения

Очевидно, есть способ сделать мое приложение с графическим интерфейсом сценариев с помощью AppleScript. Так, например, у меня могло бы быть приложение командной строки (такое как запуск от LaunchDaemon), которое говорит моему приложению GUI отправлять уведомление боковой панели. У кого-нибудь есть простой пример, чтобы это объяснить? Все, что я видел на сайте Apple, трудно понять.

Я хочу создать сообщение AppleScript, например:

tell "My App" to notify with title "Title" subtitle "subtitle" text "some text"

в моем приложении CLI, а затем мое приложение GUI просыпается, получает его и обрабатывает его.

1 ответ

Решение

Это проще, чем я думал! Некоторые вещи на заметку:

  • Вы должны включить приложение Cocoa для получения событий AppleScript с двумя специальными параметрами в файле Info.plist: NSAppleScriptEnabled а также OSAScriptingDefinition,
  • Специальный XML-файл, называемый файлом sdef, отображает ваш синтаксис AppleScript непосредственно в класс Objective C для его обработки.
  • Класс должен быть подклассом NSScriptCommand и его метод performDefaultImplementation, из которого вы можете получить доступ [self directParameter] а также [self evaluatedArguments],
  • Поэтому, когда вы отправляете команду AppleScript, ваше приложение открывается автоматически (даже если оно закрыто) и не загружает несколько его экземпляров, что приятно. Затем, если синтаксис в AppleScript правильный, он отправляет его этому классу для обработки. Файл sdef указывает, какой класс.
  • Ваша команда также может отправить ответ обратно, если вы этого хотите. Или он может не делать этого.

1. Откройте проект приложения OSX Cocoa, для которого вы хотите получать события AppleScript.

2. Добавьте файл command.sdef со следующим содержимым:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
<dictionary xmlns:xi="http://www.w3.org/2003/XInclude">
    <!-- commented out next line because it has a bug ".sdef warning for argument 'FileType' of command 'save' in suite 'Standard Suite': 'saveable file format' is not a valid type name" -->
    <!-- <xi:include href="file:///System/Library/ScriptingDefinitions/CocoaStandard.sdef" xpointer="xpointer(/dictionary/suite)"/> -->
    <suite name="Acceptable Commands" code="SVrb" description="">
        <command name="notify user with title" code="SVrbDpCm" description="">
            <cocoa class="myCommand"/>
            <direct-parameter description="">
                <type type="text"/>
            </direct-parameter>
            <parameter name="subtitle" code="arg2" type="text" optional="yes"
                    description="">
                    <cocoa key="subtitle"/>
            </parameter>
            <parameter name="text" code="arg3" type="text" optional="yes"
                    description="">
                    <cocoa key="text"/>
            </parameter>
            <!-- uncomment below if you want to return a result string -->
            <!-- <result type="text" description=""/> -->
        </command>
    </suite>
</dictionary>

3. Добавьте файл myCommand.mm со следующим содержимым:

#import <Cocoa/Cocoa.h>

@interface myCommand : NSScriptCommand
@end

@implementation myCommand : NSScriptCommand

- (id)performDefaultImplementation {
    NSString *sResult = @"";
    NSString *sTitle = [self directParameter];
    NSDictionary *asArgs = [self evaluatedArguments];
    NSString *sSubTitle = [asArgs objectForKey:@"subtitle"];
    NSString *sText = [asArgs objectForKey:@"text"];
    sResult = [sResult stringByAppendingFormat:@"TITLE=%@ SUBTITLE=%@ TEXT=%@",sTitle,sSubTitle,sText];
    NSUserNotification *n = [[NSUserNotification alloc] init];
    n.title = sTitle;
    if (![sSubTitle isEqualToString:@""]) {
        n.subtitle = sSubTitle;
    }
    n.informativeText = sText;
    [NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:n];
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
    return sResult;
}

@end

4. Убедитесь, что AppKit.framework является связанным двоичным файлом, как вы обычно делаете.

5. Отредактируйте файл Info.plist и добавьте два параметра. (Обратите внимание, ниже приведены их исходные имена ключей.)

NSAppleScriptEnabled = YES
OSAScriptingDefinition = commands.sdef

6. Скомпилируйте ваш проект. Затем щелкните правой кнопкой мыши продукт в желтой папке "Продукты" в XCode и выберите "Показать в Finder".

7. Нажмите на значок приложения, которое вы видите в Finder, а затем нажмите левую клавишу опций вниз. Затем, удерживая нажатой клавишу Option, перейдите в меню "Правка" Finder и выберите "Копировать путь". Это помещает длинный путь к вашему приложению (перед его установкой в ​​/Applications) в буфер обмена.

8. Просто для проверки откройте окно терминала и введите его, заменив путь ниже на путь к вашему приложению Какао.

osascript -e 'tell app "/crazy/long/path/Example.app" to notify user with title "My Title" subtitle "my sub" text "my text"'

9. Вы должны увидеть, как ваше приложение открывается со значком док-станции, если оно еще не открыто, а затем в правом верхнем углу вы увидите уведомление, появившееся в уведомлениях на боковой панели. Он также будет иметь значок вашего приложения с графическим интерфейсом, если вы уже установили его вместе с ним. Обратите внимание, что если вы запускаете эту команду несколько раз, AppleScript умный и не загружает ваше приложение несколько раз. Также обратите внимание, что если вы щелкнете по уведомлению боковой панели, оно откроет экран вашего приложения (вместо того, чтобы отображать его только на панели).

Дальнейшая информация

• Вы можете пересмотреть код в шагах 2 и 3, чтобы выполнить другую команду и действовать по-другому.

• Вы можете изменить свой sdef (см. Закомментированную строку), чтобы вернуть результат обратно, если вы этого захотите. (Отлично подходит для отладки!)

• Ваш файл sdef может иметь отдельные команды, идущие в разные классы. Посмотрите пример Apple, чтобы узнать, как это сделать.

• Файл sdef имеет какой-то странный синтаксис, такой как параметр "code". Более подробная информация доступна здесь.

• Это соединение AppleScript чрезвычайно полезно, если у вас есть приложение, которое работает в сочетании с LaunchDaemon, но LaunchDaemon должен отправить уведомление на боковой панели. Конечно, есть код, чтобы это произошло, и есть хитрость даже для того, чтобы значок LaunchDaemon отображал значок вашего приложения вместо значка терминала, но единственное, чего он не может сделать, это сделать его таким, чтобы при нажатии на эту боковую панель уведомлял его открывает приложение с графическим интерфейсом. Вместо этого, когда кто-то щелкает по этому уведомлению на боковой панели, он открывает LaunchDaemon, что является нежелательным результатом. Таким образом, вместо этого вы можете использовать эту технику AppleScript, чтобы ваш LaunchDaemon проснулся и уведомил своего компаньона с графическим интерфейсом приложения об отправке уведомления. Таким образом, если щелкнуть уведомление на боковой панели, откроется приложение с графическим интерфейсом, а не LaunchDaemon.

• Тривиально заставить другое приложение отправить AppleScript:

NSString *sScript = @"tell app \"/Applications/Calculator.app\" to activate";
NSAppleScript *oScript = [[NSAppleScript alloc] initWithSource:sScript];
NSDictionary *errorDict; 
NSAppleEventDescriptor *result = [oScript executeAndReturnError:&errorDict];
Другие вопросы по тегам