Itty Bitty Labs

Code and technical stuff from Itty Bitty Apps.

AppleScript and Reveal

Recently we released version 1.0.4 of Reveal. At the same time JetBrains released version 3.0 of their Objective-C IDE AppCode. One of the new features in AppCode 3.0 was a plugin that provides integration between Reveal and AppCode. This plugin makes it very easy to get Reveal running with your project and inspecting your iOS app.

But how does this integration work? Well, JetBrains have a blog post describing how to use the bundled plugin and the java source code to the plugin is on github.

If you read the source you might notice that it makes use of a little AppleScript.

Besides bugfixes the only major change in version 1.0.4 of Reveal was the introduction of support for AppleScript. We did this specifically to make the integration with AppCode easier.

But it is not just AppCode that can take advantage of this new AppleScript API.
Xcode users can too. Let me explain…

Getting Reveal’s library to start automatically.

I’ve previously written posts on how you can dynamically inject Reveal’s dylib into your app using dlopen in LLDB. Another technique, the one employed by AppCode, is to use the dynamic linker’s (dyld) environment variables. Specifically the DYLD_INSERT_LIBRARIES variable.

With Xcode the easiest way to use this technique is to modify or create a scheme in your workspace so that the DYLD_INSERT_LIBRARIES environment variable is set to /Applications/Reveal.app/Contents/SharedSupport/iOS-Libraries/libReveal.dylib.

You will have to tweak this path if you’ve not installed Reveal into your system’s root Applications folder.

The image above shows how to set and enable this environment variable. With this environment variable set the libReveal.dylib will be loaded automatically by the dynamic linker every time your app is run in Xcode. Note that this will only work in the iOS Simulator. You will get a crash if this environment variable is enabled when running on an actual iOS device.

Refreshing Reveal automatically when running your iOS application.

The next thing we need to do is get Reveal to automatically connect to your iOS application when it starts. This can be accomplished using a pre-run script action in your scheme.

In the Xcode scheme editor editor expand “Run” and select “Pre-actions”. Add a new “Run Script” action and enter the following script:

Run Pre-action Script
1
2
3
4
5
6
7
8
9
10
(echo "
  tell application \"/Applications/Reveal.app\"
    activate
    delay 4
    repeat with doc in documents
      refresh doc when available application name \"${PRODUCT_NAME}\"
    end repeat
    activate
  end tell" | osascript) &

Note that the trailing ampersand is important! It causes the script to be run in a background sub-shell and avoids delaying your application from starting.

Also ensure that you select your application’s target from the “Provide build settings from” popup button, otherwise the ${PRODUCT_NAME} variable will not be expanded correctly in the script.

Here is a screen shot of these settings:

Note also that there is a delay of 4 seconds in this script. This is there to give the iOS simulator enough time to start up. You may need to tweak this depending on how fast your Mac can start up the simulator. The Simulator also seems to take longer the first time it is launched. Reveal will time out after receiving the “refresh” command if it can’t find your application within 10 seconds.

Here is a video showing this in action:

Refreshing Using a Breakpoint

Another use for the AppleScript support is refreshing Reveal in response to hitting an Xcode break point. This assumes that Reveal is running and connected to your app already (perhaps by using the technique outlined above).

Add a breakpoint at a key point in your application. The method -viewDidAppear: on a UIViewController is a good choice. Edit the break point to add an AppleScript action. The AppleScript should be as follows:

Refresh Reveal
1
2
3
4
5
tell application "Reveal"
  refresh document 1
  activate
end tell

NB: Ensure that the breakpoint automatically continues after evaluation otherwise Reveal will not be able to take a snapshot. Also, if you don’t want Reveal to come to the foreground when the breakpoint is hit, remove the “activate” statement from the AppleScript.

So there you go. A few more gadgets for your iOS view debugging toolbelt. We’re hoping to further expand Reveal’s support for AppleScript in future releases. Let us know if you have any ideas or suggestions on what additional scripting functions we should add.


About Oliver

Oliver Jones is the Technical Director at Itty Bitty Apps. He spends his days building the iOS Introspection tool Reveal and playing Pinball. You can follow him on twitter @orj.