An enaml-native app is organized similar to a react-native app. When you create a new app with the enaml-native-cli. The project directory consists of the basic structure:
android/ #: Android project using gradle ios/ #: iOS xcode project with cocoapods src/ #: Python source for your app venv/ #: Symlink to the conda env for enaml-native packages and cross compiled libraries environment.yml #: Project config
Your actual apps are in the
ios folders. The build scripts are configured to run enaml-native commands that build and package your python source files as required for the app based on the dependencies.
src folder contains the python code that the build system will copy into the root of your python app. It does a recursive copy so any files, folders, subfolders, and files within will be added into your will be available on the actual app.
Note: The location of the root folder of these files can be obtained from the
environment.yml file is your project config. It is a conda environment file with some extra sections. If you open it you see the following.
# Name name: <app name> bundle_id: com.example.app # Channels to look for any specific libraries channels: - local - codelv # App dependencies to be installed dependencies: - python=3.10 - pip - pip-tornado - android-python * py310* - enaml-native - pip: - enaml-native-cli # Exclude unused packages and libs using glob patterns here. # Only the ones required by enaml-native are left in by default. # If you need to use a module (ex json) then remove lib._json.so # from this list so it does not get exlcuded. You can also add specific # exclusions under ios and android. excluded: # Packages - idlelib - ensurepip - distutils - lib2to3 - pydoc_data - hotshot - turtledemo - venv - site-packages/enaml/qt - site-packages/enaml/workbench - site-packages/enaml/*lib - site-packages/enaml/scint* # ... # Android specific configuration android: sdk: /home/jrm/Android/Sdk/ ndk: /home/jrm/Android/Sdk/ndk/24.0.7956693 targets: - x86_64 - x86 - arm - arm64 excluded: - lib._ctypes.so # iOS specific configuration ios: targets: - iphoneos - iphonesimulator
As you can see there's a few shared properties such as
version which are
sources, and separate configs for
Each platform config (
The rest are specfic for the platform.
As you may have guessed,
targets defines which platforms to compile python and extensions modules
dependencies is a list of requirements to install on the app.
Note: All dependencies must have a package made specifically for using on android or ios.
excluded list is a list of patterns
that you can use to exclude unused python modules from your app to reduce the app size.
For android there's
ndk which are the paths used for building. You MUST update these to
point to wherever your SDK and NDK are installed.
For ios there's the
project which defines the name of the
<project>.xcworkspace that will be
It's easiest to just make release builds using android-studio or xcode. It will prompt you to
do any configuration necessary.
androidfolder in android-studio
Build -> Generate signed APK
Once that is done you can then do release builds with the enaml-native cli using
enaml-native build-android --release or
enaml-native build-ios --release.
--release flag tells it to do a release build (it's debug by default).
For help see the documentation for each platform, enaml-native does nothing special here.
Since apps must include both the python interpreter (as native libraries) and all the python
and app sources, the installed apps can get large if care is not taken to remove unused modules.
excluded list can be used to remove unnecessary packages and files from the python build (located under
build/python/python.tar.gz in your app
directory). Add glob patterns to tell the build system to ignore copying files into the python bundle.
excluded: # Packages - idlelib - ensurepip - distutils - lib2to3 - pydoc_data - hotshot - turtledemo - venv - site-packages/enaml/qt - site-packages/enaml/workbench - site-packages/enaml/*lib - site-packages/enaml/scint*
You can also use the apk analyzer in android-studio which nicely graphs which files are using space
within an apk (it even shows within the python.tar.gz!) so use that as well!
With the release of the enaml-native-cli it is now
possible to create a single pip package that includes
ios libraries along
with the python source to use them. These are called
enaml native packages for lack of a better
name and can be installed with either
pip or the
enaml-native is growing and apps will typically want to only include the native
dependencies they need. The project was redesigned and broken down into smaller installable
EnamlPackages each containing their own with separate native and python requirements.
These packages will allow any user to create, maintain, and share their own versions of
pluggable libraries as needed. There is no need to have your code merged in by some "core" group
The concept of the package is pretty simple.
venvusing either pip or the cli
A package is simply a directory with the following subdirectories and files.
android/ #: Android library using gradle (if applicable) ios/ #: iOS xcode library using cocoapods (if applicable) src/ #: Python source for your app src/setup.py #: Setupfile for your package's source (this is what is installed on the app) setup.py #: Pip setup file for the enaml-native package
To make an "enaml-package" that follows this format use:
enaml-native init-package <some-package-name> <destination/folder>
If your package requires native dependencies (ex the
requires native android
GoogleMaps) the android or ios project can be "linked"
to your library when its installed by the user. This is done by the
enaml-native link command.
"Linking" is automatically adding the necessary changes to the users android and ios projects
(such as adding your library as a project to compile build.gradle) so they can simply install
and use it right away. This makes it easier for new users to quickly get started with your code
without having to read through how to configure it all manually.
An entry point
enaml_native_linker was added to the cli that lets you define a custom function
to link the users project where required.
Note: Currently only linking has been implemented for android (you can use your an entry point)
Unlinking is the reverse of linking and unlinking our package from a users project should remove
any changes made during linking. This is required so upgrading or switching dependencies is
seamless and error free.
You can open the
android folder in Android studio and it will load like any normal android project.
This way you can easily modify any native java code and get all the highlighting and error
checking, etc. all android documentation applies here. The project uses the gradle build system.
enaml-native hooks itself into the gradle build process to include your python source and libraries.
This hook is in android/build.grade.
It simply runs
enaml-native bundle-assets which packages all the pre-compiled packages along with your apps src code into a file
python.tar.gz and copies it to
enaml-native builds python and any dependencies that have compiled components (c, c++, cython)
These compiled modules are simply added to your apps environment file so they are included in the bundling process.
At runtime extension libraries imported using a custom import hook, see import_hooks.py .
To add custom libraries:
You can see there's a few already being used. Once a library is added with gradle you can use it
via making a wrapper Proxy and Toolkit component (see the
native component docs) .
Note: iOS is not yet supported
You can open the project.xcworkspace within the
ios folder in xcode and work in your app normally. All iOS
docs apply here.
To add custom libraries:
You can see there's a few already being used. Once a library is added with cocopods you can use it via making
a wrapper Proxy and Toolkit component (see the native component docs) .
That's all for now! Thanks for reading! Please suggest more docs if something is confusing.