First Plugin
Running your first plugin
Before we start
It's recommended to review the Plugin Class Reference documentation or keep it open for reference while developing plugins.
Basic plugin structure
All .plugin
files must include:
- Meta variables defined as plain strings (
__id__
,__name__
,__description__
,__author__
,__version__
,__icon__
,__min_version__
) - A single class that inherits from
BasePlugin
Here's the most basic plugin template:
BasePlugin
as it's implicitly imported.Creating simple Weather plugin
In this example, we'll create a plugin that provides weather information when a user sends a message prefixed with .wt
.
We'll use the wttr.in API to fetch weather data.
Implementing network call and formatting
First, let's implement the functions to fetch and format weather data. They're quite boilerplate, so we won't look deep into it:
Hooking message send event
To intercept and modify messages, we implement the on_send_message_hook
method in our plugin class:
To make your on_send_message_hook
method actually get called by the plugin system, you need to register this hook. This is typically done in on_plugin_load
by calling self.add_on_send_message_hook()
.
The on_send_message_hook
method returns a HookResult
with a MODIFY
strategy, which means the message will be modified before sending. An empty HookResult
won't modify the message.
Complete example (Initial)
Here's the complete implementation of the Weather plugin before performance enhancements:
Testing the Plugin
Try sending message like .wt
in any chat. You should get something similar to this:
Performance Considerations
Fixing UI freeze
You may notice that the app freezes for a few seconds when using the plugin. This happens because the network call (requests.get
) is a blocking I/O operation running on the UI thread. While the request is processing, the app cannot render anything.
To fix this issue, move blocking calls to a separate thread or queue to avoid blocking the UI thread. We can use client_utils.run_on_queue
for the background network request and android_utils.run_on_ui_thread
to post results back to the UI thread (e.g., to send the message or dismiss a dialog).
Additionally, we'll show a loading indicator using AlertDialogBuilder
from alert.py
while fetching data and then use client_utils.send_message
to send the processed message.
Here's the improved version:
In this improved version:
- We import
AlertDialogBuilder
fromalert
. - The
__init__
method initializesself.progress_dialog_builder
. Theon_plugin_load
method is used to callself.add_on_send_message_hook()
. - When
.wt
is detected, we create andshow()
anAlertDialogBuilder
ofALERT_TYPE_SPINNER
. - The actual work (
_process_weather_request
) is dispatched to a background queue usingrun_on_queue
. _process_weather_request
performs the network call. After getting the result, it schedules_send_message_and_dismiss_dialog
on the UI thread usingrun_on_ui_thread
._send_message_and_dismiss_dialog
dismisses the progress dialog and then usesclient_utils.send_message
to send the weather information as a new message.- The original message sending is cancelled by returning
HookResult(strategy=HookStrategy.CANCEL)
.
This approach ensures the UI remains responsive while fetching data.
What's next?
To further develop your plugin skills, explore community-made plugins: