Create a new Capacitor plugin with the CLI
You can use the Capacitor command line interface to create a new Capacitor plug-in by running this command. Since we're running the npx command to run this, you don't actually need the Capacitor CLI installed; you can just use the package directly with npx.
So when we run this command it's going to ask us for some basic information about the plugin that we are creating. So we can just make our way through these prompts here and fill in the required details.
So as an example we might just use capacitor-plugin my-plugin and you'll need to use this domain-style syntax to give it a plugin id. So typically you can just do something like com.joshmaroni.plugins.pluginname. So again we'll just use my plugin.
And then we're going to name the plugin. This is just an example so I'm just going to stick with just that example name, but obviously give your plugin a name that represents what it does. Give it a description. You can link to the git repository that is going to host this plugin. I'm not actually going to publish this plugin, but you would do something like this as an example. You can pop your name in there and a license and then we can continue to create our plugin.
So what this is going to do is just create a basic template for a plugin for us. So we're going to have an iOS and Android and a web implementation. Then we can just go ahead and modify that to implement the functionality that our plugin requires.
Okay, now that that command has finished running I'm just going to change into that and we're going to just open this up in Visual Studio Code and just take a look at what we have.
Plugin template structure and TypeScript definitions
Okay, so this is our basic plug-in template. You can see we have the android and ios folders over here which are going to contain the code for Android and iOS and we also have this source folder here which contains the definitions for our plugin.
So what we're going to do is open this up and take a look at it and you can see here that we're creating an interface that is defining the API for this plugin. So in this file we're just defining types so we're not actually doing anything yet, but it's important to set this up and it's probably also a good place to start because you can define exactly how you want your plugin to work.
So for this example we just have an echo method that is going to allow a string to be passed into it and that's going to return a promise that is also going to return a string.
Web implementation and syncing definitions
Now in this example implementation this is just going to take the string that was passed in and pass that same string back from the native code, but of course you could modify this to do whatever you want. So at this point you would modify this interface to reflect whatever methods you want to supply through your plugin and what sorts of options they are going to expect and what it's going to return back to the application.
So if you do make changes to this file you will also need to change the web.ts file. So this is where the web implementation for your plugin will live. If you might not have a web implementation you might just be having iOS and Android functionality, but even if you aren't going to implement code for the web you still do need to update this file to reflect any changes you made to the definitions file.
And you can see here for our echo method we are just logging that whatever was passed in we're logging that out. So if you are not going to have a web implementation you might just have a message logging out that this functionality isn't available on the web. Otherwise you might actually implement some kind of functionality here.
Open iOS plugin in Xcode and install CocoaPods
Okay, so now let's look at the iOS implementation. So what we're going to need to do to implement the functionality for iOS is to open the plugin.xcworkspace file which we will need to do through Xcode. So if you are already in Visual Studio Code what you could do is just right click on this and just open this up in a Finder window.
Otherwise just get to this location however you want on your machine and then right click on this plugin.xcworkspace file here and open it with Xcode. So if you've been using Capacitor already but you haven't been creating plugins then you might be familiar with opening your Capacitor projects in Xcode. The difference here is that we're not opening an entire application project; this is specifically just an Xcode project for the plugin itself.
So if we expand plugin on the left over here, open the plugin folder and then we'll find this plugin.swift file and this is the Swift code that defines the native functionality for our plugin. So when you open this project if you see an error like what you're seeing on screen here that says no such module Capacitor you can get rid of this by running pod install in the project.
Pods are kind of like npm packages, so what's happening here is essentially we haven't installed our pods which again is like npm installing packages. So we're just going to run that command manually to get rid of this error. So I'll just open up a terminal and we're just going to change into the iOS folder and then I'll just run pod install.
iOS native implementation and callbacks
Okay, so now let's look at the actual implementation here. Again, this is just the example that is created by default. If you do want to see examples of creating custom functionality I'll link to a few tutorials where you can see what custom examples might look like.
But the basic idea that is happening here is we have this plugin class and then we're just providing the methods that we defined in that API in the definitions file. So we just have an echo method here and then we just have some native Swift code that eventually calls call.success which is provided by Capacitor to provide data back to the application.
So in this case we're just grabbing the value that was passed in and then we're just passing it back through Capacitor. We're not really actually achieving anything here, but we could run whatever native code we want in here and then return whatever we want back and we could also define additional methods inside of this plugin if we wanted to provide multiple methods.
Expose iOS methods via Objective-C bridge
Now another important part of defining the iOS functionality is this plugin.m file. So this basically exposes these methods to Capacitor. So we have a CAP_PLUGIN call here that defines the plugin and then inside of here we can have multiple calls to this CAP_PLUGIN_METHOD which is going to define the various methods that our plugin provides.
So in this case we just have that single echo method which is defined in plugin.swift and we're saying that returns a promise which is why we use CAP_PLUGIN_RETURN_PROMISE. But there are other values we can use here as well. So we could use CAP_PLUGIN_RETURN_NONE for example if this wasn't going to return anything and there are also other return methods we can use as well. But for now again we'll just keep that default return promise. So that's all that's required for the iOS side of things.
Android plugin structure and Java implementation
Now let's take a look at Android. So what we're going to do is open the android folder from our plugin in Android Studio. So what we need to do inside of Android Studio is find the Java file for our plugin. Now where exactly this is is going to depend on the plugin id that you gave it when creating the plugin.
So if you recall we used an id of com.joshmaroni.plugins.example or myplugin I think it was. So if we just open the android folder and go into src then main java and then you can see it expanded out here we have com.joshmaroni.plugins.myplugin Example.java. Now again we're not going to be implementing any custom functionality here. I will link to additional tutorials where we have created custom native functionality, but again let's just focus on this basic example.
And so if you looked at the iOS example you'll see that this looks pretty similar. The syntax is a little bit different but we still have an echo method being created and it is grabbing that string that is being passed in and then it is passing that back through the call.success method which will go to Capacitor and will be passed back to our application.
So again if you wanted to define additional methods here you could. You could have others besides echo or you could replace echo completely. You could run whatever kind of native code you want here and return whatever kinds of values you want back to the application or if you prefer you don't have to return a value at all. So that's all that is required for the Android side of the plugin.
Now before we leave the Android example I do quickly want to show you where this plugin might be located now that the Android project's finished loading in properly. The file structure has changed a bit on the left so just to avoid any confusion let's just go through that example again. I'll be able to find that Java file if I go to Android, Java and then the id that was used for the plugin which is com.joshmaroni.plugins.myplugin and then we'll find that example class under that folder there.
Build, publish, and next steps
Okay, so now that we've finished implementing all the code for the plugin all we need to do in our plugin project is run npm run build. It's going to build our plugin for us and once that is finished building all we need to do is either publish the plugin to npm or we can also link to it locally if we don't want to publish it.
So I'm not going to cover those methods in this video. I do have a tutorial that discusses using npm link to use it locally and I'll link to some additional resources for publishing on npm as well. But the cool thing is once you have published it on npm you can just npm install this plugin into whatever application project you like just like you would with any other plugin.
Okay, I hope you enjoyed this tutorial. If you did please feel free to leave a like and subscribe and I'll see you in the next one.