Troubleshooting iOS Debug Build installs

In 9 cases out of 10 if you have a problem installing an app make sure your device is a 64 bit device. If not you will need to add the build hint ios.debug.archs=armv7. Notice that a 32 bit app will still work on a 64 bit device it will just display a performance warning.

If you have access to a Mac you can connect a cable and open xcode where you can use the device explorer console to look at messages which sometimes give a clue about what went wrong. If not here is a laundry list of a few things that might fail:

  • Make sure you built the debug version and not the appstore version. The appstore version won’t install on the device and can only be distributed via Apple’s store or testflight

  • Verify that you are sending a 32 bit build in the build hints using the build hint ios.debug.archs=armv7. It’s only necessary if you have an older 32 bit device, see this. Notice that this only applies for debug builds, release builds include both 32 and 64 bit versions

Devices prior to iPad Air & iPhone 5s were 32 bit devices so iPhone 5s won’t need that flag but iPhone 5 or iPhone 5c will need it
  • Check the the UDID is correct - if you got the UDID from an app then it’s probably wrong as apps don’t have access to the device UDID anymore. The way to get the UDID is either thru iOS Settings app or itunes

  • Make sure the device isn’t locked for installing 3rd party apps. I’ve had this when trying to install on my kids tablet which I configured to be child safe. This is configured in the settings as parental controls

  • Check that you "own" the package name. E.g. if you previously installed an app with the same package name but a different certificate a new install will fail (this is true for Android too). So if you installed the kitchen sink from the store then built one of your own and installed it there will be a collision.
    Notice that this might be problematic if you use overly generic package names as someone else might have used them which is why you must always use your own domain

  • Make sure the device has a modern enough version of iOS for the dependencies. I think the current minimum for hello world is 6.0.1 but some apps might require a newer version e.g. Intercom requires OS 8 or newer

  • Verify that you are using Safari when installing on the device (if you tried via cable that’s not a problem), some developers had issues with firefox not launching the install process

  • Check that the build hint ios.includePush is set in a way that matches your iOS provisioning. So it must be false if you don’t have push within the provisioning profile

The iOS Screenshot/Splash Screen Process

iOS apps seem to start almost instantly in comparison to Android apps.
There is a trick to that, iOS applications have a file traditionally called Default.png that includes a 320x480 pixel image of the first screen of the application. This creates an "illusion" of the application instantly coming to life and filling up with data, this is rather clever but is a source trouble as the platform grows [1].

You can disable the screenshot process entirely with the ios.fastBuild=true build hint. This will only apply for debug builds so you don’t need to worry about accidentally forgetting it in production.

The screenshot process was a pretty clever workaround but as Apple introduced the retina display 640x960 it required a higher resolution [email protected] file, then it added the iPad, iPad Retina and iPhone 5 [2] iPhone 6 & 6+ all of which required images of their own.

To make matters worse iPad apps (and iPhone 6+ apps) can be launched in landscape mode so that’s two more resolutions for the horizontal orientation iPad. Overall as of this writing (or until Apple adds more resolutions) we need 16 screenshots for a typical iOS app:

Table 1. iOS Device Screenshot Resolutions
Resolution File Name Devices



iPhone 3gs


[email protected]

iPhone 4x


[email protected]

iPhone 5x



Non-retina ipads in portrait mode



Non-retina ipads in landscape mode


[email protected]

Retina ipads in portrait mode


[email protected]

Retina ipads in landscape mode


[email protected]

iPhone 6


[email protected]

iPhone 6 Plus Portrait


[email protected]

iPhone 6 Plus Landscape


[email protected]

iPad Pro Portrait


[email protected]

iPad Pro Landscape


[email protected]

10.5" iPad Pro Portrait


[email protected]

10.5" iPad Pro Landscape


[email protected]

iPhone X Portrait


[email protected]

iPhone X Landscape

You can predefine any of these files within the native/ios directory in your project. If the build server sees a file matching that exact name it will not generate a screenshot for that resolution

Native iOS developers can run their applications 16 times with blank data to grab these screenshots every time they change something in the first view of their application!

With Codename One this will not be feasible since the fonts and behavior might not match the device. Thus Codename One runs the application 16 times in the build servers, grabs the right sized screenshots in the simulator and then builds the app!

This means the process of the iPhone splash screen is almost seamless to the developer, however like every abstraction this too leaks.

The biggest problem developers have with this approach is for apps that use a web browser or native maps in the first screen of their app. This won’t work well as those are native widgets. They will look different during the screenshot process.

Another problem is with applications that require a connection immediately on startup, this can fail for the build process.

A solution to both problems is to create a special case for the first launch of the app where no data exists. This will setup the screenshot process correctly and let you proceed with the app as usual.


One of the first things we ran into when building one of our demos was a case where an app that wasn’t very big in terms of functionality took up 30mb!

After inspecting the app we discovered that the iPad retina PNG files were close to 5mb in size…​
Since we had 2 of them (landscape and portrait) this was the main problem.

The iPad retina is a 2048x1536 device and with the leather theme the PNG images are almost impossible to compress because of the richness of details within that theme. This produced the huge screenshots that ballooned the application.

Mutable first screen

A very common use case is to have an application that pops up a login dialog on first run. This doesn’t work well since the server takes a picture of the login screen and the login screen will appear briefly for future loads and will never appear again.

Unsupported component

One of the biggest obstacles is with heavyweight components, e.g. if you use a browser or maps on the first screen of the app you will see a partially loaded/distorted MapComponent and the native webkit browser obviously can’t be rendered properly by our servers.

The workaround for such issues is to have a splash screen that doesn’t include any of the above. Its OK to show it for a very brief amount of time since the screenshot process is pretty fast.

Launch Screen Storyboards

With the shift to Xcode 9, which is the default version on the Codename One build servers as of February 2018, it is now possible to use a launch-screen storyboard as the splash screen instead of launch images. This will potentially solve the issue of the proliferation of screenshots, as you can supply a single storyboard which will work on all devices. Launch storyboards are disabled by default (as of April 2018), but will likely become the default at some point in the future, since this is the direction that Apple is moving. You can enable the LaunchScreen storyboard by adding the ios.multitasking=true build hint.

The build hint is called "multitasking", because iOS' split-screen and multi-tasking feature requires that the app uses a launch storyboard rather than launch images.

Launch Storyboard vs Launch Images

The key benefit of using a launch storyboard right now is that it allows your app to be used in split-screen mode. Storyboards, however, work a little bit differently than launch images. They don’t show a screenshot of the first page of your app. The default Codename One launch storyboard simply shows your app’s icon in the middle of the screen. You can customize the launch screen by providing one or more of the following files in your project’s native/ios directory

  1. Launch.Foreground.png - Will be shown instead of your app’s icon in the center of the screen.

  2. Launch.Background.png - Will fill the background of the screen.

  3. LaunchScreen.storyboard - A custom storyboard developed in Xcode, that will be used instead of the default storyboard.

Make sure to add the ios.multitasking=true build hint, or your launch storyboard will not be used.
Changes to the launch screen will not take effect until the device has been restarted. I.e. If you install your app on a device, then you make changes to the launch screen and update the app, the launch screen won’t change until the device is restarted.

Local Notifications on iOS and Android

Local notifications are similar to push notifications, except that they are initiated locally by the app, rather than remotely. They are useful for communicating information to the user while the app is running in the background, since they manifest themselves as pop-up notifications on supported devices.

To set the notification icon on Android place a 24x24 icon named ic_stat_notify.png under the native/android folder of the app. The icon can be white with transparency areas

Sending Notifications

The process for sending a notification is:

  1. Create a LocalNotification object with the information you want to send in the notification.

  2. Pass the object to Display.scheduleLocalNotification().

Notifications can either be set up as one-time only or as repeating.

Example Sending Notification
LocalNotification n = new LocalNotification();
n.setAlertBody("It's time to take a break and look at me");
n.setAlertTitle("Break Time!");

        System.currentTimeMillis() + 10 * 1000, // fire date/time
        LocalNotification.REPEAT_MINUTE  // Whether to repeat and what frequency

The resulting notification will look like

Resulting notification in iOS
Figure 1. Resulting notification in iOS

Receiving Notifications

