Modularity is a key design principle of the mPaaS framework. Business modules with low coupling and high cohesion are easier to extend and maintain.
Business modules exist as Bundles and do not affect each other. However, Bundles can be related. For example, you might navigate to another Bundle's UI, call an API in another Bundle, or need to complete certain operations during initialization.
For this reason, mPaaS provides a `metainfo` universal component registration mechanism. Each Bundle declares the components it registers in the metainfo.xml file.
The framework currently supports the following components:
ActivityApplication
ExternalService (Service)
BroadcastReceiver
Pipeline
The metainfo.xml file has the following format:
<?xml version="1.0" encoding="UTF-8"?>
<metainfo>
<broadcastReceiver>
<className>com.mpaas.demo.broadcastreceiver.TestBroadcastReceiver</className>
<action>com.mpaas.demo.broadcastreceiver.ACTION_TEST</action>
</broadcastReceiver>
<application>
<className>com.mpaas.demo.activityapplication.MicroAppEntry</className>
<appId>33330007</appId>
</application>
</metainfo>Application component
The ActivityApplication is a component designed by the mPaaS framework to act as an Activity container for managing and organizing Activities. It is used to handle navigation to the UI of another Bundle. This allows the caller to perform the navigation by only knowing the ActivityApplication information registered in the framework and the agreed-upon parameters.
About this task
The mPaaS framework fully manages the lifecycle of an ActivityApplication, including its creation and destruction. Your business logic only needs to process the received parameters and manage the Activities within its scope. This effectively isolates your business logic from the caller. The business logic and the caller only need to agree on the call parameters, which creates a more lightweight dependency.
For Android client applications developed with the mPaaS framework, Activities must inherit from `BaseActivity` or `BaseFragmentActivity` so they can be managed by the `ActivityApplication` class.
Procedure
In the main module of the project, create a
metainfo.xmlfile in the location shown in the following figure:
Add the following configuration to
metainfo.xml:The `className` attribute specifies the class that handles navigation and defines the behavior for each stage. For the class definition, see the code in step 3. The framework uses this name to load the corresponding class. Therefore, this class must not be obfuscated and must be kept in the obfuscation file.
`appId`: This is the unique identifier for the business. To perform the navigation, the caller only needs to know the `appId` of the business. The framework layer handles the mapping between the
appIdand the `ActivityApplication`.<?xml version="1.0" encoding="UTF-8"?> <metainfo> <application> <className>com.mpaas.demo.hotpatch.HotpatchMicroApp</className> <appId>33330002</appId> </application> </metainfo>
If the class specified by `className` only performs a simple navigation, you can use the following code for the implementation:
/** * Scenario 1: * If you only need to navigate to a specific Activity interface, you must override getEntryClassName and onRestart. The former returns the class name of the Activity. The latter needs to call getMicroApplicationContext().startActivity(this, getEntryClassName()). * Scenario 2: * To navigate to different Activity interfaces based on requirements, you must override onStart and onRestart. Navigate to the specified interface based on the parameters in the bundle. * Created by mengfei on 2018/7/23. */ public class MicroAppEntry extends ActivityApplication { @Override public String getEntryClassName() { // Scenario 1: If you can only navigate to a specific Activity, return the class name here. // Scenario 2: If you navigate to an interface based on parameters, you need to return null. return MainActivity.class.getName(); } /** * This method is called when the Application is created. The implementation class can perform some initialization work here. * * @param bundle */ @Override protected void onCreate(Bundle bundle) { doStartApp(bundle); } /** * This method is called when the Application starts. * If the Application has not been created, the create method is executed first, and then the onStart() callback is executed. */ @Override protected void onStart() { } /** * This callback is invoked when the Application is destroyed. * * @param bundle */ @Override protected void onDestroy(Bundle bundle) { } /** * When the Application starts, if it has already been started, the onRestart() callback is invoked instead of onStart(). * * @param bundle */ @Override protected void onRestart(Bundle bundle) { // For Scenario 1: You need to call getMicroApplicationContext().startActivity(this, getEntryClassName()) here. doStartApp(bundle); } /** * When a new Application is started, the current Application is paused, and this method is called back. */ @Override protected void onStop() { } private void doStartApp(Bundle bundle) { String dest = bundle.getString("dest"); if ("main".equals(dest)) { Context ctx = LauncherApplicationAgent.getInstance().getApplicationContext(); ctx.startActivity(new Intent(ctx, MainActivity.class)); } else if ("second".equals(dest)) { Context ctx = LauncherApplicationAgent.getInstance().getApplicationContext(); ctx.startActivity(new Intent(ctx, SecondActivity.class)); } } }The caller can navigate using the interface provided in
MicroApplicationContext, which is encapsulated by the framework. ThecurIdparameter can also be `null`:// Get the MicroApplicationContext object: MicroApplicationContext context = MPFramework.getMicroApplicationContext(); String curId = ""; ActivityApplication curApp = context.getTopApplication(); if (null != curApp) { curId = curApp.getAppId(); } String appId = "ID of the target ApplicationActivity"; Bundle bundle = new Bundle(); // Optional additional parameters context.startApp(curId, appId, bundle);
Service component
mPaaS provides the Service component to enable cross-Bundle interface calls. A Service component provides logic as a service for other modules to use.
About this task
The Service component has the following features:
No user interface restrictions.
Designed to separate the interface from the implementation.
By design, only the interface class is visible to the caller. Therefore, define the interface class in the interface module. When you generate a Bundle project, an interface module named `api` is created by default. Define the implementation in the main module.
External calls are made through the findServiceByInterface interface of MicroApplicationContext to retrieve the corresponding service using the interfaceName. For Bundles, only the abstract service interface class is exposed. This class is specified in `interfaceName` and defined in the interface package.
Procedure
Register the Service component as follows:
Define the location of
metainfo.xmlas shown in the following figure:
Add the following configuration to
metainfo.xml. The framework usesinterfaceNameas the key andclassNameas the value to create a mapping. TheclassNameattribute specifies the implementation class of the interface, andinterfaceNamespecifies the abstract interface class:<metainfo> <service> <className>com.mpaas.cq.bundleb.MyServiceImpl</className> <interfaceName>com.mpaas.cq.bundleb.api.MyService</interfaceName> <isLazy>true</isLazy> </service> </metainfo>The abstract interface class is defined as follows:
public abstract class MyService extends ExternalService { public abstract String funA(); }The interface class implementation is defined as follows:
public class MyServiceImpl extends MyService { @Override public String funA() { return "This is the interface provided by BundleB by service"; } @Override protected void onCreate(Bundle bundle) { } @Override protected void onDestroy(Bundle bundle) { } }The external call method is as follows:
MyService myservice = LauncherApplicationAgent.getInstance().getMicroApplicationContext().findServiceByInterface(MyService.class.getName()); myservice.funA();
BroadcastReceiver component
`BroadcastReceiver` is an encapsulation of android.content.BroadcastReceiver. The difference is that the mPaaS framework uses android.support.v4.content.LocalBroadcastManager to register and unregister the `BroadcastReceiver`. Therefore, these broadcasts are only used within the current application. In addition, the mPaaS framework has a series of built-in broadcast events that you can listen to.
About this task
mPaaS built-in broadcast events
mPaaS defines a variety of broadcast events, which are mainly used to monitor the status of the current application. The process of registering a listener is the same as in native development. However, note that these statuses can only be monitored in the main process. The following is sample code:
The following are the built-in broadcast events:
public interface MsgCodeConstants {
String FRAMEWORK_ACTIVITY_CREATE = "com.alipay.mobile.framework.ACTIVITY_CREATE";
String FRAMEWORK_ACTIVITY_RESUME = "com.alipay.mobile.framework.ACTIVITY_RESUME";
String FRAMEWORK_ACTIVITY_PAUSE = "com.alipay.mobile.framework.ACTIVITY_PAUSE";
// Broadcast for user leaving, pushing to background broadcast
String FRAMEWORK_ACTIVITY_USERLEAVEHINT = "com.alipay.mobile.framework.USERLEAVEHINT";
// Broadcast for all Activities being stopped. This may mean pushing to the background, but the same judgment logic is not currently used.
String FRAMEWORK_ACTIVITY_ALL_STOPPED = "com.alipay.mobile.framework.ACTIVITY_ALL_STOPPED";
String FRAMEWORK_WINDOW_FOCUS_CHANGED = "com.alipay.mobile.framework.WINDOW_FOCUS_CHANGED";
String FRAMEWORK_ACTIVITY_DESTROY = "com.alipay.mobile.framework.ACTIVITY_DESTROY";
String FRAMEWORK_ACTIVITY_START = "com.alipay.mobile.framework.ACTIVITY_START";
String FRAMEWORK_ACTIVITY_DATA = "com.alipay.mobile.framework.ACTIVITY_DATA";
String FRAMEWORK_APP_DATA = "com.alipay.mobile.framework.APP_DATA";
String FRAMEWORK_IS_TINY_APP = "com.alipay.mobile.framework.IS_TINY_APP";
String FRAMEWORK_IS_RN_APP = "com.alipay.mobile.framework.IS_RN_APP";
// Broadcast for user returning to the foreground
String FRAMEWORK_BROUGHT_TO_FOREGROUND = "com.alipay.mobile.framework.BROUGHT_TO_FOREGROUND";
}Custom broadcast events
Define the location of
metainfo.xmlas shown in the following figure:
Add the following configuration to
metainfo.xml:<?xml version="1.0" encoding="UTF-8"?> <metainfo> <broadcastReceiver> <className>com.mpaas.demo.broadcastreceiver.TestBroadcastReceiver</className> <action>com.mpaas.demo.broadcastreceiver.ACTION_TEST</action> </broadcastReceiver> </metainfo>Custom Receiver implementation
public class TestBroadcastReceiver extends BroadcastReceiver { private static final String ACTION_TEST = "com.mpaas.demo.broadcastreceiver.ACTION_TEST"; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_TEST.equals(action)) { //TODO } } }Send broadcast
LocalBroadcastManager.getInstance(LauncherApplicationAgent.getInstance().getApplicationContext()).sendBroadcast(new Intent("com.mpaas.demo.broadcastreceiver.ACTION_TEST"));
Pipeline component
The mPaaS framework has a distinct startup process. The Pipeline mechanism allows a line-of-business to encapsulate its running logic into a `Runnable` and add it to the Pipeline. The framework starts the Pipeline at the appropriate stage.
The following are the defined Pipeline timings:
com.alipay.mobile.framework.INITED: This indicates that framework initialization is complete. This event is triggered when the process starts and the framework is initialized in the background.com.alipay.mobile.client.STARTED: This indicates that the client has started to launch. This event is triggered before the UI, such as the welcome screen, is displayed.com.alipay.mobile.TASK_SCHEDULE_SERVICE_IDLE_TASK: The lowest priority. Tasks with this timing are executed only when there are no other higher-priority operations.
Because the framework invokes the Pipeline, you only need to specify the appropriate timing in metainfo.
About this task
You can download a code sample that demonstrates this universal component. For download links, usage instructions, and important notes, see Get code sample.
Procedure
Define the location of
metainfo.xmlas shown in the following figure:
Add the following configuration to
metainfo.xml:<?xml version="1.0" encoding="UTF-8"?> <metainfo> <valve> <className>com.mpaas.demo.pipeline.TestPipeLine</className> <!--pipelineName is used to specify the stage of execution--> <pipelineName>com.alipay.mobile.client.STARTED</pipelineName> <threadName>com.mpaas.demo.pipeline.TestPipeLine</threadName> <!--weight specifies the priority of the operation. The smaller the value, the higher the priority of execution.--> <weight>10</weight> </valve> </metainfo>Implement the Pipeline:
public class TestPipeLine implements Runnable { @Override public void run() { //.... } }