How to test whether an application is installed (MacOS)

Dear Forum members,

I am trying to get my first application to the Mac App Store and I feel that I am loosing the cat and mouse game with Apple reviewers.
I am writting an application that is standalone but also behaves as a Microsoft Word companion Application. I thus need to test whether Mircrosoft Word is installed on the system.
I use an Applescript but it access to the Finder and Apple refused that I get temporary entitlements to com.apple.finder.
Here is the script :

tell application "Finder"
	set isthere to false
	try
		get application file id "MSWD"
		set isthere to true
	end try
end tell

return isthere

Any idea, compatible with MAS rules, about how I may test whether Word is installed ?
I thought about looking in the Application folder but users may have installed it elsewhere. I also though about a shell but I am far from being familiar with it…

thanks a lot,
Franck

Launch Services functions?
either via Plugin or declares?

If I understand right, without Word, your application does not work ? So I assume users are aware that they cannot use it without.

I would put a strong warning in the product description that Word has to be installed in the Applications folder for it to work, and simply test if it is there upon launch. Then if it not there, display a window explaining why the application cannot continue, and what to do to correct.

Thanks Christian.
I just did a test and

  dim f as FolderItem
  f = LaunchServices.FindApp ("", "com.microsoft.word", "")
  if f = nil or not f.Exists then
    WordInstalled = false
  else
    WordInstalled = true
  end

seems to work but if microsoft word is not running, then this starts it.
I would prefer not but if I do not fond another solution…

Yes Michel. I even did not thought about testing my App without Word initially. But because I call an Applescript (Tell “Microsoft Word”…) than if is is not there, Applescript just wait, silently waiting for the user to tell it what the hell is “Microsoft XWid”, and my application hangs…
And so it was rejected from the MAS submission site because of this.

I found another solution, using a shell command
It looks for where an application is installed when providing its BundleID:

  Dim s As New Shell
  Dim cmd As String
  dim sepchar as string = chr(34)
  
  cmd = "mdfind "+sepchar+"kMDItemCFBundleIdentifier == 'com.microsoft.Word'"+sepchar
  s.Execute(cmd)
  if s.Result = "" then
    MsgBox("Not Installed")
  else
    MsgBox("Installed")
  end if

and this does not boot-up Word when testing.

Anyone knows whether this is Sandbox-compatible ?

thanks,
Franck

Thanks Jean-Paul
I have tried this

  dim f as FolderItem
  dim p as Ptr
  Dim aNSWorkspace as New NSWorkspace(p, true)
  
  f = aNSWorkspace.ApplicationFile("Microsoft Word")
  if f = nil or not f.Exists then
    MsgBox("Not Installed")
  else
    MsgBox("Installed")
  end

but it does not work (indicate that Word is not installed). I guess I do not use properly the function. I also tried (with no success with the BundleID function of NSWorkspace). As the Shell approach, it also does not boot up Word.

If the shell is Sandbox-compliant, I guess I will stay with it.

ApplicationFile does not work better with “com.microsoft.Word” (at least the way I used it in the routine above)

The following code works from a Sandboxed application (I’m using it in one).
The find if the application is installed (also returns where).

[code] #if TargetMacOS then
launchButton.enabled = false
declare function NSClassFromString lib “Foundation” ( className as CFStringRef ) as Ptr
declare function sharedWorkspace lib “AppKit” selector “sharedWorkspace” ( ref as Ptr ) as Ptr

declare function URLForApplicationWithBundleIdentifier lib "AppKit" selector "URLForApplicationWithBundleIdentifier:" ( NSWorkspace as Ptr , bundleIdentifier as CFStringRef ) as Ptr
declare function absoluteString lib "AppKit" selector "absoluteString" ( NSURLRef as Ptr ) as CFStringRef

Dim URLRef as Ptr = URLForApplicationWithBundleIdentifier( sharedWorkspace( NSClassFromString( "NSWorkspace" ) ), TextField1.text )
if URLRef <> nil then
  Dim f as folderitem = getFolderItem( absoluteString( URLRef ), folderItem.pathTypeURL )
  if f <> nil and f.exists then
    LaunchButton.enabled = true
  end if
end if

#endif[/code]

To launch an application…

[code] #if TargetMacOS then
declare function NSClassFromString lib “Foundation” ( className as CFStringRef ) as Ptr
declare function sharedWorkspace lib “AppKit” selector “sharedWorkspace” ( ref as Ptr ) as Ptr

declare function launchApp lib "AppKit" selector "launchAppWithBundleIdentifier:options:additionalEventParamDescriptor:launchIdentifier:"_
( NSWorkspaceRef as Ptr, bundleIdentifier as CFStringRef, options as Ptr, descriptor as Ptr, identifier as integer ) as boolean

call launchApp( sharedWorkspace( NSClassFromString( "NSWorkspace" ) ), TextField1.text, nil, nil, 0 )

#endif[/code]

Thanks Sam.
I will implement your solution then since I am not sure that the Shell-based solution will be MAS-compliant.

I’ll let you know…

Have a good day,
Franck

Will an approach like one of the above work with iOS?
Not tested that yet, just wondering…

You cannot launch any process from an iOS app. No shell, no f.launch, no JavaScript.

Yeah, that’s what I thought. But the Facebook SDK for xcode can somehow determine if the facebook app exists. If so, it can open the FB app to login. Otherwise Safari will be opened to handle the login process.
So, I think it must be doable.

You should start another specific iOS thread. This is getting off topic.

They usually check if UIApplication canOpenURL function returns true for a specific protocol.
And if your other app has a protocol, you get true here.

[quote=69377:@Sam Rowlands]The following code works from a Sandboxed application (I’m using it in one).
The find if the application is installed (also returns where).[/quote]

OK I know this is an old thread but in this code where are you specifying to “tell me if Microsoft Word specifically” is installed. I don’t see a string or identified for that in the code checked as the solution.

TextField1.text is where you want to set your bundle identifier.