【问题标题】:Objective-C Scripting Bridge and Apple Remote DesktopObjective-C 脚本桥和 Apple 远程桌面
【发布时间】:2014-09-22 23:24:26
【问题描述】:

尝试通过 Objective-C 中的 Scripting Bridge 自动查看 Apple Remote Desktop 中的计算机:


    @try {
        SBApplication *RD = [SBApplication applicationWithBundleIdentifier:@"com.apple.RemoteDesktop"];

        // (code to check for ARD running and installed omitted here)
        [RD activate]; // works just fine

        RemoteDesktopComputer *computer = [[[RD classForScriptingClass:@"computer"] alloc]     initWithProperties:
            [NSDictionary dictionaryWithObjectsAndKeys:
                ipAddress,@"InternetAddress", // looked up from header
                nil
             ]
        ];

        // attempt to add it to a container first:
        [(SBElementArray*)[(RemoteDesktopApplication*)RD computers] addObject:computer]; 
        // this is what raises the exception:
        [computer observeZooming:Nil];
    }
    @catch (NSException *e) {
        NSLog(@"Exception: %@", [e description]);
    }

运行它会在日志中产生以下异常:

    Exception: *** -[SBProxyByClass observeZooming:]: object has not been added to a container yet; selector not recognized [self = 0x6050004819b3]

我已经对这个主题进行了尽可能多的研究,并且了解到 SB 并不是最容易处理的,因为它是如何连接到引擎盖下的,但是任何本地 Scripting Bridge 的专家或资深人士(不请使用 obj-c 以外的第三方框架或语言)非常感谢。

执行所有先决条件,例如链接到 ScriptingBridge.framework 和导入 Remote Desktop.h - 类型转换是为了避免在构建时似乎不可避免的链接时错误...

编辑 1: 阅读有关 SBObject(RemoteDesktopComputer 的父级)的文档说它是一个引用而不是实际实例,您可以通过调用 SBObject 的 get 方法(返回 id)来获取它。所以我也尝试运行它,但不幸的是得到了相同的结果:

    [[computer get] observeZooming:Nil];

这是关于 SBObject 的文档:https://developer.apple.com/library/mac/documentation/cocoa/Reference/SBObject_Class/SBObject/SBObject.html#//apple_ref/occ/instm/SBObject/get

还在尝试中……

【问题讨论】:

  • 你能检查哪个函数抛出异常,例如通过使用异常断点?
  • Stepping into observeZooming: 只是简单地抛出异常,就像它不使用断点一样,确认 observeZooming: 确实是触发异常的方法,但没有提供任何关于原因的见解。查看我的编辑 - 尝试使用和不使用“get”选择器来取消引用对象并每次都得到相同的结果
  • 我没用过Scripting Bridge,所以可能想不出办法,但是[RD computers]的返回值是非nil吗?
  • 我用 NSLog 输出运行了一些测试代码来检查它确实不是 Nil...但是,这可能是因为正在进行一些取消引用抽象 - 请查看以下详细说明:stackoverflow.com/questions/1309958/…

标签: objective-c cocoa applescript scripting-bridge


【解决方案1】:

(FWIW,我已经编写了以下操作方法,因此我将其留在这里以供将来参考。)


如何使用 AppleScript-ObjC 代替 Scripting Bridge

Scripting Bridge 充其量是一个 80/20/80 的“解决方案”(即 80% 的时间它工作,20% 的时间它失败,而 80% 的时间你不知道为什么) .当 SB 打破在 AppleScript 中运行良好的东西时,试图与 SB 争论没有什么意义——负责的 Apple 工程师故意这样设计它,并拒绝接受他们违反规范 [1] 并搞砸了。因此,尽管 AppleScript 语言存在所有其他缺陷,但它仍然是唯一支持的解决方案,可以保证正确说出 Apple 事件 [2]。

幸运的是,从 OS X 10.6 开始,还有另一个选项可用:将 ObjC 用于所有常规编程内容,并且仅通过 AppleScript-ObjC 桥接器调用 AppleScript 以获取 IPC 内容。

