How to develop Appemble plug-ins

The App Virtual Machine (AVM) is architected in a way that it is modular and is extendible. Extensible means new standalone libraries can be written that provide new types of

  • UI elements (Screen, Control, Events and Action)
  • Integration Points with popular API’s.

The new features provided by the plugin can be added in an app seamlessly and for the app writer it makes no difference if the features are provided in the core AVM or as a plugin. Just like AVM, the plugins are written in the native SDK’s language (Android uses Java and iOS uses Objective C.).

The core AVM gives basic screen, controls and actions. However plugins can provide rich and complex controls like Coverflow, Chart, In App Purchase, Location Services etc or integration points with popular API’s like Facebook, Twitter, SalesForce and Amazon etc.

Adding a new control

Before we dive into “how to write a new control”, let us understand the life-cycle of a control and which Control Attributes are used at each stage.

Lifecycle Stage When Attributes Used
Creation Controls are created while creating screen. They may be (rarely) created in a FUNCTION name, type, Dimension - x, y, width, height, appearance_name, word_wrap, ellipsized, is_visible, os
Set Value Value of a control is set on resuming a screen or if the action SET_CONTROL_ATTRIBUTES set a new value default_value, data_type, field_name, size, format_type, storage_format, local_data_source, remote_data_source, remote_request_type, remote_data_format, remote_data_save_locally Attributes defining data source for control
Get Value Value of a control is read upon executing an action whose input_parameter_list contains control’s field_name field_name, size, data_type
Destroy Controls are destroyed while destroying the screen. Screens can end as a result of CLOSE_SCREEN or in Android, after pressing a BACK button. none
     

To write a new control, there are 4 simple steps.

  • Copy the plugin-template project and give it a suitable name.
  • Define the control’s implementation class name and its attributes in a config file.
  • Implement the control in native SDK language. (For Android it is Java and for iOS it is Objective C)
  • Optionally define functions for events onPause and onResume. These functions are called when the screen resumes and pauses. For example, in a video control you would write code for this function so that the video can be paused when the screen pauses.

Android

Android implementation needs following steps.

  • Copy the appemble-android-plugin-template project and give it a new name.

    • Select the project and then select menu File | Rename.
    • Change the package name in AndroidManifest.xml.
  • Define the control’s implementation class name and its attributes in a config file.

    • Rename the config file present in the <project's root folder>/res/xml/avm_plugin_template_config.xml to a suitable name
    • Change name of the control from com.mycompany.MYCONTROL to a suitable name.
    • Change the implementation class of the control from com.mycompany.controls.MYCONTROL to a suitable name.
    • Add specific attributes (as extended attributes) that your control needs which are in addition to the control’s Control Attributes
  • Implement the control in native SDK language. (For Android it is Java and for iOS it is Objective C)

    • Rename the package com.mycompany.controls to a suitable name
    • Rename the file MYCONTROL to a suitable name
    • Add code to initialize(), getValue() and setValue() functions.
    • Optionally add code to onResume() and onPause() functions.

Control Definition

A plugin defines the new control and its extended attributes in a config file. A config file is an XML file. A control inherits the common Control Attributes and their validation rules from the AVM, though the validation rules can be overridden. The control name resides in its own namespace for example, to write a new MYCONTROL, its name would be com.mycompany.MYCONTROL. This name will be unique and will be different from any other implementation of MYCONTROL. The app writer can use type=”com.mycompany.MYCONTROL” to differentiate with the any other implementation of MYCONTROL. The sample config file for a control is shown below.

<?xml version="1.0" encoding="utf-8"?>
<config>
    <controls>
        <control name="com.mycompany.MYCONTROL" class="com.mycompany.controls.MYCONTROL">
            <validation>
            <!-- override default attributes for MYCONTROL. It takes only JSONARRAY, CURSOR and ARRAYLIST -->
                <field name="data_type" type="enum" values="JSONARRAY, CURSOR, ARRAYLIST" default="CURSOR"
                    mandatory="yes" destination="extended_properties"/>
                <field name="permission" type="enum" values="READONLY" default="READONLY"/>
            <!-- define extended attributes for MYCONTROL-->
                <field name="mycontrol_property1" type="string" mandatory="yes" destination="extended_properties"/>
                <field name="mycontrol_title" type="string" destination="extended_properties"/>
                <field name="mycontrol_title_text_size" type="int" destination="extended_properties"/>
                <field name="mycontrol_scale" type="float" destination="extended_properties"/>
            </validation>
        </control>
    </controls>
</config>

The additional attributes defined in the config file are accessible with the AVM internal structure ControlModel. Refer to the AVM library source code for the definition of the ControlModel.

Control Definition Attributes

