All Products
Search
Document Center

Register common components

Last Updated: Aug 11, 2021

Introduction

A modular design method is one of the design principles of mPaaS framework. The low coupling and high cohesion of business modules are conducive to the expansion and maintenance of businesses.

Business modules exist in the form of Bundles and the modules do not affect each other. But there are some correlations between Bundles, such as jumping to another Bundle interface, calling APIs in another Bundle, or performing some operations in Bundle to be completed during initialization.

For this reason, mPaaS is designed with the metainfo general-purpose component registration mechanism, where each Bundle declares the components that need to be registered in metaInfo.xml.

The frameworks currently supports the following components:

  • ActivityApplication (Application)
  • ExternalService (Service)
  • BroadcastReceiver
  • Pipeline

The format of metainfo.xml is as follows:

 
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <metainfo>
  3. <broadcastReceiver>
  4. <className>com.mpaas.demo.broadcastreceiver.TestBroadcastReceiver</className>
  5. <action>com.mpaas.demo.broadcastreceiver.ACTION_TEST</action>
  6. </broadcastReceiver>
  7. <application>
  8. <className>com.mpaas.demo.activityapplication.MicroAppEntry</className>
  9. <appId>33330007</appId>
  10. </application>
  11. </metainfo>

Application component

ActivityApplication is a component designed by the mPaaS framework and acts as an activity container. The ActivityApplication component allows you to manage and organize activities, specifically for solving the issue of jumping to another Bundle interface. Thus, the caller needs only to care about the ActivityApplication information registered in the framework on the business side and the agreed parameters.

About this task

A series of logic such as creation and destruction of ActivityApplication is completely managed by the mPaaS framework. The business side only needs to process the parameters it receives and manage the activities under its own business, so that the business side is effectively isolated from the caller. The business side and the caller only need to coordinate the invoked parameters, which reduces the dependency.

For Android native apps developed based on the mPaaS framework, activities must be inherited from BaseActivity or BaseFragmentActivity in order to be managed by the ActivityApplication class.

Procedure

  1. Create a metainfo.xml file in the main module of your project, and place it in the location as shown in the following figure:

  2. Write the following configurations into the metainfo.xml file, wherein:

    • className The configured class name is used to provide the class name to jump to and define the behavior of each stages. For class definitions, see codes in step three. The framework loads the corresponding class through the name defined by className. Therefore, the class must not be obfuscated and needs to be retained in the obfuscation file.
    • appId: Unique identifier of a business. The business side only needs to know the appId of the business to complete the jump. The mapping between appId and ActivityApplication is handled by the framework layer.

           
      1. <?xml version="1.0" encoding="UTF-8"?>
      2. <metainfo>
      3. <application>
      4. <className>com.mpaas.demo.hotpatch.HotpatchMicroApp</className>
      5. <appId>33330002</appId>
      6. </application>
      7. </metainfo>
  3. If the class specified by metainfo via className performs only simple jumps, the following code is used for implementation:

       
    1. /**
    2. * Scenario one:
    3. * If you can only jump to a certain activity interface, then you need to reload getEntryClassName and onRestart. For getEntryClassName, classname of the activity is returned, and for onRestart, getMicroApplicationContext().startActivity(this, getEntryClassName()) must be invoked;
    4. * Scenario two:
    5. * To jump to a different activity interface on demand, you need to reload onStart and onRestart, and jump to the specified interface based on the parameters in the Bundle project.
    6. * Created by mengfei on 2018/7/23.
    7. */
    8. public class MicroAppEntry extends ActivityApplication {
    9. @Override
    10. public String getEntryClassName() {
    11. //Scenario one: It is only possible to jump to a certain activity screen. In this case, classname is returned
    12. //return MainActivity.class.getName();
    13. //Scenario two: Jumps to a certain interface according to parameters. The null result must be returned.
    14. return null;
    15. }
    16. /**
    17. * Invoked during application creation; the implementation class can perform initialization here
    18. *
    19. * @param bundle
    20. */
    21. @Override
    22. protected void onCreate(Bundle bundle) {
    23. doStartApp(bundle);
    24. }
    25. /**
    26. * Invoked during application startup
    27. * If the application is not created yet, the create will be executed first, and then the onStart() callback
    28. */
    29. @Override
    30. protected void onStart() {
    31. }
    32. /**
    33. * When an application is destroyed, this callback function is invoked
    34. *
    35. * @param bundle
    36. */
    37. @Override
    38. protected void onDestroy(Bundle bundle) {
    39. }
    40. /**
    41. * During the application startup, if the application has been started, the onRestart() callback will be invoked instead of the onStart()
    42. *
    43. * @param bundle
    44. */
    45. @Override
    46. protected void onRestart(Bundle bundle) {
    47. //For scenario one: The getMicroApplicationContext().startActivity(this, getEntryClassName()) must be invoked here;
    48. doStartApp(bundle);
    49. }
    50. /**
    51. * When a new application is started, the current application will be paused, and the method is called back
    52. */
    53. @Override
    54. protected void onStop() {
    55. }
    56. private void doStartApp(Bundle bundle) {
    57. String dest = bundle.getString("dest");
    58. if ("main".equals(dest)) {
    59. Context ctx = LauncherApplicationAgent.getInstance().getApplicationContext();
    60. ctx.startActivity(new Intent(ctx, MainActivity.class));
    61. } else if ("second".equals(dest)) {
    62. Context ctx = LauncherApplicationAgent.getInstance().getApplicationContext();
    63. ctx.startActivity(new Intent(ctx, SecondActivity.class));
    64. }
    65. }
    66. }
  4. As the caller, you need to jump through the API provided in the MicroApplicationContext encapsulated by the framework. curId or specify null for the parameter:

       
    1. // Gets the MicroApplicationContext object:
    2. MicroApplicationContext context = MPFramework.getMicroApplicationContext();
    3. String curId = "";
    4. ActivityApplication curApp = context.getTopApplication();
    5. if (null != curApp) {
    6. curId = curApp.getAppId();
    7. }
    8. String appId = "ID of destination ApplicationActivity";
    9. Bundle bundle = new Bundle(); // Additional parameter. This paramter is not mandatory for passing.
    10. context.startApp(curId, appId, bundle);

