How do I save custom properties in a standalone application?

Custom properties are a very useful way to store information, and if you want that information to persist between sessions you can just save your stack and the custom properties are saved and available next time you start it up. But what if you want to use and save custom properties once you have built your application into a standalone?

In this lesson we will learn how to create a standalone application consisting of a launcher and an editable file.

This lesson only applies to desktop apps. To save custom properties or other state data in mobile apps see this lesson.

The launcher and the main stack

The launcher and the main stack

Firstly we need two new stacks, one will be the launcher and one our main application.

From the file menu create a new mainstack and name it Launcher, then create another main stack and name it Main Application.

Creating the launcher

The launcher stack will be built into a standalone and all we need it to do is to open our main application, it can then close itself. Add the following script to the stack script of the launcher stack.

on openStack
   // Set the default folder
   set the itemDel to "/"  
   if the environment is "standalone application" then
      if the platform is "MacOS" then
         set the folder to item 1 to -5 of the filename of this stack
      else
         set the folder to item 1 to -2 of the filename of this stack
      end if
   else
      set the folder to item 1 to -2 of the filename of this stack
   end if
   
   open stack "Main Application.livecode"
   close stack "Launcher"
end openStack

Firstly we set the default folder to the folder containing the standalone and Main Application stack, this allows the Main Application stack to be found.

The launcher will then open the Main Application stack, which can be modified and saved as it is not a standalone.

Adding some script to the main application

Adding some script to the main application

Now we need a simple test to check that our Main Application can be saved and that custom properties are preserved.

Lets use our name as an example. We will add a field called "name" to type your name into (1), a button which saves the name as a custom property (2) and another button which displays the saved name using an answer dialog. (3)

The Save Name button just stores the name in a custom property

on mouseUp
	set the cName of this stack to field "name"
	put empty into field "name"
end mouseUp

The Display Name button uses an answer dialog to display the name saved in the custom property

on mouseUp
	answer the cName of this stack
end mouseUp

Saving the stack

In order to preserve the custom property cName we need to save our Main Application stack when it is closed. Add the following script to the stack script of the Main Application stack

on closeStack
	save this stack
	pass closeStack
end closeStack

This means any changes we have made to the stack, including our custom property are saved.

 

Building a standalone

Building a standalone

Now build the Launcher stack into a standalone. Once the standalone is built copy the Main Application file into the same folder as the standalone. Note, the standalone is an application (.exe) file, even if the extensions does not show, and the Main Application is a .livecode file (not an app).

Testing our application

Testing our application

Now close both the Launcher and the Main Application file. Re-open the launcher, you should see the Main Application window open and the Launcher close. Put in your name, save it and check it displays. Now close the application, run the launcher and try Display Name again. The custom property storing your name should have been saved from the previous run.

29 Comments

Arthur

Wow. Thanks for the tips.

--Any idea how we can secure the .rev file so no one can open it?

---Also This make is easier to update an application from say v1.0 to 1.1. How would that mechanism work. I'm guessing the launcher can check if there is an update and then just replace the old file with the new one?

Thanks again for the tutorial.

Elanor Buchanan

Hi Arthur

You can password protect the stack using the password property in Rev. This encrypts a stack's contents, allowing access only from within the application.

http://docs.runrev.com/Property/password

You can also hide the fact that it is a Rev stack by changing the extension.

Yes launchers do allow you to update an application, just use the launcher to check for an update, download the new file and launch the most up to date version of the file. You can either overwrite the original or download to an application support or documents folder and just check for the latest version when you are launching.

I hope that helps.

Elanor

Arthur

I had a question about how to include database drivers with this "Launcher method" do we add the m to the launcher standalone builder settings?

Thanks

Elanor Buchanan

Hi Arthur

That's correct, when you build your standalone launcher you need to select the inclusions for anything you want your application to have access to, so in this case you would select Database Support and whichever database types you want to be able to work with.

I hope that helps.

Kind regards

Elanor

Geoff Taylor

Brilliant!

Works great with my skin from the recent Game Academy, enabling me to flag whether or not an initial splash screen image should show when returning to the main menu card.

Can you say if this is going to work in iOS too?

Hanson Schmidt-Cornelius

Hi Geoff,

you can keep track of states in the custom properties of the application at runtime, but once the user closes an application, the properties are lost.

You can save settings to the sandbox of your application and load settings back into your application. This allows you to retrieve any settings once the user opens the application again.

Have a look at the the "specialFolderPath" function, the "open file" command, the "write to file" command, the"read from file" command and "close file" command in the dictionary.

Kind Regards,

Hanson

ian stewart

Dear all

I am trying but not quite getting this.

I follow the instructions given and the program runs as expected when the whole thing is uncompiled in that I enter a name and save it and the name disappears and then when I process display it shows the name in an answer box.

