This guide outlines the features of Solar2D that are specific to macOS desktop apps. A .app
bundle which contains the Corona runtime engine and your Corona project's compiled code and assets.
All features supported by the Corona Simulator for macOS are supported for macOS desktop builds.
Many developers will start with an iOS app, intending to duplicate it on the Mac platform. First and foremost, avoid the tempting assumption that all you need to do is choose
Keep in mind that your macOS app will undergo the Apple review process before being accepted into the
Your app appears to be a mostly unmodified port of an iOS app.
Among other things, you should consider how your app reacts to window size changes and how it works in full screen mode. The size of the content area is much more variable on the desktop than it is on devices and you will almost certainly need to make changes to your app so that it works well in the desktop environment. Remember that you can adjust both the window size and the content area and that they don't necessarily need to be the same. Also remember that landscape orientation is what users will expect, so it will be more difficult to make a good impression with a
Obviously, anything you can download from the
For both macOS desktop apps and Win32 desktop apps, Corona's build.settings
file supports a window
table for customizing the app's desktop window, including the default width/height, the title of the window, and more.
settings = { window = { -- Settings for the desktop window; applies to both macOS and Win32 desktop apps }, }
Within the window
table, the following settings are supported:
Sets how the window should be launched on startup. Supported values include "normal"
, "minimized"
, "maximized"
, or "fullscreen"
. Default is "normal"
. This can also be set programmatically via the native.setProperty() API.
settings = { window = { defaultMode = "fullscreen", }, }
Sets the default launch width of the view/client area of the window. This is the region within the borders of the window to which Corona renders. Ideally, this should match or exceed your config.lua
content area width.
settings = { window = { defaultViewWidth = 640, }, }
Sets the default launch height of the view/client area of the window. This is the region within the borders of the window to which Corona renders. Ideally, this should match or exceed your config.lua
content area height.
settings = { window = { defaultViewHeight = 960, }, }
Set this to true
to allow the end user to resize the window (the window is not resizable by default). Note that if true
, you may need to handle Corona's resize event to
settings = { window = { resizable = true, }, }
This setting only applies if resizable
is set to true
. Prevents the user from resizing the window to a width smaller than this value. Note that this represents the width of the region within the borders of the window. If resizable
is set to true
and this setting is not specified, the window can be resized down to whatever width the OS allows.
settings = { window = { minViewWidth = 320, }, }
This setting only applies if resizable
is set to true
. Prevents the user from resizing the window to a height smaller than this value. Note that this represents the height of the region within the borders of the window. If resizable
is set to true
and this setting is not specified, the window can be resized down to whatever height the OS allows.
settings = { window = { minViewHeight = 480, }, }
Tells the runtime to suspend when the window is minimized
settings = { window = { suspendWhenMinimized = true, }, }
Causes the window's title bar to be shown (by default) or hidden making the app's content fill the entire window. Dragging at the top of the window will move it as with a regular window and clicks in this area do not go to the app. This setting is supported on macOS only.
settings = { window = { showWindowTitle = false, }, }
Sets the window's title bar text to the specified string (no title bar text by default). Supports default
title text can also be set programmatically via the native.setProperty() API.
settings = { window = { titleText = { -- The "default" text will be used if the system is using a language and/or -- country code not defined below. This serves as a fallback mechanism. default = "Window Title Test", -- This text is used on English language systems in the United States. -- Note that the country code must be separated by a dash (-). ["en‐us"] = "Window Title Test (English‐USA)", -- This text is used on English language systems in the United Kingdom. -- Note that the country code must be separated by a dash (-). ["en‐gb"] = "Window Title Test (English‐UK)", -- This text is used for all other English language systems. ["en"] = "Window Title Test (English)", -- This text is used for all French language systems. ["fr"] = "Window Title Test (French)", -- This text is used for all Spanish language systems. ["es"] = "Window Title Test (Spanish)", }, }, }
You can exclude file(s) that aren't needed for an macOS desktop app via the build.settings
file's excludeFiles
pattern matching feature. Please see the Excluding Files section of the Project Build Settings guide for more details on pattern matching.
Sometimes it's necessary to include certain files in your application to support specific macOS features. One example of this is localization which is achieved at the OS level (for example the Finder's label for an app) using .lproj
directories in the application's Resource
directory (background) page. Note that this mechanism to include arbitrary resources in your app is only intended to enable the knowledge to complete certain tasks and is not intended to automate anything.
To include arbitrary files in your app's Resource
directory add a bundleResourcesDirectory
entry to your project's build.settings
for macOS builds. For example:
settings = { macos = { bundleResourcesDirectory = "osx-resources", }, }
Then, in the project, the contents of the osx-resources
directory might look like this:
fr.lproj/ osx-resources/fr.lproj: InfoPlist.strings
This results in the fr.lproj
directory ending up in MyApp.app/Content/Resources/fr.lproj
.
You will probably want to add the directory you use as bundleResourcesDirectory
to your excluded files.
To enable a custom URL scheme in your macOS app, you'll need to set it up in the app's Info.plist
by including a section like this in build.settings
:
settings = { macos = { plist = { CFBundleURLTypes = { { CFBundleURLName = "My URL Scheme", CFBundleURLSchemes = { "myscheme", }, }, }, }, }, }
This will allow the app to receive a message from
open myscheme://these/are/the/parameters
To handle the message in your Corona app, implement a handler like this:
local function onSystemEvent( event ) if ( event.type == "applicationOpen" and event.url ) then local launchURL = event.url print( "Event: applicationOpen - launchURL: ", launchURL ) end end Runtime:addEventListener( "system", onSystemEvent )
Similarly to how custom URL schemes work you can set up document types that you app recognizes and which can be opened by dragging them to the app's icon in the Finder or the Dock.
To enable custom document types in your macOS app, you'll need to set it up in the app's Info.plist
by including a section like this in build.settings
:
settings = { macos = { plist = { CFBundleDocumentTypes = { { CFBundleTypeExtensions = { "png", }, CFBundleTypeIconFile = "app.icns", CFBundleTypeName = "public.png", LSHandlerRank = "Alternate", LSItemContentTypes = { "public.png", }, }, }, }, }, }
In your Corona app, implement a handler like this:
local function onSystemEvent( event ) if ( event.type == "applicationOpen" and event.url ) then local filename = event.url print( "Event: applicationOpen - filename: ", filename ) end end Runtime:addEventListener( "system", onSystemEvent )
This code will called when files with the configured types are dropped on your app's icon in the Finder or the Dock. More information is available in Apple's developer Core Foundation Keys documentation.
If you need custom entitlements in your macOS app, specify them in build.settings
. For example, you might need to specify the com.apple.security.personal-information.location
entitlement if you use Corona's location features.
settings = { macos = { entitlements = { ["com.apple.security.personal-information.location"] = true, }, }, }
To customize the copyright message in the About box of your app, you can add the following to build.settings
:
settings = { macos = { plist = { NSHumanReadableCopyright = "Copyright © 2017 XYZ Company" }, }, }
You should add a Icon-osx.icns
file to your Corona project's root directory to provide an icon for your application on macOS This should be an .icns
file which contains multiple versions of your icon at different resolutions (details). This Icon-osx.icns
.app
bundle uses, as viewed in the Finder.You can find apps in the Mac App Store to help with the creation of .icns
files.
To build and run your macOS desktop app, follow these steps:
Open the Corona Simulator.
Open and run a Corona project.
Select the
The Application Name, Version, and Save to Folder fields are all required. Here are notes regarding these build dialog fields:
Application Name — The application name you've entered can be fetched at runtime via Corona's system.getInfo( "appName" )
call (reference).
Version — The version string you've entered can be fetched at runtime via Corona's system.getInfo( "appVersionString" )
call (reference).
Provisioning Profile — The provisioning profile for the app; see App Signing below.
Save to Folder — The directory in which to save the built project.
After Build — select which action should be performed after the app is successfully built.
Click the Build button to build your application to the given Save to Folder location. If you chose
The Corona Simulator does not currently support direct simulation of an app running in macOS desktop mode, although the Simulator running a "Custom Device" skin is almost the same.
Note that when running a built macOS Corona app or the Corona Shell, all print()
output and Lua errors/warnings will be streamed to stdout
. There are various ways to manage this output. One way is to run the executable embedded in the app bundle in a Terminal window which will make the debug output visible. For example:
./Bridge\ for\ OS\ X/Contents/MacOS/Bridge\ for\ OS\ X
In this example, the backslashes (\
) protect the spaces in the filename (you could alternatively use quotes).
You can also use the Console app in the
If you run the app by choosing the After Build → Open application option in the Corona Simulator build dialog, the app's output will appear in the Corona Simulator Console window.
You'll need a "Mac Apps" provisioning profile from the Apple Developer portal in order to sign your macOS app. This works very similarly to the iOS app signing process, but you may optionally choose to create an unsigned app by selecting None in the Provisioning Profile dropdown when performing a build. Unsigned apps can be run on your own machine and, with some tweaking of the
Provisioning profiles should be installed in ~/Library/MobileDevice/Provisioning Profiles
For testing, it's recommended you sign the app with your Mac App signing identity by choosing it in the Corona Simulator
You can distribute your app via the Mac App Store, a .dmg
, or any other way you may distribute an .app
bundle.
If not using the Mac App Store, we recommend that you sign the app with your Mac App signing identity by choosing it in the Corona Simulator build dialog menu and then tell your testers to choose the Mac App Store and identified developers option on the
If using a .zip
archive to distribute your app, be aware that there are symbolic links in the built .app
bundle, so you must specify the -y
option if running zip
on the command line to create your archive (using the Compress option in the Finder does the correct thing automatically). Failure to do this will result in macOS saying the app is damaged when run on another computer. Also note that some file sharing services can corrupt macOS applications, so we recommend that you put them in .zip
archives before uploading them.