Service component

mPaaS is designed with a service component to address the issue with invoking APIs across Bundles. The service component will be used to provide some logic as a service for being used by other modules.

About this task

The service component has the following features:

  • There is no constraint to UI.
  • The API is separated from implementation in design.

In principle, only the API classes are visible to callers. Therefore, the API classes must be defined in the API module. The implementation must be defined in the main module. Note that by default, an API module named api is generated when building a Bundle project.

External invocations are made through the findServiceByInterface API of MicroApplicationContext to get the corresponding service through interfaceName. For the use of Bundle, only the service abstract API classes, i.e. those defined in interfaceName, are exposed. Abstract API classes are defined in the API package.

Procedure

Register the service component in the following steps:

  1. Define the location of metainfo.xml, as shown in the following figure:

  2. Write the following configurations into the metainfo.xml file. The framework uses interfaceName as key, and className as value, and records the mapping relationship between them. Of them, className is the implementation class of an API, and interfaceName is the abstract API class:

       
    1. <metainfo>
    2. <service>
    3. <className>com.mpaas.cq.bundleb.MyServiceImpl</className>
    4. <interfaceName>com.mpaas.cq.bundleb.api.MyService</interfaceName>
    5. <isLazy>true</isLazy>
    6. </service>
    7. </metainfo>
    • An abstract API class is defined as follows:

           
      1. public abstract class MyService extends ExternalService {
      2. public abstract String funA();
      3. }
    • An API class implementation is defined as follows:

           
      1. public class MyServiceImpl extends MyService {
      2. @Override
      3. public String funA() {
      4. return "This is the API by service which is provided by BundleB";
      5. }
      6. @Override
      7. protected void onCreate(Bundle bundle) {
      8. }
      9. @Override
      10. protected void onDestroy(Bundle bundle) {
      11. }
      12. }
    • An external invocation method is defined as follows:
           
      1. MyService myservice = LauncherApplicationAgent.getInstance().getMicroApplicationContext().findServiceByInterface(MyService.class.getName());
      2. myservice.funA();

BroadcastReceiver component

BroadcastReceiver is the encapsulation of android.content.BroadcastReceiver, but the difference is that the mPaaS framework uses android.support.v4.content.LocalBroadcastManager to register and unregister BroadcastReciever. Therefore, these broadcasts are only used internally within the current application, and in addition, the mPaaS framework is built with a series of broadcast events for being monitored by users.

mPaaS built-in broadcast events

mPaaS defines multiple broadcast events that are primarily used to monitor the states of the current application. The registration of a listener is no different from that in a native development environment. But note that these states can only be monitored by the host process. The sample code is as follows:

Sample code

