B4J Library [ABPlugin] Live plugin library for your apps

This little library makes it possible to create Live plugins for you own apps. This means you can create plugins that can be added/removed while your app is running. Note it is a little experiment that shows the power of B4J. The 'compile to library' feature of B4J is very handy to create plugins.

Things to know when watching the video:
I've added the ABPlugin library to the DemoApp, but this is not in the video. Notice the DemoApp keeps running while I write a new 'divider' plugin!


Code:

For the DemoApp:
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private Button1 As Button
    Private ComboBox1 As ComboBox
    Private Label1 As Label
    Private TextField1 As TextField
    Private TextField2 As TextField
 
    Private plugin As ABPlugin 
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1 
    MainForm.RootPane.LoadLayout("1")
 
    ' initialize the plugin lib
    plugin.Initialize("plugin", File.Combine(File.DirApp, "plugins"), "MyKey")
    ' start the plugin lib, check for plugins every 5 seconds
    plugin.Start(5000)
 
    MainForm.Show
End Sub

Sub Button1_Action
    If ComboBox1.Value = Null Then Return
    If TextField1.text = "" Then Return
    If TextField2.text = "" Then Return
 
    ' create a map with the parameters of the method
    Dim params As Map
    params.Initialize
    params.Put("val1", TextField1.Text)
    params.Put("val2", TextField2.Text)
 
    ' run the plugin!
    Dim result As Double = plugin.RunPlugin(ComboBox1.Value, "calculate", params)
 
    Label1.Text = TextField1.Text & " " & ComboBox1.Value & " " & TextField2.Text & " = " & result
End Sub

' new plugins are found, or plugins have been removed
Sub plugin_PluginsChanged()
    Log("plugins have changed!")
    Dim plugins As List = plugin.GetAvailablePlugins
 
    ComboBox1.Items.Clear
    For i = 0 To plugins.Size - 1
        ComboBox1.Items.Add(plugins.Get(i))     
    Next
End Sub

For a plugin. You'll need all three methods (Initialize, GetNiceName and Run) and they MUST by in this syntax (you cannot add extra parameters to initialize for example).
B4X:
Sub Class_Globals
 
End Sub

'Initializes the object. You can NOT add parameters to this method!
Public Sub Initialize() As String
    Log("Initializing plugin " & GetNiceName) 
    ' Here return a key to prevent running unauthorized plugins
    Return "MyKey"
End Sub

' must be available
public Sub GetNiceName() As String
    Return "/"
End Sub

' must be available
public Sub Run(Tag As String, Params As Map) As Object
    Select Case Tag
        Case "calculate"
            Dim val1 As Double = Params.Get("val1")
            Dim val2 As Double = Params.Get("val2")
            Dim ret As Double = val1/val2
            Return ret
    End Select
 
    Return 0
End Sub

The demo and library files are in the attached Zip.

UPDATE: the 1.20 version should also support JDK9+ and an extra example on how to use a ResumableSub (for this empale you must also attach the jHttpUtils and Json libraries in the calling program)
 

Attachments

  • ABPlugin.zip
    63.3 KB · Views: 544
  • ABPlugin1.20.zip
    45.9 KB · Views: 464
Last edited:

woniol

Active Member
Licensed User
Longtime User
Hi.
Is it possible to call a sub that is defined in the plugin - like plugin.CallSub
and also call a sub in main program from the plugin?

I would like to create scheduler plugin.
I need to add new entires form the main program, and call events defined in main program from the plugin.
 
Last edited:

alwaysbusy

Expert
Licensed User
Longtime User
That is the point of the Run() method in the Plugin and the RunPlugin() method in the main program.

I don't use the CallSub methods as they are limited to 2 params max. My Run methods can take as many params as needed.

e.g. in the plugin:

B4X:
' must be available
public Sub Run(Tag As String, Params As Map) As Object
    Select Case Tag
        Case "myownfunction"
            Dim val1 As Double = Params.Get("val1")
            Dim val2 As Double = Params.Get("val2")
            return CallSub3("MyOwnFunction", val1, val2)
            ' but that is not even needed, just do:
            ' Return MyOwnFunction(val1, val2)   
    End Select
  
    Return 0
End Sub

Sub MyOwnFunction(val1 as double, val2 as double) as Double
     Return val1 * val2
End Sub

You can call MyOwnFunction in the main program like this:
B4X:
 ' create a map with the parameters of the method
    Dim params As Map
    params.Initialize
    params.Put("val1", 10.2)
    params.Put("val2", 15.8)
  
    ' run the plugin!
    Dim result As Double = plugin.RunPlugin(ComboBox1.Value, "myownfunction", params)
 

woniol

Active Member
Licensed User
Longtime User
I understand how to run a sub defined in the plugin from the main program,
but is it possible to run a sub defined in the main program from the plugin(s)?

Found it :)
CallSub("main","test") - calls test sub in the Main of the main program.
 
Last edited:

Cableguy

Expert
Licensed User
Longtime User
plugin.Start(5000)
Is there a value we can set that will result in checking for new plugins only when starting the lib, and not every x milliseconds?
Maybe even seperate the method into 2 different methods, like Start and Check_New(periodically as bool, time as int), so if periodically = False, check only on start, if true, check every x seconds
 
Top