Getting Started

Invoking Native Code

Include in Your Project

NativeObject

Platform-Specific

Real-World Examples

Using Native UI

Docking

Overlaying

Fullscreen

Widget

Floating

Navigation

Styling Native Controls

Working with Images

Native UI Layout

Panels

Properties

Writing Platform-Specific Code

Security

UI Framework Reference

Layout Panels

Controls

Ace

Platform Helpers

NativeObject

Examples

Troubleshooting Errors

Invoking Native Code

Be sure to check out the sample code to see this in action

You can invoke native code from JavaScript using NativeObject, whether it’s platform APIs, third-party code, or your own custom native code. For the latter two cases, you need to include the code in your project.

Include Native Code in Your Project

Cordova apps with Ace installed can include any native code and resources in the project’s native folder. Code and resources placed here gets compiled into your project:

Using NativeObject to Invoke Native Code

Here are the ways to do it:

// Instantiate a native class with its default constructor
var obj = new ace.NativeObject("NameOfNativeClass");

// Instantiate a native class with a parameterized constructor
var obj = new ace.NativeObject("NameOfNativeClass", 5);

// Invoke an instance method
obj.invoke("Method1");

// Invoke an instance method with two parameters
obj.invoke("Method2", 12, 24);

// Invoke an instance method and retrieve its return value
obj.invoke("Method1", function(returnValue) { /* ... */ });

// Invoke an instance method with one parameter and retrieve its return value
obj.invoke("Method1", "param", function(returnValue) { /* ... */ });

// Get an instance field value (doesn't apply to iOS)
obj.getField("Field1", function(value) { /* ... */ });

// Set an instance field value (doesn't apply to iOS)
obj.setField("Field1", 7);

// Invoke a static method
ace.NativeObject.invoke("NameOfNativeClass", "Method1");

// Invoke a static method with two parameters
ace.NativeObject.invoke("NameOfNativeClass", "Method2", 12, 24);

// Invoke a static method and retrieve its return value
ace.NativeObject.invoke("NameOfNativeClass", "Method1", function(returnValue) { /* ... */ });

// Invoke a static method with one parameter and retrieve its return value
ace.NativeObject.invoke("NameOfNativeClass", "Method1", "param", function(returnValue) { /* ... */ });

// Get a static field value (doesn't apply to iOS)
ace.NativeObject.getField("NameOfNativeClass", "Field1", function(value) { /* ... */ });

// Set a static field value (doesn't apply to iOS)
ace.NativeObject.setField("NameOfNativeClass", "Field1", 7);


Writing Platform-Specific Code

When you directly invoke native APIs, the code you write will be platform-specific. See this topic for details and strategies for writing platform-specific code.


Real-World Examples


Showing the battery level on iOS and Android

function invokeBattery() {
    if (ace.platform == "iOS") {
        // Objective-C code:
        // UIDevice* device = [UIDevice currentDevice];
        // [device setBatteryMonitoringEnabled:true];
        // double capacity = [device batteryLevel] * 100;

        // Invoke a static currentDevice method on UIDevice
        ace.NativeObject.invoke("UIDevice", "currentDevice", function (device) {
            // On the returned instance, call an instance method with no return value
            device.invoke("setBatteryMonitoringEnabled", true);
            // Call another instance method that returns a double
            device.invoke("batteryLevel", function (level) {
                alert("capacity = " + (level * 100) + "%");
            });
        });
    }
    else if (ace.platform == "Android") {
        // Java code:
        // BatteryManager batteryManager = getContext().getSystemService(Context.BATTERY_SERVICE);
        // int capacity = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);

        // Get the value of the string constant Context.BATTERY_SERVICE
        ace.NativeObject.getField("android.content.Context", "BATTERY_SERVICE", function (constant) {
            // Invoke an instance method on the Android context object to get a BatteryManager instance
            ace.android.getContext().invoke("getSystemService", constant, function (batteryManager) {
                ace.NativeObject.getField("android.os.BatteryManager", "BATTERY_PROPERTY_CAPACITY", function (constant) {
                    batteryManager.invoke("getIntProperty", constant, function (value) {
                        alert("capacity = " + value + "%");
                    });
                });
            });
        });
    }
}


Showing the current screen’s width, height, and DPI on Android

if (ace.platform == "Android") {
    //
    // WindowManager windowManager = getContext().getSystemService(Context.WINDOW_SERVICE);
    // Display display = windowManager.getDefaultDisplay();
    // Display metrics = new DisplayMetrics();
    // display.getMetrics(metrics);
    // int dpi = metrics.densityDpi;
    // int w = metrics.widthPixels;
    // int h = metrics.heightPixels;
    //
    ace.NativeObject.getField("android.content.Context", "WINDOW_SERVICE", function (constant) {
        ace.android.getContext().invoke("getSystemService", constant, function (windowManager) {
            windowManager.invoke("getDefaultDisplay", function (display) {
                var metrics = new ace.NativeObject("android.util.DisplayMetrics");
                display.invoke("getMetrics", metrics);
                metrics.getField("densityDpi", function (dpi) {
                    metrics.getField("widthPixels", function (w) {
                        metrics.getField("heightPixels", function (h) {
                            alert(dpi + " DPI, and " + w + "px by " + h + "px");
                        });
                    });
                });
            });
        });
    });
}


Showing device info on iOS

if (ace.platform == "iOS") {
    //
    // UIDevice* device = [UIDevice currentDevice];
    // NSString* name = [device name];
    // NSString* systemName = [device systemName];
    // NSString* systemVersion = [device systemVersion];
    //
    ace.NativeObject.invoke("UIDevice", "currentDevice", function (device) {
        device.invoke("name", function (value) { alert("name = " + value) });
        device.invoke("systemName", function (value) { alert("systemName = " + value) });
        device.invoke("systemVersion", function (value) { alert("systemVersion = " + value) });
    });
}


Vibrating in a pattern on Android

You must add <uses-permission android:name=”android.permission.VIBRATE” /> to your AndroidManifest.xml for this to work.

if (ace.platform == "Android") {

    var pattern = [0, 500, 110, 500, 110, 450, 110, 200, 110, 170, 40, 450, 110, 200, 110, 170, 40, 500];

    // The shorter way:
    //
    // Vibrator vibrator = getContext().getSystemService("vibrator");
    // vibrator.vibrate(pattern, -1);
    //
    ace.android.getContext().invoke("getSystemService", "vibrator", function (vibrator) {
        vibrator.invoke("vibrate", pattern, -1);
    });

    // The longer way:
    //
    // Vibrator vibrator = getContext().getSystemService(Context.VIBRATOR_SERVICE);
    // vibrator.vibrate(pattern, -1);
    //
    ace.NativeObject.getField("android.content.Context", "VIBRATOR_SERVICE", function (constant) {
        ace.android.getContext().invoke("getSystemService", constant, function (vibrator) {
            vibrator.invoke("vibrate", pattern, -1);
        });
    });
}


Having fun with proximity monitoring on iOS

if (ace.platform == "iOS") {
    //
    // UIDevice* device = [UIDevice currentDevice];
    // [device setProximityMonitoringEnabled:true];
    // BOOL isClose = [device proximityState];
    //
    ace.NativeObject.invoke("UIDevice", "currentDevice", function (device) {
        if (proximityHandle == null) {
            $("#spotForProximityOutput").html("<h2>Monitoring proximity...</h2>");

            // Turn on proximity monitoring
            device.invoke("setProximityMonitoringEnabled", true);

            // Check the status once a second
            proximityHandle = setInterval(function () {
                device.invoke("proximityState", function (isClose) {
                    if (isClose) {
                        // The user is close
                        $("<h2>CLOSE!</h2>").appendTo($("#spotForProximityOutput"));
                    }
                });
            }, 1000);
        }
        else {
            // Stop checking the status
            clearInterval(proximityHandle);
            proximityHandle = null;

            // Turn off proximity monitoring
            device.invoke("setProximityMonitoringEnabled", false);

            $("<h2>Monitoring stopped.</h2>").appendTo($("#spotForProximityOutput"));
        }
    });
}


Using the Android Palette API to detect colors in an image

For this to work, you must add a reference to the com.android.support:palette-v7 library.

function usePalette() {
    // Set up a spot for showing palette results
    var popup = new ace.Popup();
    popup.setContent(new ace.StackPanel());
    popup.show();

    if (ace.platform == "Android") {
        //
        // AssetManager assetManager = getContext().getAssets();
        // InputStream inputStream = assetManager.open("www/images/poster.jpg");
        // Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
        // Palette.Builder paletteBuilder = Palette.from(bitmap);
        // Palette palette = paletteBuilder.generate();
        // showPaletteButton(...);
        //
        ace.android.getContext().invoke("getAssets", function (assetManager) {
            assetManager.invoke("open", "www/images/poster.jpg", function (inputStream) {
                ace.NativeObject.invoke("android.graphics.BitmapFactory", "decodeStream", inputStream, function (bitmap) {
                    ace.NativeObject.invoke("android.support.v7.graphics.Palette", "from", bitmap, function (paletteBuilder) {
                        paletteBuilder.invoke("generate", function (palette) {
                            showPaletteButton("getVibrantSwatch", palette, popup);
                            showPaletteButton("getMutedSwatch", palette, popup);
                            showPaletteButton("getLightVibrantSwatch", palette, popup);
                            showPaletteButton("getLightMutedSwatch", palette, popup);
                            showPaletteButton("getDarkVibrantSwatch", palette, popup);
                            showPaletteButton("getDarkMutedSwatch", palette, popup);
                        });
                    });
                });
            });
        });
    }
}

function showPaletteButton(methodName, palette, popup) {
    //
    // Swatch swatch = palette.();
    // int color = swatch.getRgb();
    // int textColor = swatch.getBodyTextColor();
    //
    palette.invoke(methodName, function (swatch) {
        if (swatch) {
            swatch.invoke("getRgb", function (color) {
                swatch.invoke("getBodyTextColor", function (textColor) {
                    // Add a button using the two colors
                    var button = new ace.Button();
                    button.setBackground(color);
                    button.setForeground(textColor);
                    button.setContent(methodName);
                    button.addEventListener("click", function () { popup.hide(); });
                    popup.getContent().getChildren().add(button);
                });
            });
        }
    });
}
</pre>