Skip to content

PlatformHub ViewProvider

Introduction

The ViewProvider API has been extracted as an extension of PlatformHub into a separate module.

This change provides the following benefits:

  • Decouples the core PlatformHub functionality from any UI dependency
  • Follows the open-closed principle by making PlatformHub open for extension
  • Applies best practices like separation of concerns

This module contains interfaces and Kotlin extensions for PlatformHub's interoperability. It is an optional extension that allows to pass navigation functions between plugins. It supports navigation using:

  • Activity (by passing the Intent instance)
  • Fragment
  • Composable

Setup

Note:

Please check latest version of Navigation available for integration in PlatformHub README.md

To use this extension library, both the sender and receiver plugins need to add the following dependency:

groovy
platformhubNavigationVersion = "3.0.0"
implementation "com.skyrin.mobilebanking:platformhub-navigation:$platformhubNavigationVersion"

Policy

Both the sender and receiver plugins need to have correlated entries in their policy .json files under send.navigationQueries and receive.navigationQueries respectively.

  • sender
json
{
  "name": "SenderPlugin",
  "publish": {
    "eventStreams": []
  },
  "SubscribeOnStartup": {
    "eventStreams": []
  },
  "send": {
    "commands": [],
    "navigationQueries": [
      {
        "messageName": "ExampleMessageName",
        "pluginName": "ReceiverPlugin"
      }
    ],
    "queries": []
  },
  "receive": {
    "commands": [],
    "navigationQueries": [],
    "queries": []
  }
}
  • receiver
json
{
  "name": "ReceiverPlugin",
  "publish": {
    "eventStreams": []
  },
  "SubscribeOnStartup": {
    "eventStreams": []
  },
  "send": {
    "commands": [],
    "navigationQueries": [],
    "queries": []
  },
  "receive": {
    "commands": [],
    "navigationQueries": [
      {
        "messageName": "ExampleMessageName",
        "pluginName": "ReceiverPlugin"
      }
    ],
    "queries": []
  }
}

To view the structure of the policy file, please click on the links below:

Policy_Version_1

Policy_Version_2

Note:

ActivityNavResponse, FragmentNavResponse, ComposableNavResponse removed in v3.0.0 release because it is renamed as ActivityViewQueryResponse, FragmentViewQueryResponse and ComposableViewQueryResponse.

Also ActivityNavigationRequest, FragmentNavigationRequest and ComposableNavigationRequest removed in v3.0.0 release because it is renamed as ActivityViewQuery, FragmentViewQuery and ComposableViewQuery.

v2.3.0 will support both the legacy and new APIs. However, in v3.0.0, only the new APIs will be available, as deprecated code has been removed and will no longer be accessible.

It is recommended to update to the newer version of PH-Navigation v3.0.0.

Sender plugin

The sender plugin can perform a navigation using MessageSender.requestNavigation extension function. It passes a request through the PlatformHub's MessageSender instance. For an ActivityNavResponse, the call would look like:

kotlin
messageSender.fetchView(
    ViewQuery.ActivityViewQuery(
        messageName = "ExampleMessageName",
        pluginName = "ReceiverPlugin"
    ),
    plugin = plugin
  ).let { it as? ViewQueryResponse.ActivityViewQueryResponse }
      ?.also { startActivity(it.intent(requireContext())) }

and for an FragmentViewQueryResponse:

kotlin
messageSender.fetchView(
    ViewQuery.FragmentViewQuery(
        messageName = "ExampleMessageName",
        pluginName = "ReceiverPlugin"
    ),
    plugin = plugin
).let { it as? ViewQueryResponse.FragmentViewQueryResponse }
    ?.also { addFragmentSomewhere(it.fragment()) }

Here is an example for ActivityViewQuery to captures the payload for logging:

kotlin
  messageSender.fetchView(
    ViewQuery.ActivityViewQuery(
          messageName = "ExampleMessageName",
          pluginName = "MigrationExamplePlugin",
          payload = JSONObject("""{ "userId": "1" }""".trimIndent())
      ),
      plugin = plugin
  ).let { it as? ViewQueryResponse.ActivityViewQueryResponse }
      ?.also { startActivity(it.intent(requireContext())) }

As mentioned in above example it is similar for FragmentViewQuery, ComposableViewQuery you need pass the payload to capture it in logging.

To navigate using the Compose (with AndroidX Navigation) features, the pluginComposable extension function can be used:

