Developers: Plugins
Tasker supports standard Android automation plugins. Any such plugins installed on the device will appear in the Plugins action (for settings plugins), state (for condition plugins) or Event category (a Tasker-only extension) in the Tasker UI.
Please see here for the base specification.
There is also an introduction to creating plugins for Tasker.
Tasker Limitations
- Tasker only supports the value types int, long, float, double, boolean, String
- String [] and ArrayList (from v4.3) values are also supported, as long as they are not null
- bundle keys must match XML tag name constraints, due to how Tasker stores bundle data
- the bundle key class is disallowed
Tasker Protocol Extensions
Tasker provides a few additions to the protocol to enable features which are
not relevant to most automation 'host' apps. Most of these extensions require Tasker 4.2+.
If you want to take advantage of the Tasker extensions, you will need to copy
TaskerPlugin.java into your plugin/host
project (and change the pacakge name at the top to match).
Tasker Setting Plugin Extensions
Variable Replacement
The host can be requested do variable replacements on any String, String [] or ArrayList extras in a setting plugin bundle which are specified by the plugin.
In your plugin EditActivity:
if ( TaskerPlugin.Setting.hostSupportsOnFireVariableReplacement( this ) )
TaskerPlugin.Setting.setVariableReplaceKeys( resultBundle, new String [] { "com.sample.plugin.MYVALUE" } );
For the bundle key com.sample.plugin.MYVALUE, the host will scan for variable names and replace them with the current values of the
variables in the host.
So if the following bundle values were passed to the host from the EditActivity...
Bundle Key | Bundle Value (String) |
com.sample.plugin.MYVALUE | Your location is currently %LOC +- %LOCACC. |
com.sample.plugin.MYOTHERVALUE | I am %ONEHUNDRED sure this string won't be touched. |
... then the following values might be passed to the BroadcastReceiver
when the host triggers the action:
Bundle Key | Bundle Value (String) |
com.sample.plugin.MYVALUE | Your location is currently -1.0,1.5 +- 500m |
com.sample.plugin.MYOTHERVALUE | I am %ONEHUNDRED sure this string won't be touched. |
If the string values which are being replaced have an internal structure
which could be broken by the values in the variables being replaced, you
can specify this to the host via the setKeyEncoding function:
if ( TaskerPlugin.hostSupportsKeyEncoding( this ) )
TaskerPlugin.setKeyEncoding( resultBundle, new String [] { "com.sample.plugin.MYVALUE" }, TaskerPlugin.Encoding.JSON );
Synchronous Settings
The base plugin protocol only supports asynchronous settings;
once the plugin
has fired the host has no idea when it's finished or if it's worked and all it can do is hope
for the best and continue.
The Tasker plugin extensions provide a mechanism for the plugin to signal when it
has finished, return completion status and set local variables in the task
which called the plugin.
Firstly, in the EditActivity , the plugin may optionally indicate that it wishes to
run synchronously by specifying a timeout:
if ( TaskerPlugin.Setting.hostSupportsSynchronousExecution( getIntent().getExtras() ) )
TaskerPlugin.Setting.requestTimeoutMS( resultIntentToHost, 3000 );
Note that the host may choose to ignore the requested timeout or even
run the plugin completely asynchronously. From Tasker 4.7, you can find out which timeout
the host is actually applying when the action fires using the function
TaskerPlugin.Setting.getTimeoutHint() in FireReceiver .
That may be useful for aborting processing if it can't be completed within
the timeout period.
Secondly, in the plugin FireReceiver , the plugin knows that the host is waiting for it if isOrderedBroadcast()
in onReceive returns true. If so, it can set a result and/or
return some variables.
if ( isOrderedBroadcast() ) {
setResultCode( TaskerPlugin.Setting.RESULT_CODE_OK );
if ( TaskerPlugin.Setting.hostSupportsVariableReturn( intent.getExtras() ) ) {
Bundle vars = new Bundle();
vars.putString( "%pcolour", "boo" );
TaskerPlugin.addVariableBundle( getResultExtras( true ), vars );
}
}
Note that the default result is OK, you can skip setResultCode in
the case where there were no problems.
If your plugin cannot complete it's processing within the onReceive() function, put this code at the end of onReceive() instead:
if ( isOrderedBroadcast() )
setResultCode( TaskerPlugin.Setting.RESULT_CODE_PENDING );
This tells the host that you will send a separate completion intent at a later time.
When you're finished processing, probably in a Service, signal finish like this:
TaskerPlugin.Setting.signalFinish( context, fireIntentFromHost, TaskerPlugin.Setting.RESULT_CODE_OK, varsBundle );
fireIntentFromHost is the second argument in FireReceiver.onReceive() .
The third argument indicates the completion status. The final
argument is an optional (use null if unneeded) bundle of variable
values that will be applied by the host.
Error Reporting (Tasker 4.6+)
When the response code indicates failure, it's placed in the local
variable %err in the task, so that the user can take
an appropriate action if they wish (the user must have configured
the plugin action with Continue On Error to do that).
In addition to the built-in responses, plugins can return their own
customized failure codes using any integer from
Setting.RESULT_CODE_FAILED_PLUGIN_FIRST upwards.
Plugins can also optionally set a human-readable error message by including
a variable with name Setting.VARNAME_ERROR_MESSAGE
in the appropriate parameter of addVariableBundle and
addRelevantVariableList .
The error message variable should only be set when the BroadcastReceiver
response code indicates a failure.
Relevant Variables
It might be useful for the plugin to know which variables the user might
want the plugin to set. The host can pass these 'relevant' variables
to the plugin EditActivity. They can be retrieved by the plugin as
follows (typically in onCreate() ):
if ( TaskerPlugin.hostSupportsRelevantVariables( getIntent().getExtras() ) )
String [] passedNames = TaskerPlugin.getRelevantVariableList( getIntent().getExtras() );
It might also be useful for the host to know which variables a plugin is likely to set upon completion.
Tasker, for example, can use this information to show the user a variable selection list for
subsequent actions in the task.
Specify that in your EditActivity just before setResult() :
if ( TaskerPlugin.hostSupportsRelevantVariables( getIntent().getExtras() ) )
TaskerPlugin.addRelevantVariableList( resultIntent, new String [] {
"%pcolour\nPet Colour\nThe colour of the pet <B>last bought</B>"
} );
The variable specification consists of 3 parts separated by newline characters:
- the variable name
- a localized (if possible) human-readable label in plain text format
- an optional, localized (if possible) human-readable description of what the variable contains at which times etc in HTML
The variable name and label are mandatory, the description is optional.
Tasker Condition Plugin Extensions
Condition Variables
Condition plugins can stipulate variable
names and values (in a Bundle) which will be visible in any tasks that run as a result of a change in plugin state.
Example code in BroadcastReceiver.onReceive() :
if ( TaskerPlugin.Condition.hostSupportsVariableReturn( intent.getExtras() ) ) {
Bundle varsBundle = new Bundle();
varsBundle.putString( "%colour", "red" );
TaskerPlugin.addVariableBundle( getResultExtras( true ), varsBundle );
}
Relevant Variables
'Relevant' variables are also supported for condition plugins. The intention
is that the user should be shown in the host UI any variables which may be passed by the plugin to the host.
The code is the same as for a settings plugin EditActivity (see here).
Tasker Event Plugin Extension
The base protocol supports a plugin which can tell the host app whether
a condition is currently true or not e.g. there is an unread SMS. This corresponds to a Tasker state context.
However, many plugins are more event based i.e. Tasker should be notified if something
has happened e.g an SMS has been received. This corresponds
to a Tasker event context.
From Tasker 4.3, event plugins are supported as a third class of
plugin next to the setting (action) and condition (state) types.
From the point of view of the plugin developer, event plugins are
almost identical to condition plugins. When developing an event plugin
you can follow all the same documentation and code except for taking
into account the following differences:
- the plugin EditActivity should listen (with the IntentFilter
in its Manifest) for the action
net.dinglisch.android.tasker.ACTION_EDIT_EVENT instead of
the previous EDIT_CONDITION .
- when the host queries the plugin via
QUERY_CONDITION ,
only the SATISFIED result code will be acted upon by the host.
UNSATISFIED or UNKNOWN will be ignored.
- when the plugin sends a REQUEST_QUERY intent, it should add a message ID to the intent with
TaskerPlugin.addPassThroughMessageID() and when it receives a QUERY_CONDITION it should check the message ID. This serves three purposes.
- it prevents some security problems such as rogue apps sending false data under pretences of being the host
- it allows the plugin to associate each QUERY_CONDITION with an event which occured
- it allows plugins which need to use a service to be kickstarted by the host e.g. after a reboot; when the plugin doesn't see a message ID in a REQUEST_QUERY, it knows that the intent is not as a result of an event occuring and can be ignored.
Note that the plugin still has to ask the host to query it for the
SATISFIED result code. The main reasons are
to maintain as much compatibility as possible, ease transition and
maintain security.
If the plugin wishes, it can pass through an event data bundle when
it request the host to query if via QUERY_REQUEST, see addPassThroughData/retrievePassThroughData . In this case, it's still advisable to
add a message ID as described above.
Notes
Variables
Each host may have different requirements on variable names and values.
For instance, Tasker requires all variable names passed from a plugin
be lower-case (i.e. be 'local' variables).
You may wish to check the validity of any variable names used since they'll
be rejected by Tasker otherwise and it may not be clear to the user
where the bad variable name is coming from:
if ( TaskerPlugin.variableNameValid( "%colour" ) )
varBundle.put( "%colour", "red" );
Tasker-Generated Apps
From Tasker 1.2.2, Tasker supports generation of standalone apps which
can be installed on phones other than the one on which the app was
generated.
If the user has configured a plugin condition or action, the stored
Bundle data will also be carried over to the new app.
For that reason you should store all data in the passed Bundle if possible
because otherwise your plugin won't work when installed on new devices
when distributed e.g. via Play Store.
It's beneficial to a plugin developer to be included in user-generated apps
because the child app will prompt for installation of your plugin at
runtime and thus increase it's presence.
Clearly, this advice does not apply to sensitive user data such as
passwords. If you need to store such data locally in your plugin application,
then your plugin is not going to work when distributed as an app and the
user will discover that during testing and just have to live with it.
Identifying Plugins
From version 4.8u2, Tasker identifies plugins by a combination of their type, package name and class name of
the edit activity. That means that if your package name changes e.g. between beta and release, your users
will need to delete and recreate their plugin configurations.
Using Services
From version 5.1.5b, Tasker will use IntentServices to call plugins if available. Check here for a migration guide.
|