The API for receiving/handling local notifications is also similar to push. Your application’s main lifecycle class needs to implement the com.codename1.notifications.LocalNotificationCallback interface which includes a single method:

public void localNotificationReceived(String notificationId)

The notificationId parameter will match the id value of the notification as set using LocalNotification.setId().

Example Receiving Notification
public class BackgroundLocationDemo implements LocalNotificationCallback {

    public void init(Object context) {

    public void start() {


    public void stop() {

    public void destroy() {

    public void localNotificationReceived(String notificationId) {
        System.out.println("Received local notification "+notificationId);
localNotificationReceived() is only called when the user responds to the notification by tapping on the alert. If the user doesn’t click on the notification, then this event handler will never be fired.

Canceling Notifications

Repeating notifications will continue until they are canceled by the app. You can cancel a single notification by calling:


Where notificationId is the string id that was set for the notification using LocalNotification.setId().

Push Notifications

Push notification allows us to send a notification to a device while the application might be in the background. This is important both as a marketing tool and as a basic communications device.

Why Push & Not Polling?

Polling the server or long polling seem like sensible time proven strategies. However, there are many complexities related to that strategy in mobile phones.

The biggest problem is that a polling application will be killed by the OS as it is sent to the background to conserve OS resources. While this might work in some OS’s and some cases this isn’t something you can rely on. E.g. Android 6+ tightened the background process behavior significantly.

The other issue is battery life, new OS’s expose battery wasting applications and as a result might trigger uninstalls. This makes even foreground polling less appealing.

The final issue is networking, polling is problematic when a device is connected via cellular connection and switching towers. Push might have issues as well, but it’s hard to beat the QA/optimization done by Apple/Google.

What Is Push?

If you are new to mobile development then you heard a lot of buzzwords and very little substance. The problem is that iOS and Android have very different ideas of what push is and should be.

For Android push is a communication system that the server can initiate. E.g. the cloud can send any packet of data and the device can process it in rather elaborate ways.

For iOS push is mostly a visual notification triggered by the server to draw attention to new information inside an app.

These don’t sound very different until you realize that in Android you can send/receive a push without the awareness of the end user. In iOS a push notification is displayed to the user, but the app might be unaware of it!

iOS will only deliver the push notification to the app, if it is running or if the user clicked the push notification popup!

Codename One tried to make both OS’s "feel" similar so background push calls act the same in iOS and Android as a result.

You shouldn’t push important data, push is lossy and shouldn’t include a payload that MUST arrive!
Instead use push as a flag to indicate that the server has additional data for the app to fetch

The Push Bureaucracy - Android

To set the push icon place a 24x24 icon named ic_stat_notify.png under the native/android folder of the app. The icon can be white with transparency areas

Android Push goes thru Google servers and to do that we need to register with Google to get keys for server usage.

We need two important values: GCM_SENDER_ID & GCM_SERVER_API_KEY. The former is used in the client and the latter value is used to push from the server code.

To generate these values we need a Google cloud project. We go over the process of generating a cloud project in the Google+ login section here.

To generate those just go to and click pick a platform:

Figure 2. Click "pick a platform"

Select Android App

Figure 3. Select "Android App"
Google introduced support for sending GCM messages to iOS applications, this has nothing to do with the iOS native push we discuss below

Enter the details for the app and the package

Enter the details for the app and the package
Figure 4. Enter the details for the app and the package

Click the Cloud Messaging option then click the Enable Google Cloud Messaging button

Click the
Figure 5. Click the "Cloud Messaging" option then click the "Enable Google Cloud Messaging" button

You should now have the values for both GCM_SENDER_ID & GCM_SERVER_API_KEY as illustrated below. Notice that the sender id is the numeric key whereas the api key is the alpha-numeric key:

You should now have the values for both `GCM_SENDER_ID` & `GCM_SERVER_API_KEY`
Figure 6. You should now have the values for both GCM_SENDER_ID & GCM_SERVER_API_KEY

Now, in your Codename One project, you should add the gcm.sender_id build hint with the value of your GCM_SENDER_ID


gcm.sender_id=<YOUR GCM_SENDER_ID>
The gcm.sender_id build was added after the Codename One 3.6 release. If you are performing a versioned build for 3.6 or earlier, this build hint will be ignored.

The Push Bureaucracy - iOS

Push on iOS is much harder to handle than the Android version, however we simplified this significantly with the certificate wizard.

iOS push needs two additional P12 certificates.

Please notice that these are NOT the signing certificates!
They are completely different certificates that have nothing to do with the build process!

The certificate wizard can generate these additional push certificates and do quite a few other things if you just check this flag in the end of the wizard:

Enable Push in the certificate wizard
Figure 7. Enable Push in the certificate wizard
If you already have signing certificated defined for your app just skip the certificate generation phase (answer no) the rest will work as usual.

You can then install the push certificates locally and use them later on but there is an easier way.

You need to host the push certificates in the cloud so they will be reachable by the push servers, Codename One that for you seamlessly.
Once you go thru the wizard you should get an automated email containing information about push and the location of the push certificates, it should start like this:

iOS Push certificates have been created for your app with bundle ID com.mycompany.myapp.mypushdemo.  Please file this email away for safe keeping as you will need the details about the certificate locations and passwords to use Push successfully in your apps.

Development Push Certificate URL:

Development Push Certificate Password: ssDfdsfer324

Production Push Certificate URL:

Production Push Certificate Password: ssDfdsfer324

The URL’s and passwords are everything that you will need later on to get push working on iOS. Notice that the wizard also performs a couple of other tasks specifically it sets the ios.includePush build hint to true & adds push to the provisioning profile etc.

You can read more about the certificate wizard in the signing section.

The Push Bureaucracy - UWP (Windows 10)

Push on UWP requires only that you register your app in the Windows Store Dashboard. You will then be provided with credentials (Package Security Identifier (SID) and a secret key) that you can use to send push notifications to your app. To begin this process, go to the Windows Dev Center and select "Dashboard".

You can read more about the registering your app in the Windows store here.

Once you have registered your app in the Windows Store, and completed the corresponding setup in Codename One settings (e.g. generated a certificate), you should proceed to configure your app for push notifications.

Navigate to the App overview page for your app inside the Windows store dashboard. Under the "Services" menu (left side), select "Push notifications".

Push notifications menu item in Windows Store dashboard
Figure 8. Push notifications menu item in Windows Store dashboard

Then, select the "WNS/MPNS" option that appears in the left menu under "Push notifications"

WNS menu item in Windows Store dashboard
Figure 9. WNS menu item in Windows Store dashboard

This will bring you to a page with information about WNS push notifications. You’ll be interested in the paragraph shown here:

Live services link
Figure 10. Live services link

Click on the "Live Services Site" link.

You’ll be prompted to log in using your Windows Store account. Then you’ll be taken to a page that contains the push credentials that you can use for sending push messages to your app. You’ll be interested in two values:

Package SID. (It will be of the form "ms-app://XXXXXXXXXXX…​")

WNS Package SID
Figure 11. WNS Package SID

Client Secret. This will be listed in a section called "Application Secrets"

WNS Client secret
Figure 12. WNS Client secret

You will use these two values for sending push notifications to your app.

Microsoft provides full instructions on setting up WNS notifications here but much of this is not relevant for Codename One apps. For Codename One apps, one need only obtain Package Security ID and client secret values for the app.

The Push Bureaucracy - Javascript

Codename One apps support push in browsers that implement the Web Push API. At time of writing, this list includes:

  • Firefox (Version 50)

  • Chrome (Version 49)

  • Opera (Version 42)

  • Chrome for Android (Version 56)

Push support is currently under development in MS Edge, so should also be available soon.

Firefox doesn’t require any special setup for Push. If your main class implements the PushCallback interface, it should just work.

Chrome uses GCM for its push notifications - the same system that Android uses. The directions for setting up a GCM account are the same as provided here, and you can reuse the same GCM_SENDER_ID and GCM_SERVER_KEY values. You need to add the gcm.sender_id build hint so that the GCM_SENDER_ID will be added to the app’s manifest file:



Push support requires that your app be served over https with a valid SSL certificate. It will not work with the "preview" version of your app. You’ll need to download the .zip or .war file and host the file on your own site - with a valid SSL certificate.

Push Client Code

Push has two distinct pieces, the device that receives the push notification (the client) and the code that sends the push notification (either another device or more often the server code).

The following code shows a simple push test client application, we go over the significant pieces below:

public class PushDemo implements PushCallback { (1)
    private Form current;
    private Resources theme;

    private static final String MY_SERVER_URL = "https://.../"; (2)

    public void init(Object context) {
        theme = UIManager.initFirstTheme("/theme");

    public void start() {
        if(current != null){
        Form hi = new Form("Push Test");
        Display.getInstance().callSerially(() ->  Display.getInstance().registerPush()); (3);

    public void stop() {
        current = Display.getInstance().getCurrent();
        if(current instanceof Dialog) {
            current = Display.getInstance().getCurrent();

    public void destroy() {

    public void push(String value) {"Received Push", value, "OK", null);  (4)

    public void registeredForPush(String deviceId) {
        // IMPORTANT: Notice that Push.getPushKey() != deviceId !!!
        ConnectionRequest con = new ConnectionRequest(MY_SERVER_URL, true);  (5)
        con.addArgument("pushKey", Push.getPushKey());

    public void pushRegistrationError(String error, int errorCode) {"Push Error", "" + error, "OK", null);
1 A client must implement the PushCallback interface in the main class of the application (the one with the callback methods)!
2 This sample requires a server that will accept the device id. Push is challenging without some central repository that will collect device ID’s from the clients
3 We register push every time we start the application, this is expected behavior since push details might change.
Notice that we wrap the call in a callSerially, this provides the first Form with time to appear. This is important as the user can be prompted for permissions at which point you wouldn’t want that prompt to show on top of a blank screen.
It’s also important to define the gcm.sender_id build hint for this method to work properly.
4 This method is invoked when a push message is received, it can be invoked multiple times for some cases
5 After registration push might still not be valid, it is only valid once this method is invoked. While it’s not essential to register in the server at this point, it’s probably what you should do.

Sending Push Messages

You can send a push message in many ways e.g. from another device or any type of server but there are some values that you will need regardless of the way in which you send the push message.

private static final String PUSH_TOKEN = "********-****-****-****-*************";

The push token is a unique "key" that you can use to send push thru your Codename One account. It allows you to send push messages without placing your Codename One email or password into your source files.

You can get it by going to the Codename One build server dashboard at and selecting the Account tab.

The token should appear at the bottom as such:

Push Token from the build server
Figure 13. Push Token from the build server

The instructions for extracting the API key for Google are listed above.

private static final String GCM_SERVER_API_KEY = "******************-********************";

The instructions for extracting the SID and Client Secret for Windows are listed above.

private static final String WNS_SID = "ms-app://**************************************";
private static final String WNS_CLIENT_SECRET = "*************************";

When sending push to iOS devices we have two modes: - Production - Distribution

This allows you to debug the push related functionality without risking the possibility of sending a push into a production app. Its important to send the values to the right server during development/production.

private static final boolean ITUNES_PRODUCTION_PUSH = false;

iOS needs a certificate in order to send a push, this allows you to prove to Apples push servers that you are who you claim to be (the author of the app).

These are not the signing certificates and are completely separate from them!

You can obtain these two certificates (for development/appstore) via the certificate wizard as explained above.

private static final String ITUNES_PRODUCTION_PUSH_CERT = "";
private static final String ITUNES_PRODUCTION_PUSH_CERT_PASSWORD = "ProdPassword";
private static final String ITUNES_DEVELOPMENT_PUSH_CERT = "";
private static final String ITUNES_DEVELOPMENT_PUSH_CERT_PASSWORD = "DevPassword";
Sending a Push Message From Codename One

While normally sending a push message to a device should involve a server code there might be cases (e.g. instant messaging/social) where initiating a push from one client to another makes sense.

To simplify these use cases we added the Push API. To use the Push API you need the device key of the destination device to which you want to send the message. You can get that value from the Push.getPushKey() method. Notice that you need that value from the destination device and not the local device!

To send a message to another device just use:

new Push(PUSH_TOKEN, "Hello World", deviceKey)
    .apnsAuth(cert, pass, ITUNES_PRODUCTION_PUSH)

The "builder" style API used in the above sample was added post Codename One 3.6 to facilitate the addition of new Push services. If you are building against Codename one 3.6 or earlier, you should use the static Push.sendPushMessage() instead as shown below:

Push.sendPushMessage(PUSH_TOKEN, "Hello World",
         ITUNES_PRODUCTION_PUSH, GCM_SERVER_API_KEY, cert, pass, 1, deviceKey));

This will send the push message "Hello World" to the device with the key deviceKey. The 1 argument represents the standard push message type, we discuss push message types below.

Sending Push Message From A Java or Generic Server

Sending a push message from the server is a more elaborate affair and might require sending push messages to many devices in a single batch.

We can send a push message as an HTTP POST request to That URL accepts the following arguments:

  • token - your developer token to identify the account sending the push - PUSH_TOKEN

  • device - one or more device keys to send the push to. You can send push to up to 500 devices with a single request -

  • type - the message type identical to the old set of supported types in the old push servers

  • body - the body of the message

  • auth - the Google push auth key - GCM_SERVER_API_KEY (also used for sending to Chrome Javascript Apps)

  • production - true/false whether to push to production or sandbox environment in iOS - ITUNES_PRODUCTION_PUSH

  • certPassword - password for the push certificate in iOS push - ITUNES_DEVELOPMENT_PUSH_CERT_PASSWORD or ITUNES_PRODUCTION_PUSH_CERT_PASSWORD

  • cert - http or https URL containing the push certificate for an iOS push - ITUNES_DEVELOPMENT_PUSH_CERT or ITUNES_PRODUCTION_PUSH_CERT

  • sid - The package security ID (SID) for UWP apps.

  • client_secret - The client secret for UWP apps.

We can thus send a push from Java EE using code like this:

HttpURLConnection connection = (HttpURLConnection)new URL("").openConnection();
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
String query = "token="  + PUSH_TOKEN +
    "&device=" + URLEncoder.encode(deviceId1, "UTF-8") +
    "&device=" + URLEncoder.encode(deviceId2, "UTF-8") +
    "&device=" + URLEncoder.encode(deviceId3, "UTF-8") +
    "&type=1" +
    "&auth=" + URLEncoder.encode(GCM_SERVER_API_KEY, "UTF-8") +
    "&certPassword=" + URLEncoder.encode(pass, "UTF-8") +
    "&cert=" + URLEncoder.encode(cert, "UTF-8") +
    "&body=" + URLEncoder.encode(MESSAGE_BODY, "UTF-8") +
    "&production=" + ITUNES_PRODUCTION_PUSH +
    "&sid=" + URLEncoder.encode(WNS_SID, "UTF-8") +
    "&client_secret=" + URLEncoder.encode(WNS_CLIENT_SECRET, "UTF-8");
try (OutputStream output = connection.getOutputStream()) {
int c = connection.getResponseCode();
// read response JSON

Notice that you can send a push to 500 devices. To send in larger batches you need to split the push requests into 500 device batches.

Server JSON Responses

The push servers send responses in JSON form. It’s crucial to parse and manage those as they might contain important information.

If there is an error that isn’t fatal such as quota exceeded etc. you will get an error message like this:

{"error":"Error message"}

A normal response, will be an array with results:

   {"id"="deviceId","status"="error","message"="Invalid Device ID"},
   {"id"="cn1-gcm-nativegcmkey","status"="updateId", "newId"="cn1-gcm-newgcmkey"},
   {"id"="cn1-gcm-errorkey","status"="error","message"="Server error message"},

There are several things to notice in the responses above:

  • If the response contains status=updateId it means that the GCM server wants you to update the device id to a new device id. You should do that in the database and avoid sending pushes to the old key

  • iOS doesn’t acknowledge device receipt but it does send a status=inactive result which you should use to remove the device from the list of devices

APNS (Apple’s push service) returns uppercase key results. This means that code for managing the keys in your database must be case insensitive
Apple doesn’t always send back a result for a device being inactive and might fail silently
Various Types of Push Messages

The type argument when sending a push exposes many OS specific capabilities.

Notice that on iOS push messages will only trigger the push method if the app is in the foreground or if the user explicitly clicked the message!
  • 0, 1 - The default push types, they work everywhere and present the string as the push alert to the user

  • 2 - hidden, none visual push. This won’t show any visual indicator on any OS!
    In Android this will trigger the push(String) call with the message body. In iOS this will only happen if the application is in the foreground otherwise the push will be lost

  • 3 - 1 + 2 = 3 allows combining a visual push with a non-visual portion. Expects a message in the form: This is what the user won’t see;This is something he will see. E.g. you can bundle a special ID or even a JSON string in the hidden part while including a friendly message in the visual part.
    When active this will trigger the push(String) method twice, once with the visual and once with the hidden data.

  • 4 - Allows splitting a visual push request based on the format title;body to provide better visual representation in some OS’s.

  • 5 - Sends a regular push message but doesn’t play a sound when the push arrives

  • 100 - Applicable only to iOS. Allows setting the numeric badge on the icon to the given number. The body of the message must be a number e.g. unread count.

  • 101 - identical to 100 with an added message payload separated with a space. E.g. 30 You have 30 unread messages will set the badge to "30" and present the push notification text of "You have 30 unread messages".

Badging on iOS

The badge number can be set thru code as well, this is useful if you want the badge to represent the unread count within your application.

To do this we have two methods in the Display class: isBadgingSupported() & setBadgeNumber(int). Notice that even if isBadgingSupported will return true, it will not work unless you activate push support!

To truly utilize this you might need to disable the clearing of the badges on startup which you can do with the build hint ios.enableBadgeClear=false.

iOS Beta Testing (Testflight)

Apple provides the ability to distribute beta versions of your application to beta testers using testflight. This allows you to recruit up to 1000 beta testers without the typical UDID limits a typical Apple account has.

This is supported for pro users as part of the crash protection feature.

To take advantage of that capability use the build hint ios.testFlight=true and then submit the app to the store for beta testing. Make sure to use a release build target.

Accessing Insecure URL’s

Due to security exploits Apple blocked some access to insecure URL’s which means that http code that worked before could stop working for you on iOS 9+. This is generally a good move, you should use https and avoid http as much as possible but that’s sometimes impractical especially when working with an internal or debug environment.

You can disable the strict URL checks from Apple by using the venerable ios.plistInject build hint and setting it to:


However, it seems that Apple will reject your app if you just include that and don’t have a good reason.

Using Cocoapods

CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. It has over eighteen thousand libraries and can help you scale your projects elegantly. Cocoapods can be used in your Codename One project to include native iOS libraries without having to go through the hassle of bundling the actual library into your project. Rather than bundling .h and .a files in your ios/native directory, you can specify which "pods" your app uses via the ios.pods build hint. (There are other build hints also if you need more advanced features).


Include the AFNetworking library in your app:


Include the AFNetworking version 3.0.x library in your app:

ios.pods=AFNetworking ~> 3.0

For full versioning syntax specifying pods see the Podfile spec for the "pod" directive.

Including Multiple Pods

Multiple pods can be separated by either commas or semi-colons in the value of the ios.pods build hint. E.g. To include GoogleMaps and AFNetworking, you could:


Or specifying versions:

ios.pods=AFNetworking ~> 3.0,GoogleMaps

ios.pods.platform : The minimum platform to target. In some cases, Cocoapods require functionality that is not in older version of iOS. For example, the GoogleMaps pod requires iOS 7.0 or higher, so you would need to add the ios.pods.platform=7.0 build hint.

ios.pods.sources : Some pods require that you specify a URL for the source of the pod spec. This may be optional if the spec is hosted in the central CocoaPods source (

Converting PodFile To Build Hints

Most documentation for Cocoapods "pods" provide instructions on what you need to add to your Xcode project’s PodFile. Here is an example from the GoogleMaps cocoapod to show you how a PodFile can be converted into equivalent build hints in a Codename One project.

The GoogleMaps cocoapod directs you to add the following to your PodFile:

source ''
platform :ios, '7.0'
pod 'GoogleMaps'

This would translate to the following build hints in your Codename One project:


(Note that the ios.pods.sources directive is optional).

1. Apple provided another trick with XIB files starting with iOS 8 but that doesn’t apply to games or Codename One. It has its own set of problems
2. slightly larger screen and different aspect ratio