kotlin
NavHost(
    navController = navController,
    startDestination = startDestination,
    modifier = Modifier
) {
    // Navigates to outside plugin
    pluginComposable(
        routePrefix = "proxyRoute",
        messageName = "ExampleMessageName",
        plugin = plugin,
        arguments = listOf(
            navArgument("userId") {
                type = NavType.StringType
                nullable = true
            }
        )
    ) { _, response ->
        response.composable()
    }
}

To trigger this defined navigation node, you can call NavHostController extensions:

kotlin
navController.navigateToPlugin(
    routePrefix = proxyRoute,
    pluginName = "ReceiverPlugin",
    optionalArgs = mapOf("userId" to "1102")
)

Receiver plugin

The library provides 3 interfaces from which, at least one, needs to be implemented by the receiver plugin:

  • ActivityViewQueryRouter
  • FragmentViewQueryRouter
  • ComposableViewQueryRouter

(NOTE: Any Plugin can implement all 3 at the same time if required)

Each of them allows a plugin to return its corresponding response.

ActivityViewQueryRouter example:

kotlin
class ExamplePlugin constructor(assetsLoader: AssetsLoader) :
    Plugin(assetsLoader),
    ActivityViewQueryRouter {
    override val policyFilename: String = "example-plugin-policy.json"

    override fun init(
        context: Context,
        configurationFiles: Map<String, InputStream>
    ) {
        Timber.tag(TAG).d("plugin init.")
    }

    override fun onActivityViewQuery(
        viewQuery: ViewQuery
    ): ViewQueryResponse =
        ViewQueryResponse.ActivityViewQueryResponse { context ->
            Intent(context, ExampleActivity::class.java)
        }
}

Migration from mobile-navigation-android-lib

mobile-navigation-android-lib is going to be dropped in favour of platformhub-navigation (as a part of general platformhub transition).

  1. Integrate with platformhub core.
  2. Add dependency
groovy
implementation "com.skyrin.mobilebanking:platformhub-navigation:$platformhubNavigationVersion"
  1. Remove handler registration, eg:
kotlin
val navigationHandler: NavigationJourneyHandler = NavigationJourneyHandlerImpl.getInstance()

val journeys =
    arrayListOf(
        NavigationInfo(
          "SHOW_LOGON",
          NavigationType.ActivityJourney(LogonActivity::class.java)
        )
    )

  navigationHandler.registerJourneys(journeys)

and add proper router interface to your plugin:

kotlin
class MigrationExamplePlugin constructor(assetsLoader: AssetsLoader) :
    Plugin(assetsLoader),
  ActivityViewQueryRouter {
    override val policyFilename: String = "migration-example-plugin-policy.json"

    override fun init(
        context: Context,
        configurationFiles: Map<String, InputStream>
    ) {
        Timber.tag(TAG).d("plugin init.")
    }

    override fun onActivityViewQuery(
        viewQuery: ViewQuery
    ): ViewQueryResponse =
        ViewQueryResponse.ActivityViewQueryResponse { context ->
            Intent(context, LogonActivity::class.java)
        }
}

Fragments can be provided by implementing FragmentViewQueryRouter interface.

  1. Add proper entries in plugins as shown in here.
  2. UI elements launching responsibility has been moved from target plugin to the source plugin, so previous:
  • for Fragment
kotlin
navigationHandler.launchJourney(
    "SHOW_STATEMENTS",
    NavigationMode.NewFragment(
      activity as NavigationFragmentHolder,
      this
    ),
    activity
)

has to be changed to:

kotlin
messageSender.fetchView(
  ViewQuery.FragmentViewQuery(
        messageName = "ExampleMessageName",
        pluginName = "MigrationExamplePlugin"
    ),
    plugin = plugin
).let { it as? ViewQueryResponse.FragmentViewQueryResponse }
    ?.also { addFragmentSomewhere(it.fragment()) }
  • for Activity
kotlin
navigationHandler.launchJourney(
    "SHOW_LOGON",
    NavigationMode.SingleTaskActivity(),
    activity
)

has to be changed to:

kotlin

messageSender.fetchView(
  ViewQuery.ActivityViewQuery(
        messageName = "ExampleMessageName",
        pluginName = "MigrationExamplePlugin"
    ),
    plugin = plugin
).let { it as? ViewQueryResponse.ActivityViewQueryResponse }
    ?.also { startActivity(it.intent(requireContext())) }

:::caution

The uuid field present in NavigationRequest and ViewQuery is strictly intended for internal use and should not be utilized by value streams (VSs). If you are currently using it, please plan to phase out its usage and transition to your own implementation.

:::

  1. PH navigation repository (aOS)