However, when I compile "Launcher" and put the main application file into the same folder as "Launcher" and then try to run the program everything seems to work the same way but the display button does not produce an answer box.

I am not sure why there is this disparity. My immediate thought would be that the reference to 'stack' in the 'Display' button script is ambiguous and maybe it is interpreting that as referring to the Launcher as the stack instead of the main application. But then why does this not happening in the uncompiled mode as well and of course no-one else seems to have this problem?

I would really appreciate some advice on this.

Thank you
Ian

Ian Stewart

Hi again folks

Further to my last email in which I said that the display button did not appear to work when Launcher was compiled:

I put some more code into the display button. This put the name into a field instead of having it come up in an answer box.

The field did produce the name in the compiled Launcher (unlike the answer box), but it did not reproduce it when I closed and then re opened Launcher and pressed 'Display' (which of course is critical to the project under discussion in this lesson).

Again, I would really appreciate some input as to what might be going wrong with this for me as the ability to retain information in a compiled program from one session to another is crucial as far as a current project I am working on is concerned.

Thanks
Ian

Hanson Schmidt-Cornelius

Hi Ian,

the problem here is that you are loading and running a LiveCode stack from within a LiveCode standalone application.

When you create a standalone application, the build process can either automatically include all of the components necessary for the application to run, or you can specify the components that are needed to run. With the example in this lesson, the "Answer Dialog" is not automatically included in the standalone application. You have to include the "Answer Dialog" component manually through settings in the "Standalone Application Settings".

Open the "Standalone Application Settings" dialog and select the "General" tab. Ensure that you select "Advanced Options" under the "Inclusions" heading. Then tick the "Answer Dialog" box to include this feature in the standalone.

Build the standalone in the usual way and you should now have the "Answer Dialog".

Kind Regards,

Hanson

Andre De Tienne

Using this launcher (or splash screen) method where only the launcher is turned into a standalone, can the main stack (as a stack file not a substack of the launcher) be loaded with its own substacks (not themselves separate stack files)? I have built an application (main stack) that comes with more than seventy substacks. If to make it available as a standalone I create a launcher that allows the user to open this separate main stack, will it function with all of its own substacks?

Many thanks for clarifying this point.

Andre

Hanson Schmidt-Cornelius

Hi Andre,

yes it should work, but it really depends on the application and what the application is supposed to do.
It should not be much effort to set up a test application and see if it runs as expected.

Kind Regards,

Hanson

Pete Moxon

I have just tried to password protect a stack file that I added as an additional stack in the standalone build setting.

When I then build the application the password & 'encrypt with password' checkbox is cleared.

Is this a bug?

Hanson Schmidt-Cornelius

Hi Pete,

it depends on the edition of LiveCode you are using.
If you are using the community edition, then you do not have support for password protection of the LiveCode stacks. The commercial edition does provide this protection.

Kind Regards,

Hanson

Pete Moxon

Ah!

Thanks for the answer Hanson. I was thinking this may be the case.

Will be purchasing soon as soon as I figure out a few other things related to mobile.

Pete

Lars Jørgensen

Please help, as I am new to LiveCode and is trying to learn it. I have created, built and executed the Launcher and Main Application almost without issue but ran into the same problem as Ian Stewart. However, the issue I have is when I try to reopen the Launcher Stack again it opens and then immediately closes again (I see the Stack open and then after a millisecond it closes). Therefore, I am not able to rebuilt the Launcher Stack. System (Mac OS X Lion 10.7.5) LiveCode (Community Edition 6.1.1 Build 2012)
Lars

Hanson Schmidt-Cornelius

Hello Lars,

the Launcher Stack is intended to open, load the LiveCode stack and then close again.

It looks like it cannot find "Main Application.livecode" or "Main Application.livecode" is quitting.

Try debugging this by first ensuring the stack you want to launch exists. You could try something like:

answer there is a file "Main Application.livecode"

Add this to your Launcher Stack code before you close it. This should raise a dialog with either true or false, indicating if the application that is to be launched, can be found.

If that returns true, then you may have a bug in the code of your "Main Application.livecode" stack. Try debugging that code, possibly by putting some very simple constructs into that code. Again, try something like answer:

answer "Hello World"

The nice thing with answer is that it will block until you press the button. So you know that if you do not get a dialog, then you have not yet hit that bit of code.

Kind Regards,

Hanson

Ivan

The code did not work on Mac until I set the correct folderPath.

on openStack
put fGetDefaultPath() into myPath
set the defaultFolder to myPath
open stack "Main Application.livecode"

if the result is not empty then
put the result && "("& sysError() &")"
exit to top
end if

close stack "Format My URL Launcher"
--put "Messages" into fld "fMessages"
end openStack

