Bezdepbonusu7Программирование: статьи и ответы

Вопрос

ScriptingBridge - как это работает за кулисами

Автор вопроса: Sean DeNigrisОтветов: 1

Контекст: я работаю над мостом Pharo / Smalltalk -> Objective-C

Сценарий: в следующем фрагменте Objective-C ScriptingBridge:

iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];

iTunesTrack *currentTrack = iTunes.currentTrack; //[1]
// This low level way works too
//iTunesTrack *currentTrack = [iTunes propertyWithCode: 'pTrk']; //[2]

[iTunes playpause]; //[3]

Проблема: мост использует class_getInstanceMethod, чтобы определить, понимает ли объект сообщение / селектор, но он возвращает NULL для сообщений сценария, таких как playpause

Вопрос № 1 Почему class_getInstanceMethod возвращает NULL для скриптовых сообщений типа playpause? Тот же вопрос для class_copyMethodList? Что особенного в сообщениях сценариев, что они не действуют как другие сообщения Obj-C (кроме случаев, когда они действуют!)?

Вопрос № 2 [РЕШЕН - см. ответ @ Мэтта]

Где, согласно документам, в "динамически определяемом подклассе для приложение iTunes "размещает ли SB" специфичные для приложения методы, которые автоматически обрабатывают отправку событий Apple "? И, учитывая, что class_getInstanceMethod не может найти такое поведение (см. Ниже), какой надежный способ для моста проверить это (т.е. существует ли такой метод / сообщение)?

Objective-C Runtime API сообщает о смешанных результатах. С одной стороны, у класса iTunesApplication, похоже, нет никаких методов (или свойств, если на то пошло):

  • class_copyMethodList([iTunes class]... возвращает нулевые методы
  • class_getInstanceMethod, который мост использует для поиска и выполнения методов, не работает.

С другой стороны, #playpause можно запросить и отправить через другие части API:

  • respondsToSelector: -> ИСТИНА
  • methodSignatureForSelector: возвращает подпись
  • и performSelector: фактически отправляет сообщение

Как ни странно, methodForSelector:@"playpause" успешно возвращает IMP в Obj-C, но вылетает, если отправлено с другой стороны моста.

Вопрос №3 [решен]

Как можно смоделировать / воспроизвести [3]?

Ответил @Willeke в комментариях: [iTunes sendEvent:'hook' id:'PlPs' parameters:0]

  • Я не уверен, что понимаю вопрос. Низкоуровневый путь [iTunes playpause] - [iTunes sendEvent:'hook' id:'PlPs' parameters:0]. [iTunes propertyWithCode: 'pTrk'] возвращает SBObject*, [iTunes propertyWithClass:[self.iTunes classForScriptingClass:@"track"] code:'pTrk'] возвращает iTunesTrack*. Willeke 26.05.2020
  • @Willeke, это уже полезно, если я не могу найти ответ. Мой вопрос сводится к следующему: как мне получить доступ, например, метод currentTrack динамически определяемого подкласса для приложения iTunes с другой стороны моста, если API отражения времени выполнения Obj-C не может видеть этот метод? Где SB скрывает эти динамически реализуемые методы / свойства? Я бы предпочел как-нибудь вызвать playpause из Smalltalk, чем заново реализовывать его кодом, подобным тому, который вы предоставили Sean DeNigris 27.05.2020
  • Специфичные для приложения методы относятся к терминам сценариев, которые используются в вашем приложении. Эти термины - это не те методы, которые вы ищете, это команды (через Apple Events), на которые приложение реагирует. Вы можете попробовать скомпилировать / запустить скрипт и выявить ошибку (синтаксическую или другую) или посмотреть словарь скриптов приложения (хотя это все равно не скажет, правильно ли используется термин). red_menace 29.05.2020
  • @red_menace Вы говорите, что реальных методов не существует, но что SBApplication стимулирует методы, динамически перехватывая `responsedsToSelector:` и друзей и конвертируя отправленные сообщения в отправленные Apple Event? Sean DeNigris 30.05.2020
  • Почему бы не изучить альтернативный мост с открытым исходным кодом, чтобы увидеть, как это работает? Посмотрите appscript и т. Д. Внимание, вот драконы. Если бы это было легко, это сделали бы другие. matt 30.05.2020
  • Очевидно, что существуют методы для реализации различных событий Apple, но было бы просто совпадением, если бы существовал метод с тем же именем, что и термин сценария. Нет однозначного соответствия терминологии и методов сценариев приложения в целевом приложении, но вы все равно не можете просто вызвать какой-либо случайный метод в другом приложении - см. Руководство по созданию сценариев какао для получения дополнительной информации. . red_menace 30.05.2020

objective-csmalltalkscripting-bridgeobjective-c-runtimepharo

Ответы

Ответ 1 · рейтинг 4 · matt

Если SB не использует сообщения Objective-C, что означают документы, говоря "подклассы SBApplication реализуют специфичные для приложения методы, которые автоматически обрабатывают отправку событий Apple"? Почему iTunes RespondsToSelector: @ "playpause" работает, т.е. возвращает истину? А как работает [iTunes playpause]? И т. Д. И т. Д.

Это работает, потому что самое первое, что вы делаете в приложении-мосте сценариев, - это генерируете заголовок. В Catalina это делается так:

sdp -f h --basename iTunes /System/Applications/Music.app/Contents/Resources/com.apple.Music.sdef

Это читает словарь iTunes (sdef) и генерирует заголовок для группы аналогичных классов Objective-C. Теперь у вас есть файл iTunes.h, который вы включаете в проект приложения и импортируете в свой код. Он содержит эту строку:

- (void) playpause;  // toggle the playing/paused state of the current track

Итак, теперь playpause явно объявлен как допустимая команда, которую вы можете отправить объекту iTunesApplication. Затем, когда вы действительно запускаете свое приложение, вы говорите

iTunesApplication* tunes = (iTunesApplication*)[SBApplication applicationWithBundleIdentifier:@"com.apple.music"];

Это заставляет ваше приложение взаимодействовать с iTunes (Музыка) и получать словарь (sdef) снова, генерируя реализацию для методов, объявленных в заголовке. Реализация команды playpause в точности совпадает с утверждением sdef, а именно: для отправки события hookPlPs в iTunes.

Это объясняет как то, почему вам разрешено сказать playpause, так и то, что происходит, когда вы это говорите.

Это то, чем является AppleScript - это приложение, предоставляющее список вещей, которые вы можете сказать ему, используя события Apple, вместе с англоязычными терминами, которые ссылаются на эти события Apple.

Поэтому, если вы хотите написать мост, вы должны сделать то же самое: вам нужно предоставить способ просмотреть sdef ресурс целевого приложения и преобразовать эту информацию в способ для соответствующих команд быть дано на вашем языке, каким бы он ни был.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы