Applescript opens wrong version

Starting today, my script is opening an old version of an app. I have searched my HD and I can’t find the old vers. The correct version of the app is in the Applications folder. App2 is the problem child.

How can I point the script at the correct app without using a path?
Where/why could the script store the incorrect path?
How can I find the app the script is opening?


property checkInterval : 5 -- Number of seconds between checks. Adjust to requirement.

global App1WasOpen, GUIScriptingWasEnabled, previousText

on run
	-- When the script starts up, note if App1 is running and GUI Scripting is enabled.
	tell application "App1" to activate
	tell application "System Events"
		set App1WasOpen to (application process "App1" exists)
		set GUIScriptingWasEnabled to (UI elements enabled)
	end tell
	
	-- Enable GUI Scripting if necessary and give the 'previousText' variable an initial value.
	switchGUIScripting(true)
	set previousText to ""
end run

on idle
	-- Each time the script's polled by the system, check that App1's open.
	tell application "System Events" to set App1IsOpen to (application process "App1" exists)
	
	if (App1IsOpen) then
		--tell application "App2" to launch
		-- If App1's open, update the "was open" flag to indicate that it's been open while the script's been running.
		set App1WasOpen to true
		-- Get the latest value for 'beam'.
		tell application "App1"
			set hdg to getHeading
			set beam to hdg as string
		end tell
		if ((count beam) < 3) then set beam to text -3 thru -1 of ("000" & beam)
		
		-- If it's changed since the last check, enter it into App2 and keep it for later checks.
		if (beam is not previousText) then
			--display dialog "Opening App2" buttons {"OK"}
			tell application "App2" to launch
			--activate application "App2"
			tell application "System Events"
				
				set startTime to current date
				repeat until exists (text field 1 of window "App2" of application process "App2")
					if (current date) - startTime is greater than 5 then
						error "Could not find text field 1 of window AppB of application process App2"
						exit repeat
					end if
					delay 0.2
				end repeat
				tell application process "App2"
					try
						set value of text field 1 of window "App2" to beam
					end try
				end tell
			end tell
			--tell application "App1" to activate
			set previousText to beam
		end if
		
		-- Request the next 'idle' event in 'checkInterval' seconds' time.
		return checkInterval
	else if (App1WasOpen) then
		-- App1 was open at the last check, but isn't now. Tell this script applet to quit.
		quit
		-- It'll actually quit on the next idle event, so request a short interval.
		return 1
	end if
end idle

-- Unless GUI Scripting was already on when the script started to run, turn it on or off as per the parameter.
on switchGUIScripting(onOff) -- 'onOff' is 'true' for on, 'false' for off.
	if (not GUIScriptingWasEnabled) then
		tell application "System Events"
			activate
			set UI elements enabled to (onOff)
		end tell
	end if
end switchGUIScripting

-- When this applet's told to quit, restore the previous GUI Scripting state before it does.
on quit
	switchGUIScripting(false)
	continue quit
end quit

Hello.

If you have propertylist editor, I think entering a version string like 01.01.01 should work just fine! :slight_smile:

Thanks,

I don’t find it it the Developer\Utilities folder. I’ll have to find a download link. When I find it, what am I editing? The wrong app, in it’s “About” pane shows 0.3 (3). The correct one shows 0.1.4(2).

Okay, I got PListEdit Pro. What .plist do I edit?

A path is the only safe way if you have multiple copies of the app.

It’s not the script; it’s the OS.

Run the script, and when it opens the wrong app, go to the Dock, click on the app’s icon, and choose Options → Show in Finder.

Thanks Shane!

Since the app and the script are going to be distributed, there’s no telling where a user might put the app. Hopefully in the Applications folder. Can a path be specified that will work for anyone’s Applications folder?

Using “Find in folder” I was pointed to a 13 node location where Xcode archives the app. There were 17 folders there. None of those folders had any contents, but I moved them all to the trash.

Now the script didn’t find the app at all, failing with a recurring error of type -10660. I assume that is for not being able to find the app.

Next I opened the script in Script editor, copied the code, and pasted it into a new editor window and compiled it using a different name. No errors, but doesn’t run App2, and doesn’t show in the dock.

Hello.

If you open your app as a package, you’ll see a file called info.plist, when you open that file with the property list editor, you can specify a value for the key CFBundleVersion key, which may be described in human readable form as the build-version-number.

This should be specified in the form 0.0.0. If you just increase that number, then that app will execute other places, as the app with the highest version number “wins”.

This is the most practical way to do it, if you “push” your app elsewhere.

Thanks,

Put in the key and value, but no joy. The script still doesn’t start the app. The script doesn’t appear on the dock, so I think it’s not completing.

Is there anyplace I can see where the script is expecting to find the app? Is there a specific place the app should live?

Nope there is no place where the app should reside, but as far as I know, the last version of the App should start.

But having your app in one location, like /Applications or ~/Applications should help you, then you at least can overwrite it, if you install it on client’s machines. (Maybe by using the install command in a shell script.)

If I put

tell application "/Application/App2.app" to activate

at the top of the script it launches…briefly, then it disappears. Putting the path where ir is supposed to open App2 has no effect.

The dialog displays “App1 is open” but not the one for beam and previousText

if (App1IsOpen) then
		display dialog "App1 is open" buttons {"OK"}
		-- If App1's open, update the "was open" flag to indicate that it's been open while the script's been running.
		set App1WasOpen to true
		-- Get the latest value for 'beam'.
		display dialog "Beam, prev " & beam & ", " & previousText buttons {"OK"}
		tell application "App1"
			set hdg to getHeading
			set beam to hdg as string
		end tell

There was an update of OS X 10.8 last night. I hope that hasn’t caused all this.

As long as they have only one copy of the app, you’ll be fine. If not, it’s really out of your control.

It’s a bit like sending a Word document to someone. If they have more than one copy of Word, you can’t control which one opens.

According to Cocoa Fundamentals I believe (that can be downloaded from developer.apple.com), if you specify the version string, the latest version is the one that gets started, at least when started indirectly, that is, when the the app is started through launch services.

The document only states clearly that this happens when you open a document, for which the application is the default, but I see no reason why it shouldn’t work like this when being opened through an Applescript, by the “Activate” keyword, or by other incantations, since launchservices is what comes into play in such cases as well.

And I see no reason why launcservices should choose the app with the highest version number, just in some cases but not all, as long as no path to the app is specified.

If there are multiple copies of an app registered with Launch Services, and none of them is already running, the one with the highest version number is preferred. You can’t assume every copy is registered with Launch Services, and that they have version numbers in the appropriate form (not all apps do).

The docs also say: “Apple reserves the right to change the selection criteria in future system releases.”

So I think its not unreasonable to say it’s essentially out of the scripter’s control.

Thanks Shane.
If I use a path to Applicatons and they put the app on their desktop, it won’t find it right?

I did find what is causing the misbehavior. I don’t understand why.

on run
   -- When the script starts up, note if App1 is running and GUI Scripting is enabled.
   tell application "App1" to activate
   tell application "System Events"

If I take out the “APP1 activate” line (which I had added in an attempt to have the script open both apps), it finds and opens App2 nicely. I’d really like for it open App1.

McUsrII,

Thanks for your aid. See my reply to Shane for at least partial resolution.

Actually, I’m not sure – it may keep looking, or it might show a dialog.

I agree, especially about when we talk about unregistered applications. But you can better the odds for making the app “play ball” by adding a higher version number in one’s disitribution maybe also do a “dry run” to make it register, when installing the app. (By having a dry run handler for instance, that just makes the app quit after it has been acivated from a script, or install program.

So there are some small things we as developers can do to avoid such confusing behaviour by merely using the CFBundleProperty, and save some headaches".

I can’t see Apple remove that scheme, it makes a lot of sense to me, not at least before they replace it with another such criteria. And when they’ll change it, I’m pretty confident there will be a long transition period. :slight_smile:

:smiley: I finally found another reason for filling that property out!

Edit

I got confused as to whether it was CFBundleVersion or CFBundleShortVersionString, which goverened which app was to start based on version number.

I searched, and found the answer to be CFBundleVersion, and not CFBundleShortVersionString. CFBundleVersion is a single increasing integer. (I am sorry about that).

I also found a script at MacOSXAutomation.com I had from before that I have modified to deal with CFBundleVersion.

Any faults are mine, and there is no guarrantee about what so ever!

tell application "AppleScript Editor"
	try
		-- Check to see if the front document has been saved as a bundle application
		try
			set the doc_properties to the (properties of the front document)
			set the script_path to the path of doc_properties
			set the plist_path to script_path & "/Contents/Info.plist"
			set the plist_file to plist_path as POSIX file as alias
		on error
			error "The front script document has not be saved as a Script bundle or as an Application bundle."
		end try
		set just_set to false
		-- Get the value of the plist item if it exists
		tell application "System Events"
			set this_plistfile to property list file plist_path
			tell this_plistfile
				if (exists property list item "CFBundleVersion") then
					set the property_value to the value of property list item "CFBundleVersion"
				else
					set just_set to true
					set the property_value to "1"
				end if
			end tell
		end tell
		
		-- Query the user
		
		set the dialog_message to "This key specifies the build version number of the bundle, which identifies a build iteration of the application. The current build iteration  number is now: " & property_value & return & return & "Enter the build version string to use for this script bundle:" & return & return & "Leave empty to just increment by one."
		display dialog dialog_message default answer the "" with title "CFBundleVersion"
		copy the result to {text returned:temp_var, button returned:button_pressed}
		if temp_var = "" then
			if not just_set then
				set property_value to property_value + 1
			end if
		else
			set property_value to (temp_var as number)
		end if
		-- Write the value
		tell application "System Events"
			tell this_plistfile
				if (exists property list item "CFBundleVersion") then
					set the value of property list item "CFBundleVersion" to the property_value
				else
					make new property list item at end of property list items of contents of this_plistfile with properties {kind:string, name:"CFBundleVersion", value:the property_value}
				end if
			end tell
		end tell
		
		-- Confirmation
		display dialog "The value of the CFBundleVersion property for this script has been set to:" & return & return & the property_value & return & return & "Be sure to REGISTER the app with launch services" buttons {"OK"} default button 1
	on error error_message number error_number
		if the error_number is not -128 then
			display dialog error_message buttons {"Cancel"} default button 1 with icon 2
		end if
	end try
end tell

Not exactly; it’s a “monotonically increased string, comprised of one or more period-separated integers”.

That is true, I found it all clearly written in Information Property Key List Reference. I’m sorry that I wasn’t specific enough about that. But then I didn’t really mislead the originally OP, which is always a good thing :slight_smile:

The script above uses an ever increasing single number, which I think satisfies most needs for keeping a build version number. At least my needs, if somebody needs something more sophisticated, then roll your own! :slight_smile:

By the way.
Now, with the advent of version control systems like Git and Mercurial which uses a sha-1 string to differ between versions I see how this might change in the future.

IMHO Mercurial is by far the best version control system to use with Applescript as a single developer, you just look away from disk-space, and version control Apple Script. It is the absolute minimum of overhead for saving new versions, and making a branch is also very easy.

When it comes to collaborating projects, then git has this extra step of having you to specify which files to commit, which is good for safety reasons. Mercurial skips that, which is just fine when you work alone on something.