function fGetDefaultPath
-- get the file path for this stack
local tPath
put the effective filename of this stack into tPath
set the itemDelimiter to slash
if the platform = "MacOS" and the environment = "standalone application" then
-- if this is a standalone application running on a Mac, find the path to the .app file
repeat until last item of tPath contains ".app"
delete last item of tPath
end repeat
end if
-- remove the last item to get the path to the containing folder
delete last item of tPath
return tPath
end fGetDefaultPath

Russell

I am trying to use the Browser widget in my "Main application" associated with my launcher. I have tried all variations of Browser inclusions in the launcher and the .livecode "Main application". No sign of the browser. It works perfectly fine in IDE. Any solutions greatly appreciated. Thanks. Livecode 9.0.1

Elanor Buchanan

Hi Russell, I just tested a very simple "Main application" with a browser widget and it worked ok. What platform are you on?

Russell

Mac. I used the bug report on the standalone build and it came back that it was not recognising “put url into tvari” I.e. I cannot test as to whether tvari is not empty and that the user has an internet connection and has clicked on a live url. The workaround is to not test and so, if there is not internet connection, you just get a white box. Obviously not as good as being able to bring up a dialogue saying “please check your internet connection etc”.

Elanor Buchanan

Hi Russell

It may be that your code is not quite correct. If you are trying to get the value of the URL property of the widget you could try

put the URL of widget "browser" into tvari

If you are trying to the the contents of the URL try

put url into tvari

You could also use some of the browser widget messages to detect if loading a URL has failed, browserNavigateFailed might be a good place to start.

You can find the browser widget messages and properties by filtering the Dictionary using the Associations list or by searching for "browser" and selecting the entry for the browser widget which includes a list of all the browser widget messages and properties.

I hope that helps.

Elanor

Russell

Hi Elanor,

Thanks for your help. I'll try the widget value.

Regards

Russell

CAsba

Hi,
I built a standalone which worked perfectly. Subsequent standalones that I made looked exactly the same but changes were not kept. I tried many times to make another successful standalone. Afet many frustrating hours I achieved success again, changes were saved. I did two actions, one or both of which made the standalone work. I re-started the computer and I set up the standalone with the first card (1002) on screen. Previously the onscreen card presented requirements to the user prior to accessing the card (1002).

Panos Merakos

Hello Casba,

Does it work as expected for you now? If yes, I am wondering if previously for some reason the parent folder that contained the standalone (or the standalone itself) was restricted to be read-only, thus changes could not be saved, and restarting your machine fixed this.

If you still experience the same problem, then could you send a sample app that demonstrates this issue?

Kind regards,
Panos
--

bogs

In the code in the article above to determine the location of the default folder, the 'if / then' statement should be corrected to not include the 2nd 'else' which shows up *after* the original 'end/if'
------------------
on openStack
// Set the default folder
set the itemDel to "/"
if the environment is "standalone application" then
if the platform is "MacOS" then
set the folder to item 1 to -5 of the filename of this stack
else
set the folder to item 1 to -2 of the filename of this stack
end if // <- this should be the end
/* this part is redundant --
else
set the folder to item 1 to -2 of the filename of this stack
end if
-- */
open stack "Main Application.livecode"
close stack "Launcher"
end openStack
--------------------------
The extra lines may cause confusion.

Panos Merakos

Hello bogs,

The "else" block which is marked as redundant in your comment is for the case the stack is running in the IDE (i.e. not in a standalone) - so I think it is needed. There might be a shorter way to write the openStack handler but it won't be that readable.

Kind regards,
Panos
--

bogs

Hello Panos :)
As to shorter ways to write the above, several options come to mind, but for clarity of the code for beginners I would certainly limit it as I said earlier.
-------limited code---------
if the environment is "standalone application" and the platform is "MacOS" then
set the folder to item 1 to -5 of the filename of this stack
else #all other cases...
set the folder to item 1 to -2 of the filename of this stack
end if
----------end----------
Another alternative which would be even shorter AND test the only real concern (running on Mac OS) would be to actually use that as the first line , such as...
-------really limited--------
if the platform is "MacOS" then
set the folder to item 1 to -5 of the filename of this stack
else
set the folder to item 1 to -2 of the filename of this stack
end if
----------end-----------
...since that accomplishes the same result regardless of environment as the code in the article would, unless I am missing something which is always quite possible.

Panos Merakos

Hello bogs,

Thanks for the shorter forms. The first suggestion is neat and correct. The second one (i.e. the "really limited" one) is not entirely correct, since if the stack is opened in the LC IDE on MacOS, then "the folder" will be set to to item 1 to -5 of the filename of this stack , which is not what we want if the stack is running in the IDE.

Kind regards,
Panos
--

bogs

Hm. I see your point, and it wasn't that much shorter to begin with ;)

Add your comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.