Applescript Inside of a Cocoa Application - objective-c

For the application I am writing, I need to access some other applications' items, for which Applescript seems the best way to go. I have been using the Appscript framework, which worked well, because it allowed me to thread it and not make my app lock up when an Applescript was taking a while. However, now I am attempting to make my application 64 bit compatible, and it seems like the Appscript framework does not support 64 bit. Is there a "good" way to use Applescript in Cocoa that will not lock up my application, but still give me the full control I need?
--firen

It seems like SBApplication should work, but I haven't used it before.
According to #cocoadevcentral:
SBApplication: use to make cross-application scripting calls with Objective-C instead of AppleScript. Ex: get current iTunes track.
Here is is the excerpt from the documentation:
The SBApplication class provides a mechanism enabling an Objective-C program to send Apple events to a scriptable application and receive Apple events in response. It thereby makes it possible for that program to control the application and exchange data with it. Scripting Bridge works by bridging data types between Apple event descriptors and Cocoa objects.
Although SBApplication includes methods that manually send and process Apple events, you should never have to call these methods directly. Instead, subclasses of SBApplication implement application-specific methods that handle the sending of Apple events automatically.
For example, if you wanted to get the current iTunes track, you can simply use the currentTrack method of the dynamically defined subclass for the iTunes application—which handles the details of sending the Apple event for you—rather than figuring out the more complicated, low-level alternative:
[iTunes propertyWithCode:'pTrk'];
If you do need to send Apple events manually, consider using the NSAppleEventDescriptor class.
Hope that helps!

As Blaenk mentioned Scripting Bridge may well be the way to go, although it can prove somewhat inefficient if you have to iterating through large arrays etc.
The simplest way to run an Applescript in Cocoa is using NSAppleScript.
Apple has some pretty good examples, which I found useful when I needed to do something similar. There are three articles you might want to take a look at. They all contain some sample code, which I always find very useful.
A Few Examples of using Scripting Bridge
Performance & Optimisation with Scripting Bridge
NSAppleScript Technote/Example
I created a gist with the full URLs as I can't post more than one link, what with being a newbie and all.
http://gist.github.com/130146

it seems like the Appscript framework does not support 64 bit.
Should work. Make sure you set the correct architectures and SDK (64-bit requires 10.5) in the Xcode project. File a bug report if you have a specific problem.

Related

Bonjour communication wrapper for Objective-C?

I've been using MYNetwork by the venerable Jens Alfke for an app of mine that allows devices to connect and share info over the network, it's actually a mission-critical part of the app. I tried writing my own wrapper for all of the C-level stuff you have to do for Bonjour, but it didn't work out so well, so I moved to MYNetwork.
It's been great so far, but the fact it's essentially opaque to me is causing trouble, as is that I want to move over to ARC once we can submit apps with it (there's a lot of Objective-C object references in structs, which ARC hates).
Can anyone recommend a similar wrapper, ideally that allows easy message passing between a client and a server over Bonjour as well as service discovery?
Just a thought- Would using ZeroMQ advertised and discovered by the stock NSNetService suffice? Separating the service pub/sub from the actual communication would allow you to use other bonjour libraries like Avahi on linux too. ZeroMQ is sufficiently simple to make wrapping trivial, yet powerful enough to cope with complex network topologies, fast.
I have experience with both technologies in isolation but not together although I see no reason why it wouldn't work. The only caveat right now is the limited body of collective experience of ZeroMQ use on iOS but I'd expect that to change over time.
You know you can disable ARC for specific files? So, you can just disable ARC for the library, and keep it on for your other files.
Disable Automatic Reference Counting for Some Files

Manage files on iDevices

Does anyone know how programs like iPhoneExplorer manage to list/add/remove files on an iDevice?
I would like to do something similar (but more basic) in a Cocoa Touch application.
It's technically not an Apple-approved™ method, so don't plan on putting this in the App Store. But it is possible. First, import the MobileDevice framework from /System/Library/PrivateFrameworks. Then use the reverse-engineered header for the MobileDevice framework:
http://code.google.com/p/ziphone/source/browse/trunk/ZiPhone/MobileDevice.h
It includes all the methods necessary to communicate with an attached iOS device.
There's also a C++ wrapper for it that's a bit easier to use, especially for detecting the device in the first place. It also includes methods specifically for jailbreaking, but they're not required.
http://code.google.com/p/independence/source/browse/trunk/libPhoneInteraction/PhoneInteraction.cpp?r=323

Submitting an app to the App Store that uses BWToolkit

I'm currently using BWToolkit, does anyone know if there are any steps that need to be taken before submitting to the app store (as far as licensing)? Do I need to put any disclaimers anywhere etc? I know it's BSD licensed but I don't want to have my app rejected because I missed a simple legal step.. Any help?
I don't think that NSGod is right.
You may want to read this and/or that.
You are not going to like this answer.
You will not be able to use the BWToolkit.framework as-is. Some of its classes rely on private APIs which Apple has strictly forbidden for apps that are submitted to the app store.
For example, the developer ran a tool called class-dump on the AppKit.framework Mach-O object and generated the .h files for 4 secret classes: NSTokenAttachment (an NSTextAttachment subclass), NSTokenAttachmentCell (an NSTextAttachmentCell subclass), NSWindow (NSTimeMachineSupport), some additional methods on NSWindow, and NSCustomView.
I'm not that familiar with the inner workings of the framework, but depending on what classes you've made use of, it may be possible to create a custom build of the framework from the source that doesn't include the private APIs. Or, you could just include the source files for the classes you use in your project (provided of course that they don't rely on private APIs).
What particular classes did you make use of? If you used BWSplitView, you might look into using RBSplitView. (I talked to Rainer and have confirmed that there's no private APIs used in it, so you'd be okay).