The control definition attributes are internal attributes of the control, not available to app writers but to the author to define (internal) properties of the control. Some of these attributes are used by AVM on how to deal with the control creating it or setting the values to it or getting the values from it.
Attribute Name Description Possible Values
isGroup This attribute tells AVM that this control is a group control and can have child controls to it true or false
isClickable Tell the AVM to listen to user TAP for this control and raise the event to execute actions associated with this event true or false
process_remote_ds This tells the AVM what to do when there is a remote data source attached to the contol. If set to false, AVM will not act upon the remote data source of the control. If set to true, the AVM will execute the remote data source and pass the response of the remote data source to the control. For ex. in the AVM library the config file appemble-android-library/res/xml/ appemble_android_library_config.xml contains process_remote_ds=”false” for IMAGE control. This means that AVM will not process the remote data source of the control and pass the remote data source to the control as-is via the function setValue(). true or false
cursorMgmt AVM processes the local_data_source for all controls in the screen. AVM creates the cursor and closes it after fetching the values from the local data source. This attribute tells the AVM that the control will manage the lifecycle of the cursor and AVM does not have to close it. self or avm
childControlDataMgmt AVM processes the local and remote data sources for all controls when onResume() is called. This attribute tells AVM not to process the local or remote data source for child controls of this GROUP Control.  

Implementation Class

A new control is implemented by defining a new class which must extend a android.view.view class and implements the interface ControlInterface. The control class may be extended from an existing view class. The following functions must be implemented.

  • initialize()
  • getValue()
  • setValue()
  • Other functions can have the default implementation present in the com.mycompany.MYCONTROL class.

Please refer to the sample code in the project appemble-android-plugin-template. The source file is location in <project root>/src/com/mycompany/controls/MYCONTROL.java

iOS

Adding a new action

Before we dive into “how to write a new action”, let us understand the life-cycle of a action and which Action Attributes are used at each stage.

Lifecycle Stage When Attributes Used
Creation Actions are created when an event executes them or they are called by another action (nested actions) action_name, event_list
Get Data After creation the first step is to fetch data for field names specified in the input_parameter_list. The values can be constants or can come from global properties, local database or from the parent screen input_parameter_list, target_parameter_list
Execute The second step is to execute the action. The action utilizes the values for fields specified in the target_parameter_list to complete the action. target, target_parameter_list
     

To write a new action, there are 3 simple steps.

  • Copy the plugin-template project and give it a suitable name.
  • Define the action’s implementation class name and its attributes in a config file.
  • Implement the action in native SDK language. (For Android it is Java and for iOS it is Objective C)

Android

The implementation needs following steps.

  • Copy the appemble-android-plugin-template project and give it a suitable name.

    • Select the project and then select menu File | Rename.
    • Change the package name in AndroidManifest.xml.
  • Define the action’s implementation class name and its attributes in a config file.

    • Rename the config file present in the <project's root folder>/res/xml/avm_plugin_template_config.xml to a suitable name
    • Change name of the action from com.mycompany.MYACTION to a suitable name.
    • Change the implementation class of the action from com.mycompany.actions.MYACTION to a suitable name.
    • Add specific attributes (extended attributes) that your action needs which are in addition to the action’s Action Attributes
  • Implement the action in native SDK language. (For Android it is Java and for iOS it is Objective C)

    • Rename the package com.mycompany.actions to a suitable name
    • Rename the file MYACTION to a suitable name
    • Add code to execute() function.

Action Definition

A plugin defines the new action and its extended attributes in a config file. Ab action inherits the common Action Attributes and their validation rules from the AVM (though the validation rules can be overridden). The action name resides in its own namespace for example, to write a new MYACTION, its name would be com.mycompany.MYACTION. This name will be unique and will be different from any other implementation of MYACTION. The app writer can use type=”com.mycompany.MYACTION” to differentiate with the any other implementation of MYACTION. The sample config file for a action is shown below.

<?xml version="1.0" encoding="utf-8"?>
<config>
    <actions>
        <action name="com.mycompany.MYACTION" class="com.mycompany.actions.MYACTION">
            <validation>
                <field name="myaction_property1" type="int" destination="extended_properties"/>
            </validation>
        </action>
    </actions>
</config>

The additional attributes defined in the config file are accessible with the AVM internal structure ActionModel. Refer to the AVM library source code for the definition of the ActionModel.

Implementation Class

A new action is implemented by extending a new class from ActionBase. The following functions must be implemented.

  • execute()
  • Other functions can have the default implementation present in the com.mycompany.MYACTION class.

Please refer to the sample code in the project appemble-android-plugin-template. The source file is location in <project root>/src/com/mycompany/actions/MYACTION.java

Adding a new event

Events are generally treated as hooks for the app writers to define business logic or call a pre-defined action. While implementing new controls, activities or actions, you may want to provide such hooks or more event types.

To add a new event, there are 3 simple steps.

  • Define the event in a config file.
  • Call the action for the newly added event. (For Android it is Java and for iOS it is Objective C)

Android

To define a new event, do the following steps.

  • Define the event(s) in a config file.
  • Call actions associated with this event in native SDK language. (For Android it is Java and for iOS it is Objective C)

Event Definition

<events>
        <event name="com.mycompany.MYEVENT1"/>
        <event name="com.mycompany.MYEVENT2"/>
</events>

Call Actions associated with the event

  • Fetch the actions associated with the event.
  • Prepare the variable targetParameterValueList to fill in the right key/value pairs to be passed to the action.
  • Execute the action.

The sample code to call actions for a particular event is below.

