Getting Started

Invoking Native Code

Include in Your Project



Real-World Examples

Using Native UI







Styling Native Controls

Working with Images

Native UI Layout



Writing Platform-Specific Code


UI Framework Reference

Layout Panels



Platform Helpers



Troubleshooting Errors


Your app can navigate from the page hosting the Cordova WebView to additional all-native pages (and back). These pages can be constructed programmatically in JavaScript, or they can be defined in markup. You have three markup options:

  • Using Android XML. (This only works on Android.)
  • Using a .xib file created from Xcode’s Interface Builder. (This only works on iOS.)
  • Using a XAML file. (This works everywhere.)

When using XAML, you gain the option of using elements from the cross-platform UI framework in addition to (or instead of) raw platform-specific elements.

If your target page is defined in markup, you can use a hyperlink:

<a href="native://page.xaml">
  Go to an all-native page
<a href="android://page.xml">
  Go to an Android XML page
<a href="ios://page.xib">
  Go to an Interface Builder page

Clicking the hyperlink triggers a native navigation, complete with a purely-native animated transition. (On Android, the new content opens in a child activity. On iOS, the new content opens in a new view controller hosted inside a navigation controller.)

The original page with the Cordova WebView remains intact, and the WebView’s internal history remains unaffected. You can navigate back to it with the ace.goBack() API. If you use XAML markup, this can even be attached inline:

<Button ace:On.Click="ace.goBack()">Back</Button>

If your target page is defined in markup, you can also change the document’s location in JavaScript:

// Three options:
document.location.href = "native://page.xaml";
document.location.href = "android://page.xml";
document.location.href = "ios://page.xib";

This behaves just like following a hyperlink.

You can also use a navigate API, which enables you to navigate to markup or any UI object constructed programmatically:

Navigate to a markup file:

// Three options:

Navigate to an arbitrary UI object:

// Navigate to a Page constructed dynamically:
var page = new ace.Page();
// You aren't required to use a Page object:
var button = new ace.Button();

Notice that you’re not required to use a Page object. (But Page is useful if you want to show app bars or control the navigation bar.)

You don’t need to use the cross-platform UI framework, either. Here’s an example that navigates to a raw iOS control, which occupies the whole screen upon navigation:

if (ace.platform == "iOS") {
    // Create a UISegmentedControl
    var uiSegmentedControl = new ace.NativeObject("UISegmentedControl");

    // Add two segments
    uiSegmentedControl.invoke("insertSegmentWithTitle:atIndex:animated:", "One", 0, false);
    uiSegmentedControl.invoke("insertSegmentWithTitle:atIndex:animated:", "Two", 1, false);

    // Select the last segment
    uiSegmentedControl.invoke("setSelectedSegmentIndex", 1);

    // Navigate to the single control
        // Just so we have a way to get back:
        function () { ace.Frame.showNavigationBar(); },
        function () { ace.Frame.hideNavigationBar(); });

Here’s a similar example, but with raw Android controls constructed entirely in JavaScript (no Android XML):

Click here to expand example

And here’s a complete example of navigating to cross-platform UI constructed entirely in JavaScript (no XAML):

Click here to expand example

Interacting with the New Native Content

A key feature of the navigate API, compared to the other navigation approaches, is that it returns the root UI object that you just navigated to. This enables you to manipulate the UI, attach event handlers, and so on.

ace.navigate("native://page.xaml", function (root) {
    // Navigation done
ace.navigate("native://page.xaml", function (root) {
    // Attach event handler
    root.doneButton.addEventListener("click", function() { ... });

Retrieving Subelements

If you’re using XAML markup, you can mark elements with a Name attribute. You can then access elements by name directly from the root element, e.g.:

ace.navigate("native://page.xaml", function (root) {
    // There is an element with Name="doneButton"
    root.doneButton.addEventListener("click", function() { ... });

Or, from any element in the same scope (not just the root), you can use a findName API:

ace.navigate("native://page.xaml", function (root) {
    // There is an element with Name="doneButton"
    root.findName("doneButton").addEventListener("click", function() { ... });

Whether you get a cross-platform UI object from XAML or programmatically, you can retrieve sub-objects by name with the findName API.

If you’re using Android XML, you can set ids as you normally would, and programmatically leverage those ids in JavaScript the same way you would in Java.

To go back from a native navigation, call ace.goBack().

If you use the navigate API, you can pass an extra callback that acts like a “navigating away from” event:

ace.navigate("native://page.xaml", function (root) {
    // Navigated to
    root.doneButton.addEventListener("click", function() { ... });
}, function (root) {
    // Navigating away
    root.doneButton.removeEventListener("click", function() { ... });

Global Navigation Events

You can handle global Navigating and Navigated events, which is especially useful when navigation is done via hyperlinks rather than the navigate API:

ace.addEventListener("navigating", function (oldContent, newContent) {
  console.log("NAVIGATING: " + oldContent + " -> " + newContent);

ace.addEventListener("navigated", function (root, url) {
  // There's no url in the case of navigating to a live object
  console.log("NAVIGATED: " + url);

Controlling the Navigation Bar

Frame has exposes showNavigationBar and hideNavigationBar APIs. A previous example demonstrated these in conjunction with the navigate API callbacks:

    // Just so we have a way to get back:
    function () { ace.Frame.showNavigationBar(); },
    function () { ace.Frame.hideNavigationBar(); });