The built-in broadcast events are as follows:

 
  1. public interface MsgCodeConstants {
  2. String FRAMEWORK_ACTIVITY_CREATE = "com.alipay.mobile.framework.ACTIVITY_CREATE";
  3. String FRAMEWORK_ACTIVITY_RESUME = "com.alipay.mobile.framework.ACTIVITY_RESUME";
  4. String FRAMEWORK_ACTIVITY_PAUSE = "com.alipay.mobile.framework.ACTIVITY_PAUSE";
  5. //Broadcast indicating that a user logs off, switch-to-backend broadcast
  6. String FRAMEWORK_ACTIVITY_USERLEAVEHINT = "com.alipay.mobile.framework.USERLEAVEHINT";
  7. //Broadcast indicating that all activities stop. This may be the switch-to-backend broadcast, but no the same judgment logic applies now
  8. String FRAMEWORK_ACTIVITY_ALL_STOPPED = "com.alipay.mobile.framework.ACTIVITY_ALL_STOPPED";
  9. String FRAMEWORK_WINDOW_FOCUS_CHANGED = "com.alipay.mobile.framework.WINDOW_FOCUS_CHANGED";
  10. String FRAMEWORK_ACTIVITY_DESTROY = "com.alipay.mobile.framework.ACTIVITY_DESTROY";
  11. String FRAMEWORK_ACTIVITY_START = "com.alipay.mobile.framework.ACTIVITY_START";
  12. String FRAMEWORK_ACTIVITY_DATA = "com.alipay.mobile.framework.ACTIVITY_DATA";
  13. String FRAMEWORK_APP_DATA = "com.alipay.mobile.framework.APP_DATA";
  14. String FRAMEWORK_IS_TINY_APP = "com.alipay.mobile.framework.IS_TINY_APP";
  15. String FRAMEWORK_IS_RN_APP = "com.alipay.mobile.framework.IS_RN_APP";
  16. //Broadcast indicating that a user returns to the front-end
  17. String FRAMEWORK_BROUGHT_TO_FOREGROUND = "com.alipay.mobile.framework.BROUGHT_TO_FOREGROUND";
  18. }

Customize broadcast events

  1. Define the location of metainfo.xml, as shown in the following figure:

  2. Write the following configurations into the metainfo.xml file:

       
    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <metainfo>
    3. <broadcastReceiver>
    4. <className>com.mpaas.demo.broadcastreceiver.TestBroadcastReceiver</className>
    5. <action>com.mpaas.demo.broadcastreceiver.ACTION_TEST</action>
    6. </broadcastReceiver>
    7. </metainfo>
    • Customize Receiver implementation

           
      1. public class TestBroadcastReceiver extends BroadcastReceiver {
      2. private static final String ACTION_TEST = "com.mpaas.demo.broadcastreceiver.ACTION_TEST";
      3. @Override
      4. public void onReceive(Context context, Intent intent) {
      5. String action = intent.getAction();
      6. if (ACTION_TEST.equals(action)) {
      7. //TODO
      8. }
      9. }
      10. }
    • Send broadcast

           
      1. LocalBroadcastManager.getInstance(LauncherApplicationAgent.getInstance().getApplicationContext()).sendBroadcast(new Intent("com.mpaas.demo.broadcastreceiver.ACTION_TEST"));

Pipeline component

The mPaaS framework has an obvious startup process. The pipeline mechanism allows the business line to encapsulate its own run logic into runnable and then place it in the pipeline. The framework starts an appropriate pipeline at an appropriate stage.

The following defines the pipeline timing:

  • com.alipay.mobile.framework.INITED: The framework is initialized. The framework can also be initialized when the process starts in the background.
  • com.alipay.mobile.client.STARTED: The client starts initialization. You have to wait until a page appears, for example, the welcome page.
  • com.alipay.mobile.TASK_SCHEDULE_SERVICE_IDLE_TASK: Lowest priority. This is executed only when there are no other operations with higher priority

As the Pipeline invocation is triggered by the framework, the user only needs to specify the appropriate timing in metaInfo.

Procedure

  1. Define the location of metainfo.xml, as shown in the following figure:

  2. Write the following configurations into the metainfo.xml file:

       
    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <metainfo>
    3. <valve>
    4. <className>com.mpaas.demo.pipeline.TestPipeLine</className>
    5. <!--pipelineName is used to specify the stage at which execution occurs-->
    6. <pipelineName>com.alipay.mobile.client.STARTED</pipelineName>
    7. <threadName>com.mpaas.demo.pipeline.TestPipeLine</threadName>
    8. <!--weight is used to specify the priority of an operation. The lower the value is, the higher the execution priority is-->
    9. <weight>10</weight>
    10. </valve>
    11. </metainfo>
  3. To implement the pipeline:
       
    1. public class TestPipeLine implements Runnable {
    2. @Override
    3. public void run() {
    4. PreferenceManager.getDefaultSharedPreferences(LauncherApplicationAgent.getInstance().getApplicationContext()).edit().putString(Constants.KEY_PIPELINE_RUN_TIMESTAMP, "Pipeline running timestamp: " + System.currentTimeMillis()).apply();
    5. }
    6. }