Skip to main content

How To Define a Portal API

One of the biggest benefits of including Ionic Portals in an application is the ability to easily communicate between web and native code using the PortalsPlugin. However, in some more niche cases, creating your own Plugins may be neccessary. By creating a Capacitor Plugin, you can create your own API to communicate between web and native code.

For this example, we will create a Plugin called EchoPlugin that has a single function: echo.

Creating API Definitions#

We strongly recommend using TypeScript to create a type defintion file which can be used to define your API. This way, there is a central source of truth for the API across Android and iOS as well as having type defintions for the web code.

export interface EchoPlugin {   echo(options: { value: string }): Promise<{ value: string }>;}

On the Android or iOS side, the EchoPlugin class will need to match this type signature.


If you are not using TypeScript, you can skip this step, but you'll need to take steps to make sure that the method signatures across Android and iOS match if you are using reusing Portals across multiple mobile applications.

Implementing the API#

First, you'll need to install the proper dependencies. You can now start building the plugin. In this example, the EchoPlugin will extend the base Capacitor Plugin class and implement the API that was defined in the previous step.

import Capacitor
@objc(ECHO_PLUGIN)public class EchoPlugin: CAPPlugin {  @objc func echo(_ call: CAPPluginCall) {    let value = call.getString("value");    print(value);  }}

In iOS, if you require Objective-C compatibility, you'll also need a file called EchoPlugin.m to create Objective-C bindings with helper functions that Capacitor provides. Below is an example of EchoPlugin Objective-C bindings.

#import <Capacitor/Capacitor.h>
CAP_PLUGIN(ECHO_PLUGIN, "EchoPlugin",  CAP_PLUGIN_METHOD(echo, CAPPluginReturnNone);)

Adding the Plugin to the Portal#

After creating the Capacitor Plugin, add the Plugin to the Portal to use it.


When creating a Portal via the PortalManager, you'll need to call the PortalManager.addPlugin() function in order to add the Plugin to that Portal instance.

PortalManager.newPortal("echo_portal")    .addPlugin(    .create()


After a Portal has loaded, you will need to inject the Plugin to the Portal's bridge. You can do this in the viewDidLoad function.

override func viewDidLoad() {    // Inject the plugin into the native bridge    apiPlugin = bridge?.plugin(withName: "EchoPlugin") as? EchoPlugin        // now call super which will start the initial load    super.viewDidLoad()    }

Calling Your Plugin Code via the Web#

Once the Plugin has been defined, implemented, and initialized in the native code, you will need to register the Plugin on the web. To do this, you can use the Capacitor.registerPlugin() function. After calling this function, Capacitor will handle communication across native and web code.

import { registerPlugin } from "@capacitor/core";import { EchoPlugin } from "./types";
const Plugin = registerPlugin<EchoPlugin>("EchoPlugin");export default Plugin;

Once the Plugin has been registered in the web code, you can use it anywhere in your codebase without needing to register it again in the web code.

import EchoPlugin from './echo-plugin'
EchoPlugin.echo("Hello World!")


For more information on how to create Capacitor Plugins, check our guide for creating Capacitor Plugins.