Interop (FDC3)
Learn more about how FDC3 can work for you
Interop: Making apps work together
A smart desktop consists of many independent apps working together. Finsemble ensures that their windows can work together across technologies, allowing your users to launch and organize their apps into efficient workspaces. We call this Visual Integration.
Interoperability (or Interop), on the other hand, can be thought of as Logical Integration. It allows applications to exchange data and to invoke functionality in each other.
When separate applications interoperate well, a user can efficiently perform a task or a workflow. There’s no need for difficult to maintain, monolithic apps, and no need for the user to manually integrate each app via copy and paste or re-enter data. As a result, there is less risk of errors and slow-downs along the way.
There are many different ways that apps can achieve logical integration. Examples include exposing and consuming backend APIs, providing local frontend APIs, reading and writing data files, or working with messaging APIs provided by their technology platforms or specialist vendor technologies. You can use any of these techniques in Finsemble.
However, these types of integration are often based on proprietary APIs and standards. They require lengthy integration projects and bilateral agreements between app vendors or developers. They're also inflexible in that integration work you do between two applications will often not be usable if you want to add another app or replace an existing one. Instead, you will need to do yet more integration work. This is costly and time-consuming, which often leads to vendor lock-in and to failures to integrate. As a result, companies hesitate to do this work, which forces users to manually operate their workflows. And so we are back to an increased chance of errors.
FOrtunately, there is a solution to this problem: the interoperability standard that FDC3 defines. Every smart desktop and every app that follows this standard can work with anyone else that also follows it. Let’s look at this standard now.
The FDC3 standard
Finsemble tackles the integration problem by enabling front-end integration by using the Financial Desktop Connectivity and Collaboration Consortium (FDC3) Standard. This standard is defined and adopted by leading organizations across the financial industry and hosted by the Fintech Open Source Foundation (FINOS).
By standardizing an API and format for discovering and describing applications (App Directory), an API for exchanging data and invoking actions (Desktop Agent API) and both action names (Intents) and data formats (Context data), FDC3 enables rapid integration between apps without the need for bilateral agreements or new technology development. At the same time, integrated apps remain loosely coupled, making it easy to swap out or add-in new components to your smart desktop and your users' workflows.
Finsemble provides implementations of the FDC3 Desktop Agent API for both Javascript/Typescript and .NET applications. You can use them both for applications that Finsemble launches and manages, and for authenticated Freestanding applications.
From version 2.1, FDC3 also supports the interoperability between Desktop Agents via the @experimental
Desktop Agent Bridging API, which allows application interoperability between applications managed by different Desktop Agents or running on different devices by providing the first 'wire-format' definition for FDC3. Finsemble is the first Desktop Agent implementation to offer support for Desktop Agent Bridging, see FDC3 Desktop Agent Bridging for details.
Conformance to the Standard
As a Desktop Agent, Finsemble works with App Directories (AppD) and AppD records to enable the integration of apps into your smart desktop. It provides implementations of the FDC3 Desktop Agent API that those apps can use to interoperate. Hence, you can use FDC3 integrations written and tested on Finsemble or any other compliant FDC3 Desktop Agent.
This is only true as long Desktop Agent implementations produce consistent behavior. In other words, they must strictly conform to the Standard. To that end, Cosaic and Finsemble are also significant supporters of and contributors to the FDC3 Conformance Testing Framework provided by FINOS. We both run the FDC3 Conformance Testing Framework as part of Finsemble's continuous integration testing and submit releases to FINOS' FDC3 Conformance Testing Program, ensuring that we remain compliant at all times.
Finsemble currently conforms to both versions 1.2 and 2.0 of the FDC3 standard. Read more about Finsemble's Conformance to the FDC3 Standard.
Types of interop
FDC3 defines two main types of interoperability between apps:
- Context sharing: The passing of context data between applications, by broadcasting onto channels or the passing of context to newly opened applications.
- Intents: Invoking functionality within other applications via a raised Intent, describing a requested action, and Context data, describing how to perform the action and/or what object to perform it on.
Context sharing
Desktop users in Financial services often have more screens on their desks and need to work with more apps or windows as part of their workflows than in any other sector. Typical workflows might involve viewing or working with apps and UIs related to pricing data, positions, order or execution management, news and other research, risk and reporting tools, CRMs and a host of others.
These apps often work with a particular context (such as a particular stock or security, an order, a portfolio, a customer and so on), with several different apps that need to work on the same or a closely related contexts. When the user wants to move to a new context, each app has to receive it, typically from the user. However, if the apps can share that context or other related data amongst themselves, they can all navigate themselves to the right context when the user does so in any one of them. This automatic navigation improves efficiency and reduces mistakes or cut corners.
In FDC3, apps can share context data via a number of means. Let's look at these more closely.
User channels
- A set of 8 pre-created channels intended for open context sharing. Each channel is identified by a number and color.
- Apps broadcast and listen for context messages on the currently selected channel by using the API.
- The user selects the channel for each app (by using the channel selector menu on each window title bar), as shown here.
Finsemble allows apps to join multiple channels, allowing to receive and broadcast context to and from all of the channels they are connected to. This is a non-standard behavior. You can disable it by configuring an individual app or the whole desktop.
You can use selectConnect's autoAssociate
feature to automatically add apps to channels. For example, you can configure your app to put 'child' applications (those spawned by your app through fdc3.raiseIntent()
or fdc3.open()
) on the same channel as the parent, or have apps labeled with the same connectId
added to the same channel whenever they start. In this case, Finsemble selects the next free channel for a new association.
App channels
- An open-ended set of named channels created and retrieved via the API.
- App developers determine the channels used and their names, which are not discoverable and so they must be known in advance.
- Apps broadcast and listen for context on each channel.
- Apps can work with multiple channels concurrently.
Private channels
- Similar to App channels, but they are created by and retrieved from other applications via a raised Intent, allowing the channel to relate to a context. One example is a stream of pricing for a particular security.
- Intended for more private communication, rather than open context sharing.
- Provide additional lifecycle functionality to enable the creation and clean-up of data feeds.
Opening with context
- Applications can open another application by using the API. To do so, they must use its Identity, specified by an
appId
. - When you open an app, you can provide a context, which is passed to the application using the same handlers they use for User channel context. This makes the app point to the right context on launch.
Intents
While context sharing allows applications already running to track and respond to each other's context, it doesn't cover all possible interactions you might want between applications. For example, you might need to:
Perform a specific action in an application, such as viewing, creating, or updating an order.
Discover what actions are available to perform for a particular context.
Discover what apps are available to perform those actions. This is useful when your app doesn't have this info.
Start a new copy of an application, or re-use an existing one.
Request and retrieve, rather than just display, specific data or even a stream of data.
FDC3's Intent functionality enables all of these interactions by providing API functionality to raise or receive raised intents and associated context, return results back to the caller, discover what intents and resolving applications are available, and to target the raised intent at an existing app instance or start a new one. You can either target an intent programmatically, or you can defer to the user by displaying the built-in intent resolver UI.
By default, Finsemble shows the app window that receives an intent. This action might include a combination of bringing the window to front, restoring it if minimized, or showing the tab if in a tabbed group. This default behavior occurs as long as the window's autoShow option is true. You can also override the default behavior in the app’s configuration using interop.showWhenIntentReceived
, as shown in this finsemble.apps
config snippet:
"hostManifests": {
"Finsemble": {
"interop": {
"showWhenIntentReceived": false,
}
}
The Intent Resolver
When an application raises an Intent without a specified target, Finsemble must determine which application will handle it. We call this intent resolution. If there is only one option available, Finsemble automatically delivers the Intent to that app. But if there are multiple options, such as an existing instance of an app and the option to start a new instance or multiple apps that can resolve the intent, Finsemble needs user input to complete the resolution. To collect the user choice, Finsemble displays the intent resolver:
The resolver appears automatically over any application that raises an Intent without a target, whenever there’s more than one option available for resolution. The user can select either an existing application to resolve the intent or can launch a new app instance to do the resolution. The options available are determined by the interop metadata of the apps that you've added to your smart desktop.
To help the user to select from existing app instances already running, the resolver automatically highlights their windows when the user mouses-over the relevant option. If the app's window is in a tabbed group, it becomes the currently selected tab. Minimized and hidden windows are not currently highlighted.
To build efficient, assisted workflows, users can choose to remember their choices on the intent resolver by selecting the 'Remember choice' checkbox before picking an option. If they do so the resolver remembers the combination of source app instance (the one that raised the intent), Intent, Context type, and receiving app instance. If the source app subsequently raises the same Intent and Context type, the resolver will NOT appear and the intent or context will be automatically delivered to the same destination.
Remembered destinations persist in your workspace. To release a remembered choice, you must close either the source or destination app instance. You can open a new copy if you need one.
Finally, applications can also raise an unspecified intent for a particular context with the FDC3 API's fdc3.raiseIntentForContext(context)
function. This again displays the FDC3 Intent Resolver, but with the additional option for the user to pick the action from a drop down menu and then select a destination from the available options:
By leaving the choice of action to the user, you can include a single 'action' button in your app. This way the user can perform a variety of different actions - a set of options that may grow each time new applications are added to your smart desktop.
Do more with selectConnect
After several years of experience working with FDC3, and in response to requests from customers, Finsemble also provides several features that go beyond what the FDC3 Standard defines. This includes methods of controlling information flow between apps, making Finsemble's interop easier to use by auto-associating applications with channels, allowing apps to join multiple user channels, or enabling external and virtualized applications to participate in FDC3 interop.
For more details see Augmenting FDC3: selectConnect.
Using the FDC3 API
Adding apps to your smart desktop
The first step in using the FDC3 API is to add applications to your desktop - whether chosen from selected vendors or developed in-house.
Finsemble provides 2 ways of adding an app. The easier way is to use the Smart Desktop Designer (SDD), The designer is a graphical interface that helps you add apps, no coding needed. For more info, see Add and manage apps and services with SDD.
The other way to add apps is via configuration either for individual applications or the import of whole App Directories. See Add apps to your smart desktop for more detail.
As soon as you start developing an FDC3 integration to add interoperability to your app, you'll need other apps to develop and test against. Having seen many teams develop throwaway apps to use as test harnesses for their work, the Finsemble team decided to develop and Open Source the FDC3 Workbench application to help provide a better development experience. You'll find a configuration for the FDC3 Workbench included in the Finsemble seed project and SDD by default. You can also check out our tutorial on Integrating FDC3-compliant apps into a workflow using the FDC3 workbench.
Getting access to the API
JavaScript
For a web application to be FDC3-enabled, it needs to run in the context of an environment or Platform Provider that makes the FDC3 API available to the application. As Finsemble is an FDC3 Platform Provider, you can rely on the global window.fdc3
object, which is available to your application as described by the FDC3 Supported Platforms page.
Finsemble makes the FDC3 API available immediately. There’s no need to implement a check or wait for the fdc3Ready
event, as described by the FDC3 documentation. However, if your code needs to run in other Desktop Agents you should handle this as described by FDC3.
Finally, if you'd like to import individual operations using ES6 import syntax, you need to use the wrapper functions provided in the @finos/fdc3 NPM module.
TypeScript
Applications built with TypeScript access the FDC3 API in the same way that regular JavaScript apps do. However, you will want access to types for the FDC3 API. These are provided by the @finos/fdc3 NPM module which defines types for the window.fdc3
global and any functions you import from the NPM module using ES6 import syntax.
.NET
The Finsemble DLL provides an implementation of an FDC3 client for Finsemble, allowing your .NET applications to interoperate with both each other and web apps running in or integrated with Finsemble. The DLL is available from Nuget. See Integrating Native apps for more details on usage and some example projects.
To use the integration import the types for the FDC3 API:
using ChartIQ.Finsemble.FDC3.Types;
You can connect to Finsemble, as described in Integrating Native apps and associated example projects, and start making API calls:
var context = new Context(new JObject
{
["type"] = "fdc3.instrument",
["name"] = DataToSend.TextBox.Text,
["id"] = new JObject
{
["ticker"] = DataToSend.TextBox.Text
}
});
FSBL.FDC3Client.DesktopAgentClient.Broadcast(context);
Freestanding apps (.NET)
Freestanding .NET apps, that is apps not started by Finsemble but that connect into it using the Finsemble DLL and static authentication, can also make use of Finsemble's .NET FDC3 API implementation.
Because FInsemble doesn’t start these applications, it cannot use them to resolve intents unless they are already running and have registered their listeners. Also, make sure that they identify their appId
on connection to associate them with a configuration.
Freestanding apps (JavaScript)
JavaScript apps running in a web browser or web view in a native application can connect into Finsemble and use the FDC3 API by using the Finsemble JavaScript Adapter. See Integrating freestanding apps with the JavaScript adapter for more information.
Virtual apps (Citrix)
Virtualized applications, such as those running on a remote Citrix server, are displayed within windows on the local desktop so that the app appears to the user to be running locally. This would usually present a problem for application interop. However, virtual apps launched through Finsemble may participate in FDC3 interop with locally running applications by communicating with Finsemble through a Microsoft Terminal Services plug-in. A virtual app then behaves in a similar way to a local app: the user can link such an app to a channel, have it broadcast and receive context, and raise and listen for intents, etc..
See Setting up the virtual app interop for more information.
The Citrix plug-in is not a standard part of Finsemble and you must obtain it separately. Contact your sales rep for details.
Core concepts
The following sections provide a brief introduction to using FDC3 API to add interop to your app. For further information on using the FDC3 API see its FDC3 Standard documentation and API reference.
Opening apps
You can open an instance of an application using the appId
set in its appD record by calling:
try {
const appIdentifier = await fdc3.open({appId: "myAppId"});
} catch (err){
console.error("An error occurred while spawning the application: " + err.message);
}
You can use the AppIdentifier
object returned to target further API calls at the instance of the application that you started.
Context sharing
User Channels
By design, users control sharing context data on User Channels. To participate in it, your app must register a handler for context messages by making one of the following calls as soon as possible after it starts up:
//listen for all context types
const listener = await fdc3.addContextListener(null, async (context) => {
if (context.type === "fdc3.instrument") {
/* handle fdc3.instrument context messages here*/
} else if (context.type === "someOtherContext") {
/* etc. */
}
});
//listen for just fdc3.instrument context messages
const listener = await fdc3.addContextListener("fdc3.instrument", async (context) => {
/* handle fdc3.instrument context messages here*/
});
You can use the returned Listener
object to later unsubscribe a listener if you want: call listener.unsubscribe()
.
To broadcast your context on to the channel whenever it changes, make this call:
let context = { type: "fdc3.instrument", id: { ticker: "MSFT" } };
await fdc3.broadcast(context);
Users can add your app's window to one or more channels by using the Linker menu in the top-left corner of the window. While on that channel, your broadcast messages go to other apps on the channel. You also receive messages when other apps broadcast. If the user removes your app from the channel, your app stops receiving messages and any that you broadcast are ignored. When your app joins a new channel, you automatically receive its current context immediately.
For more details see the FDC3 Standard documentation section on Joining User Channels and the API reference for fdc3.addContextListener
and fdc3.broadcast
.
Opening apps (with Context)
When opening an application via FDC3, you can pass an optional Context object as an additional argument:
try {
let context = { type: "fdc3.instrument", id: { ticker: "MSFT" } };
const appIdentifier = await fdc3.open({appId: "myAppId"}, context);
} catch (err){
console.error("An error occurred while spawning the application: " + err.message);
}
When the application starts up and adds a User Channel context listener by using fdc3.addContextListener()
, as used above to listen for context on User Channels, this context is passed to it.
This is the one case where the app doesn’t have to be on a User Channel to receive a Context via the User Channel listener. If you don’t also want to participate in User Channel context sharing, remove the listener after starting up with listener.unsubscribe()
.
For more details see the API reference for fdc3.open
.
App Channels
In contrast to User Channels, App Channels provide developer-controlled communication channels that don’t allow any direct user interactions. The channels have arbitrary names and are interacted with through the API only. There is no way to discover the names of existing channels. So, you can use these channels only by prior agreement between application developers or within a single suite of applications.
To create or retrieve a channel object call:
const channel = await fdc3.getOrCreateChannel("MyChannelName");
You can then use the channel object to retrieve the current context of the channel, listen for new context messages or broadcast context:
//get the most recent Context on the channel
const context = await channel.getCurrentContext();
//get the most recent contact Context on the channel
const contactContext = await channel.getCurrentContext("fdc3.contact");
//add a ContextListener
const listener = await channel.addContextListener(null, async (context) => {
if (context.type === "fdc3.instrument") {
/* handle fdc3.instrument context messages here*/
} else if (context.type === "someOtherContext") {
/* etc. */
}
});
//broadcast your Context
await channel.broadcast(context);
Unlike User Channels, App Channels don’t automatically send you their current Context when you add a listener to them. If you need to know the current Context, retrieve it with channel.getCurrentContext()
.
For more details, see the FDC3 Standard documentation section on Direct Listening and Broadcast on Channels and the API reference for the Channel Object.
Private channels
You can only create Private channels locally or receive them as a result from a raised Intent. They're intended for sending or receiving a stream of data relating to a particular request, for example a stream of pricing or orders relating to a particular instrument. For more details see the Intents section later in this topic.
Intents
Raising Intents
To add an action button or similar interaction to your app that will trigger behavior in another app via an Intent; raise the Intent and pass along an appropriate Context object:
const resolution = await fdc3.raiseIntent("ViewChart", context);
If there are multiple options for where to send the Intent and Context, the FDC3 Intent Resolver appears as described earlier. After the user resolves the Intent, you can use the IntentResolution
object find out where the intent ended up.
Alternatively, if you know the appId
for the application you want to send the intent to, or the full AppIdentifier
for a particular instance of an app (for example because you used fdc3.open
or a previous fdc3.raiseIntent
call to open it), you can pass that along as a third argument to send it straight there:
const appIdentifier = {appId: 'ChartIQ Example App', instanceId: 'fdc3-instanceId-ChartIQ Example App=2dc32acd-27b9-4309-994f-716d1057d538'};
const resolution = await fdc3.raiseIntent("ViewChart", context, appIdentifier);
Finally, if you'd like to let the user choose the action to perform (the 'Intent') use the fdc3.raiseIntentForContext
function:
const resolution = await fdc3.raiseIntentForContext(context);
For more details, see the FDC3 Standard documentation section on Raising Intents and the API reference for the fdc3.raiseIntent
and fdc3.raiseIntentForContext
functions.
Receiving results
If the app handling the Intent returns a result, which could be either a single Context
object or a Channel
, you can also use the IntentResolution
to receive it:
//Raise an intent and retrieve a result from the IntentResolution
let resolution = await agent.raiseIntent("intentName", context);
try {
const result = await resolution.getResult();
if (result && result.broadcast) { //detect whether the result is Context or a Channel
console.log(`${resolution.source} returned a channel with id ${result.id}`);
} else if (result){
console.log(`${resolution.source} returned data: ${JSON.stringify(result)}`);
} else {
console.error(`${resolution.source} didn't return anything`
}
} catch(error) {
console.error(`${resolution.source} returned a result error: ${error}`);
}
For more details about receiving Intent results see the API reference for the fdc3.raiseIntent
.
Handling raised Intents
Your app must register an IntentHandler for each Intent you want to receive as soon as possible after it starts up:
const listener = await fdc3.addIntentListener("ViewChart", async (context) => {
if (context.type === "fdc3.instrument") {
/* handle ViewChart with fdc3.instrument context messages here */
} else if (context.type === "someOtherContext") {
/* etc. */
}
return;
});
Use the finsemble.apps[].interop.intents.listensFor
configuration setting in your AppD record to declare what Intents your app listens for. This allows the Interop service and FDC3 Intent Resolver to offer your app as a destination and to start an instance of it to resolve Intents. For more information about creating appD records see An application directory.
For more details about receiving Intents see the API reference for fdc3.addIntentListener
.
Returning results
When you receive an Intent, you can return a result for the application that raised the Intent to pick up. There are two types of IntentResult
that you can return: a Context Object or a Channel.
To return a Context result, return it from your IntentHandler
function:
const listener = await fdc3.addIntentListener("CreateOrder", async (context) => {
if (context.type === "fdc3.order") {
/* handle CreateOrder with fdc3.order context messages here */
context.id = { orderId: "XYZ" };
//then return the result
return context;
} else if (context.type === "someOtherContext") {
throw new Error("Unrecognized context type received");
}
});
If you need to return a stream of responses, for example updates on an order or a pricing stream for a particular Instrument, you can return a Channel. Here’s an example that returns an App Channel:
const listener = await fdc3.addIntentListener("GetPricing", async (context) => {
if (context.type === "fdc3.instrument") {
/* handle GetPricing with fdc3.instrument context messages here */
Const ticker = context.id.ticker;
const pricingChannel = await fdc3.getOrCreateChannel("pricing-" + ticker);
//start streaming pricing to the channel in another process
//then return the result to the caller
return pricingChannel;
} else if (context.type === "someOtherContext") {
throw new Error("Unrecognized context type received");
}
});
Sometimes you might want to be able to synchronize the start of your data streaming to an app starting to listen to it, and to clean up after they leave. In that case, use a PrivateChannel
which offers a number of additional callbacks for that purpose:
const listener = await fdc3.addIntentListener("GetPricing", async (context) => {
if (context.type === "fdc3.instrument") {
/* handle GetPricing with fdc3.instrument context messages here */
Const ticker = context.id.ticker;
const pricingChannel = await fdc3.createPrivateChannel();
// This gets called when the remote side adds a context listener
const addContextListener = channel.onAddContextListener((contextType) => {
// broadcast price quotes as they come in from our quote feed
feed.onQuote(symbol, (price) => {
pricingChannel.broadcast({ type: "price", price});
});
});
// This gets called when the remote side calls Listener.unsubscribe()
const unsubscriberListener = channel.onUnsubscribe((contextType) => {
feed.stop(symbol);
});
// This gets called if the remote side closes
const disconnectListener = channel.onDisconnect(() => {
feed.stop(symbol);
});
//then return the result to the caller
return pricingChannel;
} else if (context.type === "someOtherContext") {
throw new Error("Unrecognized context type received");
}
});
For more details about returning results from Intents see the API reference for fdc3.addIntentListener
and the API reference for PrivateChannel
.
Configuration
There are a number of Finsemble configuration options that affect either how applications interact with interop or interop as a whole within your smart desktop.
App-level configuration
Finsemble adopts the FDC3 2.0 appD format for app configuration, which provides details to launch an application and manage its interoperability. For example, you can declare what intents the app listens for. For more details about how to configure your app for FDC3 interop and about the format generally see Application directory (appD).
In addition to the standard appD configuration, each appD record can contain proprietary manifests for configuring the app when running in a particular Desktop Agent. For Finsemble you'll find this at finsemble.apps[].hostManifests.Finsemble
. The manifest supports a number of configuration settings specific to interop in Finsemble, including:
finsemble.apps[].hostManifests.Finsemble.interop.joinMultipleChannels
: If explicitly set tofalse
, an app cannot join multiple user channels.finsemble.apps[].hostManifests.Finsemble.interop.launchable
: If explicitly set tofalse
, an app is not launchable from the FDC3 UI resolver for handling an intent. This property is independent from thelaunchableByUser
property affecting the App Launcher menu.finsemble.apps[].hostManifests.Finsemble.interop.selectConnect
: Properties relating to the selectConnect configuration. See Augmenting FDC3: selectConnect for more details.finsemble.apps[].hostManifests.Finsemble.interop.useLinker
: The linker menu is turned on by default for any app that uses FDC3. Set this flag tofalse
to turn off the linker for this app. For example, set this flag tofalse
if your app only uses App channels.finsemble.apps[].hostManifests.Finsemble.signatureKeyURL
: URL specifying the location of the signature key. This is an alternative to providing thesignatureKey
with the Finsemble configuration.
Desktop-level configuration
Here are the 3 most important desktop-level configuration settings:
finsemble.servicesConfig.interop.allowResolverToRemember
: Set to false to disable the 'Remember your choice' checkbox on the FDC3 Intent Resolver for all applications. The default istrue
.finsemble.servicesConfig.interop.addIntentListenerMaxInitializationTimeout
: Sets the maximum length of time (in milliseconds) that the interop service will wait forfdc3.addIntentListener()
to be invoked by an application started to resolve an intent. The default is15000
.finsemble.servicesConfig.interop.visible
: Set totrue
to display the Interop Service's window, which provides a set of Redux devtools that you can use to debug problems with FDC3 interactions. The default isfalse
.
Getting involved in FDC3
Cosaic and the Finsemble team are big supporters of FDC3, currently leading development and maintenance of the Standard. If you'd like to get involved in the FDC3 community, let us know via your Finsemble account representative or the Finsemble support team, and we'll be happy to help make introductions and get you started. You should also take a look at the getting involved section of the FDC3 Github repository readme.
See also
For more info about adding apps to your desktop, see Integrating HTML applications and Integrating native apps.
For more info about appD, see Application directory (appD).
To learn more about FDC3 and how to make your apps compliant, see Integrating FDC3-compliant apps into a workflow using the FDC3 workbench and the FDC3 Standard documentation.
To go beyond the FDC3 Standard with Finsemble' extended FDC3 feature set, see Augmenting FDC3: selectConnect.
To enable FDC3-based interop between applications running under Finsemble and other Desktop Agents, or on different devices, see FDC3 Desktop Agent Bridging.
For an alternative introduction to all things FDC3, see FDC3: Interoperability for the Financial Desktop.