Appearance
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 theIntentinstance)FragmentComposable
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:
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:
ActivityViewQueryRouterFragmentViewQueryRouterComposableViewQueryRouter
(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).
- Integrate with
platformhubcore. - Add dependency
groovy
implementation "com.skyrin.mobilebanking:platformhub-navigation:$platformhubNavigationVersion"- 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.
- Add proper entries in plugins as shown in here.
- 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.
:::