Implementing a Capacitor plugin
Capacitor plugins provide a practical approach to structured communication through a Portal. The Capacitor bridge is used under the hood in Portals, allowing Capacitor plugins to be used.
In this step, you will author a Capacitor plugin to log analytics.
Exploring the problem
Business sponsors of the Jobsync superapp would like to allow the web apps presented through Portals to log analytic events, with the following requirements:
- The ability to log navigation to a new screen shall exist.
- The ability to log specific actions taken in the app shall exist.
- Every analytic entry shall track the platform the log occurred on.
You could use Portal's pub/sub mechanism to satisfy the requirements, but authoring a Capacitor plugin to handle analytics provides a structured, OOP-based approach to communicate through a Portal without the need to manage subscriptions.
Defining the API contract
Capacitor plugins are bound to a shared API which platform developers (iOS/Android/web) implement. During runtime, a Capacitor plugin dynamically directs calls to the appropriate implementation.
Capacitor plugins perform platform-detection under the hood, making them a good abstraction for processes that require different implementations on different platforms.
Ionic recommends using TypeScript to define the API of a Capacitor plugin. This provides a central source of truth for the API across iOS and Android as well as providing type definitions for web code.
Based on the requirements above, the following interface is reasonable for the analytics plugin:
_10interface AnalyticsPlugin {_10 logAction(opts: { action: string, params?: any }): Promise<void>;_10 logScreen(opts: { screen: string, params?: any }): Promise<void>;_10}
Notice that the interface doesn't address the requirement of tracking the running platform. This is an implementation detail that can be addressed when platform-specific code is written.
In Xcode, create a new Swift file in the Portals
folder named AnalyticsPlugin.swift
and populate the file with the following code:
Refer to How To Define a Portal API for detailed information on authoring a Capacitor plugin.
Adding the plugin to a Portal
Capacitor plugins can be added to a Portal that has been initialized. Update the Portal defined in WebAppView
, adding the AnalyticsPlugin
to the Portal:
Build and run the Jobsync app and navigate to one of the features in the dashboard view. Switch from the 'Initial Context' tab to the 'Capacitor Plugins' tab.
Look at the list of plugins. Each Portal registers a few Capacitor plugins by default, such as Console
and Portals
(which provides web access to pub/sub). You'll also see that the analytics plugin has been added as Analytics
, after the value provided for jsName
.
Expand Analytics
tap and tap logAction
. You'll be taken to a detail view for the method where you can provide input as a JSON string in the 'Argument' field and a button allowing you to execute the method. Click 'Execute logAction' and the method will run, logging to Xcode's console.
In the next section, you'll learn how to access input provided to a method in a Capacitor plugin.
Validating plugin calls
Take a look at the signature of the logAction
plugin method:
_10@objc func logAction(_ call: CAPPluginCall)
CAPPluginCall
is the call sent to the plugin method from the Capacitor bridge (which Portals uses under the hood). With it, you can access input data and either successfully resolve the call or reject the call and return an error.
Resolving or rejecting the call completes the asynchronous process initiated by the web code.
Since input data is available as part of the call, you can guard against bad input. Update logAction
to reject any calls made to the plugin method that do not contain the action
parameter:
Build, run, and navigate to the 'Capacitor Plugins' tab. Click logAction
to get to the detail view, and then press 'Execute logAction' without providing any input. The detail view will print out the message supplied to call.reject()
: "Input option 'action' must be provided.".
Using logAction
as a guide, guard logScreen
such that it rejects any calls made that do not supply screen
as input.
Test logScreen
and once complete, head to the next section to complete the implementation of the analytics plugin.
Completing the implementation
For the purpose of this training, logging analytic events consists of POSTing data to an HTTP endpoint.
Modify Portals/AnalyticsPlugin.swift
and use NetworkManager
to complete the implementation:
Start by adding a private instance of NetworkManager
to the plugin class.
Add structs to encode the body of the request and to decode the response.
Additional parameters are optional and untyped. They can be stringified and added to the request should they exist.
Make the network request. If it succeeds, call.resolve()
will resolve the call made from the web code, otherwise call.reject()
will throw an error to be handled by the web code.
logScreen
also needs to stringify params
and make the same network request. Refactor the code to add utility methods.
Update logAction
to use the new utility methods.
Finally, implement the logScreen
plugin method.
Start by adding a private instance of NetworkManager
to the plugin class.
Add structs to encode the body of the request and to decode the response.
Additional parameters are optional and untyped. They can be stringified and added to the request should they exist.
Make the network request. If it succeeds, call.resolve()
will resolve the call made from the web code, otherwise call.reject()
will throw an error to be handled by the web code.
logScreen
also needs to stringify params
and make the same network request. Refactor the code to add utility methods.
Update logAction
to use the new utility methods.
Finally, implement the logScreen
plugin method.
Build, run, and navigate to the 'Capacitor Plugins' tab. Test out the method calls by providing the following input arguments:
logAction
:{ "action": "Submit time", "params": { "time": "600" } }
logScreen
:{ "screen": "Edit Expense View", "params": {"expenseId": "123" } }
If you inspect network traffic (optional), you will see network requests made to an analytics endpoint with a data payload containing platform: 'ios'
, confirming all requirements have been met.
What's next
Authoring Capacitor plugins, like the analytics plugins, creates structured, contract-bound communication between native mobile and web code. So far, you have been testing Portals using the sample web app downloaded from the Portals CLI. In the final step of this module, you will sync the finished web apps to complete the Jobsync superapp.