// fetch the actions for the event.
ActionModel[] actions = ActionModel.getActions(mActivity.getScreenModel().sSystemDbName,
        mActivity.getScreenModel().sContentDbName, "com.mycompany.MYEVENT1");

// add the needed key/value pairs to be passed to the actions
targetParameterValueList.putString("variable1", "value1");
targetParameterValueList.putString("variable2", "value2");

// execute the action
for (int i = 0; null != actions && i < actions.length; i++)
    Action.callAction(mActivity.getContext(), null, null, actions[i], targetParameterValueList);

Adding a new Screen

Before we dive into “how to write a new type of screen?”, let us understand the life-cycle of a screen and which Screen Attributes are used at each stage.

Lifecycle Stage When does it occur Attributes Used
Create When an intent is received with a particular screen name or type. Android calls onCreate(). screen_type, width, height, menuOrder, menuName, icon, tab_group_name, allowed_layouts, allow_reorientation, scroll, title_background, background, os
Start When the screen is visible. Android calls onStart()  
Resume When the screen resumes. The screen resumes after being created or when it comes to foreground again. local_data_source, remote_data_source, remote_request_type, remote_data_save_locally, on_resume_update
Pause When the screen goes to background. The screen is paused when another screen is shown on top of it.  
Stop The screen becomes invisible on the device.  
Destroy Generated after the screen is finished and all its views have been destroyed.  

To write a new type of screen, there are 3 simple steps.

  • Copy the plugin-template project and give it a suitable name.
  • Define the screen’s implementation class name and its attributes in a config file.
  • Implement the new screen type in native SDK language. (For Android it is Java and for iOS it is Objective C)

Android

In Android, a screen is generally referred to as Activity. To implement a new screen (activity), the following steps are needed.

  • Copy the appemble-android-plugin-template project and give it a suitable name.

    • Select the project and then select menu File | Rename.
    • Change the package name in AndroidManifest.xml.
  • Define the screen’s (activity’s) implementation class name and its attributes in a config file.

    • Rename the config file present in the <project's root folder>/res/xml/avm_plugin_template_config.xml to a suitable name.
    • Change name of the screen (activity) from com.mycompany.MYACTIVITY to a suitable name.
    • Change the implementation class of the screen (activity) from com.mycompany.activitys.MYACTIVITY to a suitable name.
    • Add specific attributes (extended attributes) that your screen (activity) needs which are in addition to the screen’s Screen Attributes
  • Implement the screen (activity) in native SDK language. (For Android it is Java and for iOS it is Objective C)

    • Rename the package com.mycompany.activities to a suitable name

    • Rename the file MYACTIVITY to a suitable name

    • Add code to the relevant functions. If your activity is not derived from DynamicActivity, then it is recommended to override functions
      • onCreate() to create controls,
      • onResume() to populate data in them (if needed). Call setValue() for each control
      • Raise events by calling actions for each Screen life cycle.

Screen (Activity) Definition

A plugin defines the new screen (activity) and its extended attributes in a config file. An activity inherits the common Screen Attributes and their validation rules from the AVM. The validation rules can be overridden. The activity name resides in its own namespace for example, to write a new MYACTIVITY, its name would be com.mycompany.MYACTIVITY. This name will be unique and will be different from any other implementations of MYACTIVITY. The app writer can use type=”com.mycompany.MYACTIVITY” to differentiate with the any other implementation of MYACTIVITY. A sample config file for defining a new screen (activity) is shown below.

<?xml version="1.0" encoding="utf-8"?>
<config>
<activities>
    <activity name="com.mycompany.MYACTIVITY" class="com.mycompany.actvities.MYACTIVITY">
        <validation>
        <!-- override default attributes with MYACTIVITY. It takes only JSONARRAY, CURSOR and ARRAYLIST -->
            <field name="remote_request_type" type="enum" values="GET" default="GET"/>
        <!-- define extended attributes for MYACTIVITY-->
            <field name="myactivity_property1" type="string" mandatory="yes" destination="extended_properties"/>
            <field name="myactivity_property2" type="float" destination="extended_properties"/>
        </validation>
    </activity>
</activities>
</config>

The additional attributes defined in the config file are accessible from the AVM’s internal structure ScreenModel. Refer to the AVM library source code for the definition of the ScreenModel.

Implementation Class

A new type of screen (activity) is implemented by defining a new class which may extend an android.app.Activity class and implements the interface AppembleActivity. The following interface functions must be implemented.

  • public Context getContext();
  • public HashMap<Integer, Cursor> getCursors();
  • public View getRootLayout();
  • public void setActivityCreateStatus(boolean bBoolean);
  • public boolean getActivityCreateStatus();
  • public boolean getNetworkAvailableFlag();
  • void startActivityForResult(Intent intent, int requestCode);
  • public boolean isDestroyed();
  • public void finish();
  • public Vector<ControlModel> getAllControls(); // contains all controls
  • public ScreenModel getScreenModel(); // contains all controls
  • public Bundle getTargetParameterValueList();

Most functions have the default implementation. Please refer to the sample code in the project appemble-android-plugin-template. The source file is location in <project root>/src/com/mycompany/activities/MYACTIVITY.java

iOS