Enaml Native

A framework for building native Android and iOS apps in python using native widgets.


code

Apps are declarative

Apps are written declaratively using enaml. It's like JSX, just with python and no "flux" pattern is required. All of the features of enaml can be used with enaml-native, such as automatic data synchronization, conditional and looper patterns, and extensions.

android

Use native libraries

Apps use native widgets and can easily access native libraries by simply defining a small wrapper. The apps look and feel native because they are. You can define your own loading screen's and adding new libraries is extremely easy using gradle and cocoapods.

devices

Developer friendly

Time saving features such as live code reloading and popup error messages are built in. Code can be reloaded over wifi, with no need to plugin and rebuild the app for every change. Also it's just python, no knowledge of Java or Objective-C is required to build an app.

Why use enaml? Watch the short video that explains why enaml is great for building UI's.

Android Demo

You can try it yourself on the play store: Enaml-Native Demo

Swipe to change screens.

Note: Loading is slower here than on a real device.
Example App

A simple two page app with a toolbar.

from enamlnative.core.api import *
from enamlnative.widgets.api import *

enamldef ContentView(Flexbox):
    flex_direction = "column"
    Toolbar:
        title = "Enaml-Native"
        background_color = "#6CA6CD"
        layout_height = "100"
    ViewPager:
        PagerFragment:
            TextView:
                text = "Python powered native apps!"
        PagerFragment:
            TextView:
                text = "A multi screen app in < 20 lines? Yep!"
Native access

An actual working example using the Android LocationManager for GPS updates.

from enamlnative.widgets.api import *
from enamlnative.android.app import AndroidApplication
from enamlnative.android.bridge import *

#: Define our class
class LocationManager(JavaBridgeObject):
    instance = None
    listener = None
    __nativeclass__ = set_default('android.location.LocationManager')
    requestLocationUpdates = JavaMethod('java.lang.String', 'long', 'float',
                                        'android.location.LocationListener')

    class LocationListener(JavaProxy):
        __nativeclass__ = set_default('android.location.LocationListener')

        onLocationChanged = JavaCallback('android.location.Location')
        onProviderDisabled = JavaCallback('java.lang.String')
        onProviderEnabled = JavaCallback('java.lang.String')
        onStatusChanged = JavaCallback('java.lang.String', 'int', 'android.os.Bundle')

#: Create our listener callback
def on_location_changed(location):
    app = AndroidApplication.instance()
    app.view.text = str(location)
    print(location)

#: Called when loaded
def on_loaded(ref):
    #: Create reference
    lm = LocationManager(__id__=ref)

    #: Create our listener
    ll = LocationManager.LocationListener()

    #: Bind a listener
    ll.onLocationChanged.connect(on_location_changed)

    #: Save a ref
    LocationManager.listener = ll

    #: Request updates from GPS
    lm.requestLocationUpdates("gps", 0, 0, ll)

    #: Safe a ref
    LocationManager.instance = lm

#: Get the service
app = AndroidApplication.instance()
app.get_system_service("location").then(on_loaded)

enamldef ContentView(Flexbox): view:
    alias text: tv.text
    TextView: tv:
        text = "Waiting..."

Supports iOS and Android