Talk to your Tabris App

If you’re a seasoned Tabris developer you’re likely familiar with the helpful shortcuts built into the Tabris CLI. After all, every time a Tabris app is side-loaded you get this message:

What you may not know is that you can do a lot more with the CLI if you enable interactive mode. To do so, simply add the --interactive (or -i) option to the tabris serve command. Assuming you use npm start to sideload your app, the package.json script section may look like this:

Now, once connected to a device, you can use the CLI like a regular JavaScript console, like with the node REPL or a browser’s developer tools.
But what can you do with it? All text entered into the console will be evaluated as JavaScript expressions in the context of the global scope of your running Tabris application. Note that this feature requires a constant stable connection to the device. If the prompt becomes unresponsive, try restarting the application and/or the CLI.

There are a few useful objects and functions you can access immediately: console (obviously), tabris, require(), $(), localStorage, secureStorage, cordova, navigator and all namespaces contributed by UMD modules. If you want to see exactly what is available, type Reflect.ownKeys(global).join().

console

For simple expressions you will not need the console since the return value is printed out anyway. You can use the dirxml method to print out a summary of the UI state or localStorage, but that’s the same as using the CTRL + P shortcut. However, if your command results in a promise you may pass it the console.log function to see the result. See “Asynchronous commands” below.

tabris

Via the tabris object you have access to all the exports of the 'tabris' module, for example contentView, drawer, app, device and fs. It will be used in several examples below.

require

The require function allows you to obtain the exports of any module in your application. However, this only works if you do not use a packager like Webpack. Also, if you use TypeScript consider that the runtime location of a module is in the dist/ directory, not src/. If you want to see what exactly is available, here is a line to view the internal module registry of Tabris:

Keep in mind that this is not an official API and may not work in future versions.

$

The $() function gets you access to arbirary widget objects that are currently in your UI tree. Given a selector string it searches contentView for matches. So if you have a custom component called MainView attached to contentView, and you want to inspect its model property, you could do it like this:

However, keep in mind that $(selector) respects component encapsulation and it may therefore not be possible to match every widget in contentView. It also doesn’t search the drawer, and in some cases a widget may not have an id that makes it easy to match just the desired instance. In all of those cases print out the UI tree and use the displayed cid to obtain the instance. Do not put the cid in quotes, it’s a number and not a string.

localStorage and secureStorage

The CLI shortcuts already allow you to print, save, restore and clear the entire content of localStorage. However, with direct access in the console you can be more precise and read, set or delete individual keys as you would in code.

cordova and navigator

Tabris apps always include the runtime parts of cordova responsible for loading cordova/phonegap compatible plug-ins. Some of these plug-ins publish API on either the navigator and/or cordova global objects. You can also see what plug-ins are loaded by typing:

Publishing other objects

Likely, your application’s most interesting objects aren’t easily acessible via the interactive console. After all, the entire point of a module system (such as commonJS used by tabris) is that you don’t have tons of variables floating around in the global scope where they can easily clash. But for debugging purposes you may want to put some of your key values in global scope temporarily. Let’s say you have an object that provides access to data that is used across your application, and the state of which may be useful to inspect via the CLI. Maybe it looks like this:

We want to put this object in global scope, but only during development. A good way to do this is to check if the developer toolbar is visible:

Now you can check the state of people at runtime:

It can be a cleaner alternative to putting “console.log()” commands all around your code.

Custom commands

There is even more you can do with this approach. Let’s say you have a longer command you regularily use:

Of course you can take advantage of the built-in history feature of the CLI using the up and down arrow keys to bring back previously entered commands, but if it doesn’t happen to be within the last few, that’s not very convinient either. Instead you could add this piece of code somewhere in your app:

Now entering urls returns exactly the same value as typing the entire line.

Asynchronous commands

The interactive console does not support the await keyword. Therefore you need to deal with asynchroneous APIs (those returning promises) directly. For example, listing files in the on-device application directory could look like this:

This is rather long, yet the output is not very pretty. Therefore this is a good candidate for a custom command:

Result:

Bonus: Listing all application files

This custom command will list all application files recursively, including the file size:

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published.