How is it possible to access function of app A from app B

I was wondering if and in how many way an app can access specific funcions of another app.
for example
open an url in safari/firefox/chrome
run a javascript in current browser-tab
play/pause itunes
rename selected files in Finder
I am aware of the existence of applescript but i was wondering if that's the only way i have to interact with those apps and others
thanks
There are three main ways an app exposes its function to the outside world.
One is by supporting an URL protocol. To open an URL, just use NSWorkspace. There are many methods; if an app registers a specific protocol like x-my-app://some-work, you can just do
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:#"x-my-app://some-work"] ];
If you want to open an URL whose protocol (say http) is supported by many apps and if you want to specify which app to use, use openURLs:withAppBundleIdentifier:options:additionalEventParamDescriptor:launchIdentifiers:
.
Another is the System Services. With this, an app can add entries in the Service menu and in the context menu of other apps; you can also call it programmatically.
Otherwise, it's via Apple events. Applescript is one way to deal with them, but not the only one. It's just a language to issue Apple events. There are many ways to deal with Apple events from Cocoa, see this detailed document by Apple.
Basically, an app can export its internal as an object-oriented manner (which is not just its Objective-C hierarchy; you can control how much of its internal objects and methods you expose, etc.) by an sdef file. Then, another app can use this object-oriented system via Apple events.
To send and receive Apple events, you can of course construct them by hand, but you can use higher-level objects like
Applescript via NSAppleScript
Scripting Bridge
or AppScript.
To learn what kind of aspects an app exposes, just open the AppleScript Editor and choose the menu File → Open Dictionary, and choose an app.
Now, it's rather hard to use features of an app which the app does not expose via any of these methods. You still have a few workaround.
UI Scripting. This is done by sending Apple Events to a headless app called System Events which is one of the core program in OS X. This way, you can programmatically emulate clicking a button, choosing a menu, etc. of another app. So, almost whatever you can do using GUI with another app can be done programmatically from another app. To see the hierarchy of UI objects accessible from UI scripting, use a utility which comes with XCode tools, at
/Developer/Applications/Utilites/Accessibility Tools/Accessibility Inspector.app
This is very rudimentary but does the job; if you regularly use UI scripting, consider obtaining UI browser, as Zygmunt suggests.
Finally, if you want to use a non-GUI non-exposed feature of another app, you can inject a code into another app.
Just expanding on Yuji's answer. If you were forced to go the UI scripting path, there's a nice application to analyze the interface - hxxp://pfiddlesoft.com/uibrowser/. However, the examples you mentioned should expose some APIs.
I might also recommend using Sikuli hxxp://groups.csail.mit.edu/uid/sikuli/ as an IDE to script around user interface robustly.
For some applications usually coming from GNU/Linux there is D-BUS hxxp://en.wikipedia.org/wiki/D-Bus - although I haven't used it on a Mac on my own yet. And let me also quote Wikipedia about Cocoa "It is one of five major APIs available for Mac OS X; the others are Carbon, POSIX (for the BSD environment), X11 and Java." hxxp://en.wikipedia.org/wiki/Cocoa_%28API%29 That's just a loose tip for further exploration as Yuji has already explained Apple events that are key to your question.

sample mac Firefox Plugins?

I'm trying to re-write an old image-viewing plugin for the mac. The old version uses QuickDraw (I said it was old) and resources (really really old) and so it doesn't work in Firefox 3.6 (which is why I'm re-writing it)
I know some Objective C, and so I figure I'm going co re-write this in that using new-fangled Mac routines and nibs, etc. However, I don't know how to start. I've got the BasicPlugin example that comes with mozilla source, so I know how to create a plugin with entrypoints, etc. However, I don't know how to create the nib, and how to interface Obj-C with the entrypoints, etc.
Does anyone know of a more advanced sample for mac than BasicPlugin.bundle? (Preferably simple enough that I can just look at it and understand it...)
thanks.
Sadly i don't really know of any good "intermediate" example. However, integrating Obj-C isn't that difficult. Thus, following is a short overview of what needs to be done.
You can use Obj-C and C/C++-sources in the same project, its just recommendable to keep them seperated to some extent. This can for example be done by letting the source file with the entry-points and other NPAPI-interfacing stay plain C or C++ files and e.g. forward calls into the plugin from there.
Opaque pointers help to keep a clean seperation, see e.g. here.
The main changes to your plugin include switching to different drawing and event models. These have to be negotiated in NPP_New(), here is an example for the drawing model. When using Cocoa and to support 64bit enviroments, you need to use the Cocoa event model.
To draw UI elements you should be able to use a NSGraphicsContext from the CGContextRef and then draw an NSView in the context. See also the details provided in this post and its follow-ups.