Ошибка принудительной развертки с помощью Scripting Bridge с Chrome

Я пытаюсь использовать Apple Scripting Bridge для взаимодействия с Google Chrome. Я начал с кода в https://stackoverflow.com/a/24147285.

Я создал файл .h с помощью команд sdef и sdp.

Я включил файл, а также создал заголовок моста и импортировал файл заголовка хрома в заголовок моста. Но проблема в использовании заголовка в Swift. Код старый, а Swift сильно изменился.

Мой файл Swift:

import Cocoa
import ScriptingBridge


var chromeObject = SBApplication.init(bundleIdentifier: "com.google.Chrome")! as AnyObject

print(chromeObject.closeable)

я получаю сообщение об ошибке

фатальная ошибка: неожиданно найдено nil при развертывании необязательного значения

Что я делаю неправильно?


person ssh    schedule 05.03.2017    source источник
comment
Хром установлен?   -  person jscs    schedule 06.03.2017
comment
@JoshCaswell Да   -  person ssh    schedule 06.03.2017
comment
@JoshCaswell Единственная работающая команда - chromeObject.activate()   -  person ssh    schedule 06.03.2017
comment
@psh Дело в том, что с использованием ScriptingBridge документация не очень выразительна. Так вот почему вы не получаете. Вы уверены, что хотите продолжить использовать ScriptingBridge вместо прямого использования AppleScript? Это будет легко, как только вы поймете, как это работает, но станет утомительно, если вы работаете с iTunes.sdef, у которого так много интерфейсов.   -  person SkrewEverything    schedule 06.03.2017
comment
@SkrewEverything Не знаю почему, но мне совсем не удобно работать с AppleScript. Я просто хочу сделать это в Swift. Пожалуйста помогите!   -  person ssh    schedule 06.03.2017
comment
Настоятельно рекомендуется использовать AppleScriptObjC. Это делает вещи намного проще.   -  person vadian    schedule 06.03.2017
comment
@vadian Я не знаю obj-c и не нашел учебника. Вот почему я использую ScriptingBridge. Объяснение, данное @SkrewEverything, решило мою проблему.   -  person ssh    schedule 06.03.2017


Ответы (2)


SBApplication возвращает объект приложения. Вы можете увидеть разные interface в файле .h.

@interface ChromeApplication : SBApplication
@interface ChromeWindow : SBObject <ChromeGenericMethods>
@interface ChromeApplication (ChromiumSuite)
@interface ChromeTab : SBObject <ChromeGenericMethods>
@interface ChromeBookmarkFolder : SBObject <ChromeGenericMethods>
@interface ChromeBookmarkItem : SBObject <ChromeGenericMethods>

Итак, SBApplication возвращает вам ChromeApplication. Вы можете вызывать любые свойства, определенные внутри ChromeApplication. Попробуй сам. Вы не получите никакой ошибки.

Проблема в том, что вы звоните closeable, который является частью ChromeWindow.

Из Документация Apple:

AppleScript и объекты

AppleScript — это объектно-ориентированный язык. Когда вы пишете, компилируете и выполняете сценарии, все, с чем вы работаете, является объектом. Объект — это экземпляр определения класса, который может включать в себя свойства и действия. AppleScript определяет классы для объектов, с которыми вы чаще всего работаете, начиная с объекта сценария верхнего уровня, который является общим сценарием, с которым вы работаете.

..............

.....................

и главное,

Что находится в объекте скрипта

Когда вы вводите операторы AppleScript в окно сценария в редакторе сценариев, вы работаете с объектом сценария верхнего уровня. Все определения объекта скрипта следуют одному и тому же синтаксису, за исключением того, что объект скрипта верхнего уровня не имеет операторов, обозначающих его начало и конец.

Объект сценария может содержать следующее:

Определения свойств (необязательно): свойство — это помеченный контейнер, в котором хранится значение.

Явный обработчик выполнения (необязательно): обработчик выполнения содержит операторы, которые AppleScript выполняет при запуске сценария. (Дополнительную информацию см. в разделе обработчики запуска.)

Неявный обработчик запуска (необязательно): неявный обработчик запуска состоит из любых инструкций за пределами каких-либо содержащихся обработчиков или объектов сценария.

