JavaScript Samples
The following JavaScript samples are available as examples of how you can use the JavaScript engine:
#!/usr/bin/env js
to ensure the Android
device agent recognizes the script as a JavaScript script.Simple log
Demonstrates simple logging to the console.
#!/usr/bin/env js
mobicontrol.log.info('Hello world!');
Executing a simple command on the device
Enters admin mode on the device.
#!/usr/bin/env js
mobicontrol.agent.enterAdminMode();
Log real-time device information to the console
Logs device battery charge level to the console.
#!/usr/bin/env js
mobicontrol.log.info('The current battery level is: ' + mobicontrol.battery.level);
Conditioning on agent's values
Logs camera permission status.
#!/usr/bin/env js
while (mobicontrol.featureControl.camera.isDisabled()) {
mobicontrol.featureControl.camera.allow();
}
mobicontrol.log.info('Camera feature is allowed');
if loop and string operations
Demonstrates some JavaScript standard features: if loop and string operations.
#!/usr/bin/env js
if (mobicontrol.device.name.startsWith('Headquarters')) {
mobicontrol.featureControl.camera.disable();
}
Arrays
Demonstrates a JavaScript standard feature: arrays.
#!/usr/bin/env js
// Stop clock app if it runs in the foreground
var clockApp = 'clock';
var foregroundActivities = mobicontrol.app.foregroundActivities;
foregroundActivities.forEach(function(activity) {
if (activity.packageName.includes(clockApp)) {
mobicontrol.app.stop(activity.packageName);
}
});
Simple asynchronous callback execution
Installs an app, then starts the app.
#!/usr/bin/env js
// Install an app and start it as soon as it has been installed
mobicontrol.app.install('/sdcard/example.apk', onFinish);
function onFinish(result) {
if (result.isSuccessful) {
mobicontrol.app.start('net.soti.example');
}
}
Complex asynchronous callback execution
Creates an asynchronous callback including an invocation timeout parameter and failure scenario.
#!/usr/bin/env js
mobicontrol.agent.disconnect()
pause(3000)
mobicontrol.agent.connect(onFinish, 3000)
function onFinish(result) {
if (result.isTimedOut) {
mobicontrol.log.info('Timeout')
} else {
mobicontrol.log.info('Failure')
}
if (result.statusCode == mobicontrol.agent.ConnectResult.NO_NETWORK) {
mobicontrol.log.info('No network')
} else {
mobicontrol.log.info(result.statusCode)
}
}
function pause(numberMillis) {
var now = new Date()
var exitTime = now.getTime() + numberMillis
while (true) {
now = new Date()
if (now.getTime() > exitTime)
return;
}
}
Randomize code execution over time
Randomizes device reboots over 30 minutes, so the DS (which might serve up to 100-200K devices) does not become unresponsive.
#!/usr/bin/env js
setTimeout(reboot, Math.random() * 30 * 60 * 1000);
function reboot() {
mobicontrol.device.reboot();
}
Verify agent version
Verifies that the version of the agent is correct.
#!/usr/bin/env js
var CORRECT_VERSION = '14.3.3 Build 1234';
if (mobicontrol.agent.version != CORRECT_VERSION) {
mobicontrol.log.error("The agent has incorrect version: " + mobicontrol.agent.version);
}
Check minimum OS version
Checks the minimum Android operating system version on a device.
#!/usr/bin/env js
var MINIMUM_ANDROID_OS_LEVEL = 26;
if (mobicontrol.os.apiLevel < MINIMUM_ANDROID_OS_LEVEL) {
mobicontrol.log.error("Device must be upgraded to Oreo or higher");
}
Check SIM card status
Checks if a SIM card is inserted in the device.
#!/usr/bin/env js
if (mobicontrol.cellular.signalStrength == null) {
mobicontrol.log.error("SIM card is removed.");
}
Force agent connection
Forces the agent to connect if it is not already online, and provides error messages in case the connection fails.
#!/usr/bin/env js
mobicontrol.agent.connect(onFinish);
function onFinish(result) {
if (result.isSuccessful) {
mobicontrol.log.info('Success');
} else if (result.isTimedOut) {
mobicontrol.log.info('Timeout');
} else {
switch (result.statusCode) {
case mobicontrol.agent.ConnectResult.NO_NETWORK:
mobicontrol.log.info('No available networks');
break;
case mobicontrol.agent.ConnectResult.SERVER_UNREACHABLE:
mobicontrol.log.info('The agent cannot establish network connection to the deployment server');
break;
case mobicontrol.agent.ConnectResult.SERVER_BUSY:
mobicontrol.log.info('The network connection to the deployment server was established, but the server didn't acknowledge connection');
break;
default:
mobicontrol.log.info('Other error occurred: ' + result.statusCode);
}
}
}
Device property check and action
Sends a message to the screen when certain device properties are identified. Here, it is checking for signal strength and suggesting a remedy.
#!/usr/bin/env js
if (mobicontrol.cellular.signalStrength == null) {
mobicontrol.message.createInfoDialog("Check that your SIM card is properly inserted.").show();
}
Request user acknowledgement before action
Sends a custom dialog with multiple options to allow users to control app install time. The package will be pushed to the device, and the pre-install script will check if the app is running in the foreground and if it is, it will ask the user if we can install the app now, in 5 minutes, or in 1 hour.
#!/usr/bin/env js
var FIVE_MINUTES = 5 * 60 * 1000;
var ONE_HOUR = 60 * 60 * 1000;
var buttonLabels = ['Install now', 'Install in 5 minutes', 'Install in 1 hour'];
if (isAppRunningInForeground('com.acme.importantapp')) {
mobicontrol.message.createInfoDialog('Would you like to install ImportantApp?')
.withButtons(buttonLabels[0], buttonLabels[1], buttonLabels[2])
.withCallback(onConfirm).show();
}
function onConfirm(result) {
if (result.buttonIndex != null) {
switch (buttonLabels[result.buttonIndex]) {
case 'Install now':
installImportantPcg();
break;
case 'Install in 5 minutes':
setTimeout(installImportantPcg, FIVE_MINUTES);
break;
case 'Install in 1 hour':
setTimeout(installImportantPcg, ONE_HOUR);
break;
}
}
}
function installImportantPcg() {
// Do nothing - the normal return from the script will launch the package installation
}
function isAppRunningInForeground(app) {
return mobicontrol.app.foregroundActivities.filter(activity => activity.packageName == app).length > 0;
}
Device self-service scripts
The following simple scripts could be organized as icons users could click to perform self-help actions that are based on condtional logic:
Restarts the agent if the battery is charging.
#!/usr/bin/env js
if (mobicontrol.battery.isCharging) {
mobicontrol.agent.restart();
}
Performs a check-in if the device is not currently roaming.
#!/usr/bin/env js
if (!mobicontrol.cellullar.isRoaming) {
mobicontrol.agent.checkIn();
}
Reboots the device if the clock app is not running in the foreground.
#!/usr/bin/env js
if (isAppRunningInForeground('com.android.deskclock')) {
mobicontrol.device.reboot()
}
function isAppRunningInForeground(app) {
return mobicontrol.app.foregroundActivities.filter(activity => activity.packageName == app).length > 0;
}
Closes an app if a low memory state is detected.
#!/usr/bin/env js
var ONE_HUNDRED_KB = 100 * 1024;
if (mobicontrol.memory.availableSpace < ONE_HUNDRED_KB) {
mobicontrol.app.stop('com.example');
}
Device compliance support
Promotes device compliance by running periodic checks to ensure the device is operating within accepted parameters. In this case, a persistent pop-up window is displayed for user action if the device battery is low.
#!/usr/bin/env js
if (mobicontrol.battery.level < 0.20 && !mobicontrol.battery.isCharging) {
mobicontrol.message.createWarnDialog('The battery is low, charge your device!').show();
}
Package deployment support
Controls the flow and execution of package installation. In this case, installation is aborted on devices running earlier than Android Oreo OS.
#!/usr/bin/env js
if (mobicontrol.os.level < 26) {
mobicontrol.log.warn('Aborting package installation, as device has below-Oreo OS');
throw(mobicontrol.packages.Termination.ABORTED);
}
Device relocation by custom data, attribute, or properties
Controls the deployment progress or ensures the proper configurations are pushed based on certain values. The following examples feature SSID and geofencing scenarios.
If a device's SSID is abc, move the device to ABC folder (device group). To set this up, perform the following steps:
- Create the ABC folder (device group) and configure it with a certain payload
(for example, Disable Camera) and INI custom data ssid.ini,
with section
info
and keyssidIsAbc
. - Create a relocation rule from the original folder to the ABC folder, when
ssidIsAbc
becomestrue
. - Create a relocation rule from ABC to the original folder, when
ssidIsAbc
becomesfalse
. - Run the following JavaScript on schedule to ensure that when the device connects and disconnects to/from abc SSID - the device is successfully relocated:
#!/usr/bin/env js
var ini = require('ini');
var iniFile = new mobicontrol.io.File(mobicontrol.storage.internal.dataDirectory + '/ssid.ini');
var config = ini.parse(iniFile.readText());
var currentSsidIsAbc = mobicontrol.network.ssid == 'abc';
if (config.info.ssidIsAbc != currentSsidIsAbc) {
config.info.ssidIsAbc = currentSsidIsAbc;
iniFile.writeText(ini.stringify(config));
mobicontrol.agent.checkIn();
}
If device with a name starting with 'Headquarters' enters geofence abc, move the device to the ABC folder. To set this up, perform the following steps:
- Create the ABC folder (device group), and configure it with a certain payload
(e.g Disable Camera) and XML custom data geofence.xml, with
the name
isInAbc
and XPath expression/isInAbc
. - Create a relocation rule from the original folder to the ABC folder, when
isInAbc
becomestrue
. - Create a relocation rule from ABC to the original folder, when
isInAbc
becomesfalse
. - Create a rule for entering the abc geofence with the following
script:
#!/usr/bin/env js if (mobicontrol.device.name.startsWith('Headquarters')) { var xmlFile = new mobicontrol.io.File(mobicontrol.storage.internal.dataDirectory + '/geofence.xml'); var config = new XML(xmlFile.readText()); config.isInAbc = true; xmlFile.writeText(config.toString()); mobicontrol.agent.checkIn(); }
- Create a rule for exiting abc geofence with the same script as above, but with
false
instead oftrue
. - Ensure that when device enters or exits the abc geofence it is successfully relocated.
Here is the same script with some custom troubleshooting code:
#!/usr/bin/env js
if (mobicontrol.device.name.startsWith('Headquarters')) {
try {
var xmlFile = new mobicontrol.io.File(mobicontrol.storage.internal.dataDirectory + '/geofence.xml');
var config = new XML(xmlFile.readText());
config.isInAbc = true;
xmlFile.writeText(config.toString());
mobicontrol.agent.checkIn();
} catch(err) {
if (err.statusCode == mobicontrol.io.IoError.FILE_NOT_FOUND) {
mobicontrol.log.err("XML file is missing");
} else if (err.statusCode == mobicontrol.io.IoError.NOT_ACCESSIBLE) {
mobicontrol.log.err("XML file is not accessible");
}
}
}
Upgrade application if it is not runnning in the foreground
Installs an application if it is not currently running in the foreground. The device battery must also be sufficiently charged and currently charging before the upgrade can begin. When installation is complete, the agent automatically checks in so that the WebConsole immediately reflects the change.
#!/usr/bin/env js
function isBatteryFullOrCharging() {
return mobicontrol.battery.level > 0.75 || mobicontrol.battery.isCharging;
}
function isForegroundApp(app) {
return mobicontrol.app.foregroundActivities.some(function(activity) {
return activity.packageName == app;
});
}
if (!isForegroundApp('com.example.bundleid') && isBatteryFullOrCharging()) {
mobicontrol.app.install('sdcard/PathTo/ExampleApp.apk', onFinish);
} else {
mobicontrol.log.info('Either Secure web is running or the battery is low and not charging')
}
function onFinish(result) {
if (result.isSuccessful) {
mobicontrol.agent.checkIn();
mobicontrol.log.info('Application ' + result.apkFileName + ' successfully installed');
} else {
mobicontrol.log.error('Application ' + result.apkFileName + ' installation failure: ' + result.statusCode);
}
}