Integrate Tabris.js with existing Android Apps
Tabris.js application can be integrated into other existing Android applications. On the first impression, it can be considered complicated to use Tabris.js along with a native Android app. However, you can easily embed Tabris.js into your native app with a few steps described below.
In this article, we are going to create and integrate a simple Tabris.js app into an example Android app. The Android application contains a button that loads and renders Tabris.js components when clicking on it.
First, create a new Tabris.js project by following the guide here.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const {Button, TextView, contentView} = require('tabris'); new Button({ centerX: true, top: 100, text: 'Show message' }).onSelect(() => { textView.text = 'Tabris.js rocks!'; }).appendTo(contentView); const textView = new TextView({ centerX: true, top: 'prev() 50', font: '24px' }).appendTo(contentView); |
Second, create a simple example Android project and update the activity_main.xml
layout file as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main_container" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#aaaaaa" tools:context=".MainActivity"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="Launch" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <FrameLayout android:id="@+id/fragment_container" android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="16dp" android:background="#eeeeee" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button"/> </androidx.constraintlayout.widget.ConstraintLayout> |
To add Tabris.js dependency to your local build, download the latest Tabris.js Android Cordova platform. Create the environment variable TABRIS_ANDROID_PLATFORM on your operating system and point it to the downloaded platform root directory.
Declare specific maven repositories for jitpack
and tabris
in the project build.gradle
:
1 2 3 4 5 6 7 8 9 10 |
allprojects { repositories { ... maven { url 'https://jitpack.io' } maven { // provides tabris from directory repository url System.getenv("TABRIS_ANDROID_PLATFORM") + "/bin/templates/project/m2repository" } } } |
Add the tabris
and kotlinx-coroutines-android
implementations in the app build.gradle
:
1 2 3 4 5 |
dependencies { implementation 'com.eclipsesource.tabris.android:tabris:3.7.0' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1" ... } |
Append the following source codes to the MainActivity.kt class. This code loads Tabris.js sources from the specified URL or path, renders the result in the TabrisFragment, and appends the fragment to the fragment_container
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
private val projectPath = "http://192.168.1.104:8080" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) findViewById<Button>(R.id.button).setOnClickListener { launch() } } private fun launch() { GlobalScope.launch { BootJsLoader(application) .load(projectPath) .catch { showError(it.message ?: it.toString()) } .collect { withContext(Dispatchers.Main) { handleBoothJsResource(it) } } } } private fun showError(message: String) { Snackbar.make(findViewById(R.id.main_container), message, Snackbar.LENGTH_LONG).show() } private fun handleBoothJsResource(resource: Resource<BootJsResponse>) { when (resource) { is Resource.Success -> showTabrisFragment(resource.data) is Resource.Failure -> showError("${resource.code} - ${resource.message}") else -> Unit } } private fun showTabrisFragment(response: BootJsResponse) { val tabrisFragment = newTabrisFragment(response) supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, tabrisFragment, tabrisFragment::class.java.name) .addToBackStack(null) .commit() } private fun newTabrisFragment(response: BootJsResponse): TabrisFragment { val tabrisFragment = TabrisFragment.newInstance(baseUri = response.baseUri) tabrisFragment.onScopeAvailable { scope -> scope.onClose { action -> println("TabrisFragment.onScopeAvailable: $action") } scope.boot(response.bootScripts) } return tabrisFragment } |
It is recommended to load the JavaScript code from the development server when developing or testing the project. However, you must provide some details in the AndroidManifest.xml
file in order to sideload the Tabris.js sources successfully.
First, make sure you have ACCESS_NETWORK_STATE
and INTERNET
permissions:
1 2 |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> |
Next, apply the usesCleartextTraffic
option to allow plain text network communication (as restricted in Android 9):
1 2 3 4 |
<application ... android:usesCleartextTraffic="true" tools:targetApi="30"> |
Provide the replace
element that prevents theme conflict during sideloading.
1 2 3 |
<application ... tools:replace="android:theme"> |
Now build and run your Android app as usual. Once you click the button, it should load the JavaScript code from the development server and display it.
When you create a release build, I suggest moving essential Tabris.js sources to the assets
folder of the Android project and load them directly from there:
private val projectPath = "file:///android_asset/tabris-js-app"
That is all. Hope this small blog post helped you understand how to properly integrate Tabris.js with an existing Android App.
You can download the complete project from GitHub.
Feedback is welcome!
Want to join the discussion?Feel free to contribute!