Дополнительные обработчики (необязательно): обработчик является эквивалентом подпрограммы. (Подробности см. в разделе Об обработчиках.)

Дополнительные объекты скрипта (необязательно): объект скрипта может содержать вложенные объекты скрипта, каждый из которых определяется так же, как объект скрипта верхнего уровня, за исключением того, что вложенный объект скрипта заключен в квадратные скобки операторами, которые отмечают его начало. и конец. (Подробнее см. в разделе Объекты сценария.)

Итак, простыми словами, Application — это объект, который содержит Window, который является объектом, который содержит Tab объект.....

Вам нужно получить Window объект/элемент из Application, чтобы использовать closeable.

У вас должно быть SBElementArray в каждом interface. Вы должны получить это.

Пример,

// The application's top-level scripting object.
@interface ChromeApplication : SBApplication

- (SBElementArray<ChromeWindow *> *) windows;

@property (copy, readonly) NSString *name;  // The name of the application.
@property (readonly) BOOL frontmost;  // Is this the frontmost (active) application?
@property (copy, readonly) NSString *version;  // The version of the application.

- (void) open:(NSArray<NSURL *> *)x;  // Open a document.
- (void) quit;  // Quit the application.
- (BOOL) exists:(id)x;  // Verify if an object exists.

@end

Вы должны получить - (SBElementArray<ChromeWindow *> *) windows;, чтобы использовать closable. Опять же, в окнах у вас есть массив вкладок и т.д.

Например, в AppleScript, чтобы получить URL и заголовок каждой вкладки:

tell application "Google Chrome"

    set a to ""
    repeat with w in windows
        repeat with t in tab in w  // Getting tab object from window
            set a to a & linefeed & title of t & " -URL: " & URL of t
        end repeat
    end repeat

end tell

Эквивалентом в Swift будет:

import Cocoa
import ScriptingBridge


var chromeObject: AnyObject = SBApplication.init(bundleIdentifier: "com.google.Chrome")!

var f = chromeObject.windows() // get the windows from application
for i in f!
{
    var t = (i as AnyObject).tabs() // get the tabs from windows
    for j in t!
    {
        print(((j as AnyObject).title as String) + " -URL: " + ((j as AnyObject).url as String))
    }
}

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

person SkrewEverything    schedule 06.03.2017
comment
Документация Apple, которую вы цитируете, описывает, как работает язык AppleScript. AS определяет ряд стандартных встроенных типов данных (строки, списки и т. д.) и поддерживает своего рода ООП на основе прототипов через объекты сценария. В то время как его мост событий Apple работает совершенно по-другому: автоматизация приложений — это не ООП, это RPC плюс простые первоклассные реляционные запросы. (ASLG более чем бесполезен для объяснения этого; документ AppleScript намного лучше. SB тоже делает из этого немало, поэтому советуем придерживаться AS, если можете.) - person foo; 07.03.2017

Из документации для SBApplication.init?(bundleIdentifier:):

Возвращаемое значение

Инициализированный общий экземпляр подкласса SBApplication, который представляет целевое приложение с идентификатором пакета ident. Возвращает nil, если такое приложение не может быть найдено или если приложение не имеет интерфейса сценариев.

Вы должны убедиться, что метод init возвращает экземпляр перед принудительной распаковкой, например:

if let chromeObject = SBApplication.init(bundleIdentifier: "com.google.Chrome") as? AnyObject {
    print(chromeObject.closeable)
}
person Dave Weston    schedule 05.03.2017
comment
На самом деле проблема в chromeObject.closeable. Он всегда возвращает nil. Но когда я пытаюсь в Obj-c, он работает нормально с некоторыми предупреждениями. - person ssh; 06.03.2017
comment
Когда вы печатаете, вы получаете эту ошибку? Если у вас есть работающий код на Objective C, почему бы вам его не опубликовать? И, может быть, мы можем помочь вам перевести его на Swift? - person Dave Weston; 06.03.2017
comment
Спасибо за попытку помочь. @SkrewEverything решил мою проблему. - person ssh; 06.03.2017