Applications as resources to my application

My application shell’s out to a java application and gets results back in a file or from the standard output of that application.
I’d like to create a folder in my project (in the IDE) and put those programs in that folder.
Will I be able to reference those applications from my application at run time?
How do I get the Path to that resource within application via folderitem?

OS X or Windows? If you’re building OS X, then there’s some rules that you must obey.

  1. Executable code must be placed in a specific folder, for a helper application, it’s advisable to place it into “/Contents/Helpers”. Do not be tempted to put it into “/Contents/Resources/”.

  2. Your helper application must also be code signed at the same time as your main application, using App Wrapper will take care of this.

  3. If you’re intending to ship on the App Store, you’ll need to Sandbox the application and you’ll also have to use a different function for communicating with the helper application. If you have the Sandbox Kit, the class is called “OWShell”. You must also make sure that the helper application uses special entitlements, which again are set with App Wrapper.

My advice is to create a folder next to your project and call it “Helpers”, then in the Xojo IDE create a copy files script to copy that folder into the “Contents” folder.

As for getting the path to the helper. Check out this forum post for Tim’s module as it will help you get to important folders.
https://forum.xojo.com/15318-modules-for-you-updated-9-28

You his code to find the resources folder, then go up one level (to the contents) folder and down into your Helpers folder. Psudo code follows

Dim helpers as folderitem = TPSF.Resources.parent.child( "Helpers" ).child( "myHelperApp" )

Now you can use helpers.shellPath for the Xojo Shell or helpers.nativePath for OWShell.

I’m writing for a webservice to be deployed on mac or windows or linux, but not too concerned about the app store.
When you say “/Contents/Helpers” You mean I need to create folder in the (IDE) in the project called Contents and create a folder underneath it called Helpers?

example
Many thanks.
B.

Also when I drag and drop the helper application into a folder in the IDE all I get is a shortcut.
Am I doing this wrong?

[quote=181984:@Brian O’Brien]Also when I drag and drop the helper application into a folder in the IDE all I get is a shortcut.
Am I doing this wrong?[/quote]

In Mac, the .app is in fact a folder. So you cannot drag it into the folder that way. Just use a Copy File step.

On Windows, I would copy to the Resources folder. It will be placed next to the app and easy to point to.

You need a copy files step, select “Insert” > “Build Step” > “Copy Files”.

Add in your files and folders you want added, then move that “Build Step” into the intended target, make sure your copy files step is below the actual build process.

Here, I have several build scripts and a copy files step.

Is there a problem with putting the helpers next to the application executable (i.e., in “/Contents/MacOS”)?

It should work, and ‘MacOS’ is one of the places where you can store executable code.

I’m doing this in a project that I’m developing, and it certainly works from the standpoint of being able to run the app, but I was wondering whether it was not the “right” thing to do, I’d rather not buy current or future problems based on where I put the helper…

Thanks for responding, Sam.

I’m not really fond of the copy files step because this can be screwed up when the file is missing. Also you can’t copy to sub-sub directories. This made a nice crash the last time I tried it. Here is my script:

[code] 'copy the scheduler to app/library/loginitems

dim appPath as string = currentBuildLocation + “/” + shellEncode(currentBuildAppName)
if right(AppPath, 4) <> “.app” then appPath = appPath + “.app”

'do directory for loginitems
dim cmd as String = "/bin/mkdir -p " + appPath + “/Contents/Library/LoginItems”
dim theOutput as string = doShellCommand(cmd)
if theOutput <> “” then print theOutput

'get path to scheduler
dim CountSlashes as integer = CountFields(ProjectShellPath, “/”)
dim ProjectName as string = NthField(ProjectShellPath, “/”, CountSlashes)
dim ProjectPath as String = Left(ProjectShellPath, Len(ProjectShellPath) - Len(ProjectName))
dim PathToScheduler as String = ProjectPath + shellEncode(“Builds - max scheduler.rbp/Mac OS X (Cocoa Intel)”)

'copy scheduler to app
cmd = "usr/bin/ditto " + PathToScheduler + " " + appPath + “/Contents/Library/LoginItems”
theOutput = doShellCommand(cmd)
if theOutput <> “” then print theOutput

// Helper functions for this script
Function shellEncode(inValue as string) as string
Dim rvalue as string = replaceAll(inValue, " ", "\ ")
rvalue = replaceAll(rvalue, “&”, “\&”)
rvalue = replaceAll(rvalue, “-”, “\-”)
rvalue = replaceAll(rvalue, “(”, “\(”)
rvalue = replaceAll(rvalue, “)”, “\)”)
return rvalue
End Function[/code]

Don’t use cp for stuff like this because this wrecks the signing of the helper app.

[quote=181599:@Sam Rowlands]<…>

  1. If you’re intending to ship on the App Store, you’ll need to Sandbox the application and you’ll also have to use a different function for communicating with the helper application. If you have the Sandbox Kit, the class is called “OWShell”. You must also make sure that the helper application uses special entitlements, which again are set with App Wrapper.
    <…>.[/quote]
    Which entitlements are you referring to? Application specific entitlements (like client network access) or are there any entitlements specifically for helper apps?

Generally (as there are some circumstance where you don’t want the helper application to have access to the same resources as the main application). You need to use “Inheritance”, which is on the “Capabilities” pane of App Wrapper, under the heading “Contained Executables”.

In this Content I have 2 more questions:

  1. if the helper app is contained within the main app (/contents/Helpers) can it run an installer which replaces the main app? I guess, the main app file would be locked?

  2. I can’t find any example for how to use OWShell from the sandbox kit: do you have an example which runs a helper while being sandboxed?

It can’t ‘run’ an installer, but you can use folderitem.launch to open an Apple installer package and then it’s up to the user (which is how we do it at the moment).

If there isn’t one in the Sandbox Kit demo application, I can make you one.

quote=189348:@Sam Rowlands
If there isn’t one in the Sandbox Kit demo application, I can make you one.[/quote]
If I have not totally missed something, then there is no example for OWShell in your sandbox kit. If you could add one, this would probably be helpful also for others.

I don’t know what the difference is between ‘run’ and ‘launch’, but this is what I meant: launch the installer pkg which is generated by AppWrapper.

In fact, I have it working in a non-sandboxed application. There I store the credentials in keychain and (with user consent) I run automatic updates in silent mode lateron. I hope to get this working with OWShell also in sandboxed mode.

Just to clarify, I don’t see this working with a Sandboxed application as it can’t overwrite it’self and if you use NSTask or OWShell to run the installer command-line function, it will actually run it as a child of your application, which means that it also cannot overwrite the main application.

Updating Sandboxed applications outside of the App Store, is a whole can of worms. If I understand correctly, Sparkle (http://sparkle-project.org) still isn’t Sandbox compatible. I know Andy was working hard on trying to figure out how to do this when Sandboxing first appeared.

As for a simple OWShell example, here’s one for zipping a file.

[code]Function zipTo(extends f as folderItem, destination as folderItem, byRef error as string) As boolean
Dim s as new OWShell
Dim arguments( -1 ) as string = array( “-ck”, “–sequesterRsrc” )

if f.directory then arguments.append “–keepParent”
arguments.append f.shellPath
arguments.append destination.shellPath

s.execute( “/usr/bin/ditto”, arguments )
error = s.result

return error = “”
End Function
[/code]

Now if you want to use a helper application within your application bundle, you must pass in true when creating the OWShell class.

Dim s as new OWShell( true )

Thanks, Sam!