从您的 ObjC 代码的 POV 来看,您基于 AppleScript 的 ASOC“类”或多或少与常规的 ObjC 类没有区别。设置它需要一些摆弄,过桥时你会付出一些代价,但考虑到替代方案的残缺、不可靠的性质,对于任何不平凡的事情来说,它都是受支持的选项中最不可怕的。

假设您已经有了一个现有的基于 ObjC 的项目,以下是如何向其中添加基于 ASOC 的类:

  1. 在 Targets > APPNAME > Build Phases > Link Binary With Libraries 中,添加 AppleScriptObjC.framework

  2. 在 Supporting Files > main.m,添加导入和加载行,如下所示:

    #import <Cocoa/Cocoa.h>
    #import <AppleScriptObjC/AppleScriptObjC.h>
    
    int main(int argc, const char * argv[]) {
       [[NSBundle mainBundle] loadAppleScriptObjectiveCScripts];
       return NSApplicationMain(argc, argv);
    }
    
  3. 要定义一个可从 ObjC 调用的名为 MyStuff 的基于 ASOC 的类,请创建一个声明其公共方法的 MyStuff.h 接口文件:

    // MyStuff.h
    
    #import <Cocoa/Cocoa.h>
    
    @interface MyStuff : NSObject
    
    // (note: C primitives are only automatically bridged when calling from AS into ObjC;
    // AS-based methods with boolean/integer/real parameters or results use NSNumber*)
    
    -(NSNumber *)square:(NSNumber *)aNumber;
    
    @end
    

    连同一个包含其实现的MyStuff.applescript 文件:

    -- MyStuff.applescript
    
    script MyStuff
    
       property parent : class "NSObject"
    
       on square_(aNumber)
           return aNumber ^ 2
       end square_
    
    end script
    
  4. 因为MyStuff 类没有 ObjC 实现,所以链接器无法在构建时将您的 ObjC 代码链接到它。相反,使用NSClassFromString() 在运行时查找类对象:

    #import "MyClass.h"
    
    ...
    
    MyStuff *stuff = [[NSClassFromString(@"MyStuff") alloc] init];
    

    否则它与正常使用的原生 ObjC 类几乎没有区别:

    NSNumber *result = [stuff square: @3];
    NSLog(@"Result: %@", result);
    

HTH

--

[1] Apple 管理层在最初发布后不久就解散了最初的 AppleScript 团队,导致其设计人员作为回应退出,因此很多关于这些东西应该如何工作的知识都丢失了。特别是,在设计脚本支持时,从来没有为应用程序开发人员制定完整的正式规范,因此他们所能做的就是使用个人判断和最佳猜测,然后针对 AppleScript 进行测试以检查它是否按预期工作。因此,AppleScript 自己的 Apple 事件桥是事实上的规范,在过去的 20 年中,每个可编写脚本的应用程序都针对它实施,因此其他 AE 桥能够正常工作的唯一方法是模仿它们AS 自己的每一个查询和怪癖的桥梁 - 不幸的是,当前的 AS 团队反复未能理解 [2]。

[2] 顺便说一句,支持自动化的 Apple 事件的 JavaScript 同样糟糕透顶。

【讨论】:

  • 非常有用,谢谢!希望这对其他人有帮助。
【解决方案2】:

Scripting Bridge 是一个有缺陷的混乱混乱,因此当应用程序命令无法工作时,您不知道问题是 SB 有缺陷还是应用程序本身有错误,或者只是要求您以不同的方式表达它。

因此,第一步是在 AS 中编写一个测试脚本,看看它在那里工作。如果是这样,那就是SB,那是废话;如果没有,请尝试修改您的 AS 代码(例如,尝试以不同的方式解释 at 参数的引用,或完全省略它)直到它完成为止。

您还应该询问 Apple 的 AppleScript 用户和 ARD 邮件列表以及 ARD 脚本编写者可能会出没的其他任何地方,因为大多数应用程序的脚本文档都严重不足,因此有关如何做事的大量知识是众所周知的嘴。 (您真正想与之交谈的人是 John C Welch,又名 @bynkii,因为他是 ARD 脚本的大师。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多