From ebe24d638c0066452f770d8b71713ffd8f93a48a Mon Sep 17 00:00:00 2001 From: Erisu Date: Sat, 21 Jun 2025 16:29:15 +0900 Subject: [PATCH 1/5] doc(ios): plugin development guide --- www/docs/en/dev/guide/platforms/ios/plugin.md | 461 ++++++++++++------ 1 file changed, 301 insertions(+), 160 deletions(-) diff --git a/www/docs/en/dev/guide/platforms/ios/plugin.md b/www/docs/en/dev/guide/platforms/ios/plugin.md index f1ba5c1c7f..45deefb565 100644 --- a/www/docs/en/dev/guide/platforms/ios/plugin.md +++ b/www/docs/en/dev/guide/platforms/ios/plugin.md @@ -23,134 +23,180 @@ toc_title: iOS # iOS Plugin Development Guide -This section provides details for how to implement native plugin code -on the iOS platform. +- [iOS Plugin Development Guide](#ios-plugin-development-guide) + - [Creating an Cordova Plugin for iOS](#creating-an-cordova-plugin-for-ios) + - [Adding Native Source Code](#adding-native-source-code) + - [Configuring the `plugin.xml`](#configuring-the-pluginxml) + - [Adding Plugin Code to iOS Project](#adding-plugin-code-to-ios-project) + - [Setting Class Mapping for WebView-to-Native Communication](#setting-class-mapping-for-webview-to-native-communication) + - [Configuring Plugin Initialization Timing](#configuring-plugin-initialization-timing) + - [Supporting Swift Package Manager (SPM)](#supporting-swift-package-manager-spm) + - [Creating SPM's `Package.swift` File](#creating-spms-packageswift-file) + - [Additional Native Side Implementation](#additional-native-side-implementation) + - [Executing Plugin Initialization Logic](#executing-plugin-initialization-logic) + - [Handeling Long-running \& Background Activities](#handeling-long-running--background-activities) + - [Hooking into WKURLSchemeTask](#hooking-into-wkurlschemetask) + - [Using Background Threads](#using-background-threads) + - [CDVPluginResult Message Types](#cdvpluginresult-message-types) + - [Other Supported `CDVPlugin` Features](#other-supported-cdvplugin-features) + - [Debugging Plugins for iOS](#debugging-plugins-for-ios) + - [Common Pitfalls](#common-pitfalls) -Before reading this, see [Plugin Development Guide][plugin-dev] for -an overview of the plugin's structure and its common JavaScript -interface. This section continues to demonstrate the sample _echo_ -plugin that communicates from the Cordova webview to the native -platform and back. -An iOS plugin is implemented as an Objective-C class that extends the -`CDVPlugin` class. For JavaScript's `exec` method's `service` -parameter to map to an Objective-C class, each plugin class must be -registered as a `` tag in the named application directory's -`config.xml` file. +This guide provides details on implementing native plugin code for the iOS platform. The plugin's native code can be written in either Objective-C or Swift. -## Plugin Class Mapping +Before proceeding, refer to the [Plugin Development Guide][plugin-dev] for an overview of plugin structure, plugin core files, and its common JavaScript interface. This guide will continue to use the _echo_ plugin, as an exmaple, which enables communication between the Cordova WebView and the native platform. -The JavaScript portion of a plugin uses the `cordova.exec` method as -follows: +## Creating an Cordova Plugin for iOS -```javascript -exec(, , , , []); -``` +In this section we will cover: -This marshals a request from the `UIWebView` to the iOS native side, -effectively calling the `action` method on the `service` class, with -the arguments passed in the `args` array. +1. Adding Native Source Code +2. Configuring `plugin.xml` + - Adding Plugin Code to iOS Project + - Setting Class Mapping for WebView-to-Native Communication +3. Adding Swift Package Manager Support +4. Additional Native Side Implementation -Specify the plugin as a `` tag in your Cordova-iOS -application's project's `config.xml` file, using the `plugin.xml` file -to inject this markup automatically, as described in [Plugin Development Guide][plugin-dev]: +### Adding Native Source Code -```xml - - - -``` +In the following example, we will place all files in the `src/ios/` directory. This directory will be located inside the Cordova plugin's project root directory. The name and path of the directory are not strict and can be customized as you prefer. However, this is the typical pattern used by official Apache Cordova plugins to separate platform-specific source code and resources. -The feature's `name` attribute should match what you specify as the -JavaScript `exec` call's `service` parameter. The `value` attribute -should match the name of the plugin's Objective-C class. The `` -element's `name` should always be `ios-package`. If you do not follow -these guidelines, the plugin may compile, but Cordova may still not be -able to access it. +- **Swift** -## Plugin Initialization and Lifetime + In Swift, the implementation source code is written inside a `.swift` file. This is where the business logic is performed. -One instance of a plugin object is created for the life of each -`UIWebView`. Plugins are not instantiated until they are first -referenced by a call from JavaScript, unless `` with an `onload` -`name` attribute is set to `"true"` in `config.xml`. For example, + To expose methods written in Swift to Objective-C, the `@objc` annotation needs to be added. When the `@objc` annotation is used, those methods are automatically included in the `-Swift.h` header file. This is required so that Cordova can locate and invoke them. -```xml - - - - -``` + **Echo.swift (Source File):** -Plugins should use the `pluginInitialize` method for their startup logic. + In this example, when the `echo` method is invoked, an `.ok` response with the provided message is returned if the message exists; otherwise, an `.error` is returned. -Plugins with long-running requests or background activities such as media -playback, listeners, or that maintain internal state should implement -the `onReset` method to cancel those long-running requests or to clean up -after those activities. -The method runs when the `UIWebView` navigates to a new page or refreshes, which -reloads the JavaScript. + ```swift + #if canImport(Cordova) + import Cordova + #endif -## Writing an iOS Cordova Plugin + @objc(Echo) + class Echo : CDVPlugin { + @objc func sample(_ command : CDVInvokedUrlCommand) { + let myarg = command.arguments[0]; + let pluginResult; -A JavaScript call fires off a plugin request to the native side, and -the corresponding iOS Objective-C plugin is mapped properly in the -`config.xml` file, but what does the final iOS Objective-C plugin -class look like? Whatever is dispatched to the plugin with -JavaScript's `exec` function is passed into the corresponding plugin -class's `action` method. A plugin method has this signature: + if (myarg != nil) { + pluginResult = CDVPluginResult(status: .ok, messageAs: myarg) + } else { + pluginResult = CDVPluginResult(status: .error) + } -```objective_c -- (void)myMethod:(CDVInvokedUrlCommand*)command -{ - CDVPluginResult* pluginResult = nil; - NSString* myarg = [command.arguments objectAtIndex:0]; + self.commandDelegate.send(pluginResult, callbackId: command.callbackId) + } + } + ``` + +- **Objective-C** + + **Echo.h (Header File):** + + The header file defines the methods and properties that are exposed to other native classes. We also expose the methods that the front-end WebView requests so that Cordova can locate and invoke them. + + In this example, we are exposing the `echo` method: + + ```objc + #import + + @interface Echo : CDVPlugin + + - (void)echo:(CDVInvokedUrlCommand*)command; + + @end + ``` + + **Echo.m (Source File):** + + The implementation source code (.m files) is where the business logic is performed. + + In this example, when the `echo` method is invoked, it examines the contents of the first argument to determine if there is something to echo back to the front-end WebView. If there is content, a `OK` result is returned with the message; otherwise, an `ERROR` is returned. - if (myarg != nil) { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Arg was null"]; + ```objc + #import "Echo.h" + #import + + @implementation Echo + + - (void)echo:(CDVInvokedUrlCommand*)command + { + CDVPluginResult* pluginResult = nil; + NSString* echo = [command.arguments objectAtIndex:0]; + + if (echo != nil && [echo length] > 0) { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:echo]; + } else { + pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; + } + + [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} -``` -For more details, see - [CDVInvokedUrlCommand.h][CDVInvokedUrlCommand.h], [CDVPluginResult.h][CDVPluginResult.h], -and [CDVCommandDelegate.h][CDVCommandDelegate.h]. + @end + ``` -## iOS CDVPluginResult Message Types +**Additional Notes:** -You can use `CDVPluginResult` to return a variety of result types back to -the JavaScript callbacks, using class methods that follow this pattern: +- Plugin entry classes must extend `CDVPlugin`. +- Supporting classes does not extend `CDVPlugin`. +- The following `import` statements are required to be added to the top of the plugin entry classes. -```objective_c -+ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAs... -``` + Swift based project will added the following to the source file: -You can create `String`, `Int`, `Double`, `Bool`, `Array`, -`Dictionary`, `ArrayBuffer`, and `Multipart` types. You can also leave -out any arguments to send a status, or return an error, or even choose -not to send any plugin result, in which case neither callback fires. + ```swift + #if canImport(Cordova) + import Cordova + #endif + ``` -Note the following for complex return values: + Objective-C based projects will added the following to the header & source files: + + ```objc + #import + ``` + +**Additional References:** + +For more details, see the following class headers: + +- [CDVInvokedUrlCommand.h][CDVInvokedUrlCommand.h] +- [CDVPluginResult.h][CDVPluginResult.h] +- [CDVCommandDelegate.h][CDVCommandDelegate.h] + +### Configuring the `plugin.xml` + +#### Adding Plugin Code to iOS Project + +Now that we have our native source code written in our plugin project, we need to add these resource files to the application's directory. This ensures that the source code is available and used by the app. This can be achieved by defining the `` and `` elements in the `plugin.xml`. + +Below is an example of what this should look like inside the `plugin.xml`: + +```xml + + + -- `messageAsArrayBuffer` expects `NSData*` and converts to an - `ArrayBuffer` in the JavaScript callback. Likewise, any - `ArrayBuffer` the JavaScript sends to a plugin are converted to - `NSData*`. + + + + +``` + +_Note:_ If you are following along with **Objective-C**, be sure to update the above accordingly. In the example above, we are using **Swift**. -- `messageAsMultipart` expects an `NSArray*` containing any of the - other supported types, and sends the entire array as the `arguments` - to your JavaScript callback. This way, all of the arguments are - serialized or deserialized as necessary, so it is safe to return - `NSData*` as multipart, but not as `Array`/`Dictionary`. +What the above configuration does is for the iOS platform, it places the header file and source file in the appropriate location within the application. It also creates the necessary references in the Xcode project so that the application will recognize and use these files. -## Echo iOS Plugin Example +#### Setting Class Mapping for WebView-to-Native Communication -To match the JavaScript interface's _echo_ feature described in -Application Plugins, use the `plugin.xml` to inject a `feature` -specification to the local platform's `config.xml` file: +To be able to trigger native functionality in JavaScript, the native classes needs to be mapped within `plugin.xml` by using the `` element. + +Below is an example of what this should look like once the feature is added to the `plugin.xml` from the previous steps, combined: ```xml @@ -158,85 +204,129 @@ specification to the local platform's `config.xml` file: - + + + + + + + + ``` +Specify the plugin's `` tag ensures that the necessary configuration is automatically injected into the Cordova-iOS project, as described in the [Plugin Development Guide][plugin-dev]. -Then we would add the following `Echo.h` and `Echo.m` files to the -`Plugins` folder within the Cordova-iOS application directory: +Lets break down what each element and attribute means. +- `` + - The `name` attribute should match with the `service` parameter' value that is used in the JavaScript `cordova.exec` method call. +- `` + - The `value` attribute should match the name of the plugin'sObjective-C or Swift class name. + - The `name` attribute should always have the value of `ios-package` for iOS plugins. -```objective_c -/********* Echo.h Cordova Plugin Header *******/ +If the follow guidelines are not met, the plugin may compile but Cordova will not be able to access it. -#import +**IMPORTANT NOTE:** During the platform preparation for building the app, an auto-generated merged `config.xml` file is created. This file contains all platform-specific application configurations and plugin data gathered from the application's `config.xml` and the plugin's `plugin.xml`. The `config-file` block, as shown in the example above, ensures that the plugin's feature is injected into the merged `config.xml`, allowing the plugin to function properly. This `config.xml` is separate from the application's root `config.xml`. -@interface Echo : CDVPlugin +#### Configuring Plugin Initialization Timing -- (void)echo:(CDVInvokedUrlCommand*)command; +A single instance of a plugin object is typically created for the lifecycle of each `WKWebView`, though the instantiation timing depends on the plugin's implementation. -@end +By default, plugins are instantiated when they are first referenced by a call from JavaScript. However, plugins can be configured to instantiate when the app loads by defining the `onload` attribute within a `` element in the plugin's `plugin.xml` configuration file. This `` should be added to the plugin's `` element. -/********* Echo.m Cordova Plugin Implementation *******/ +For example: + +```xml + + + + +``` -#import "Echo.h" -#import +### Supporting Swift Package Manager (SPM) + +Starting from Cordova-iOS 8 and greater, support for the Swift Package Manager has been implemented. To start using SPM with your plugin, a `Package.swift` file will need to be created in the plugin's root directory and a couple of things needs to be set and made aware in the `plugin.xml`. + +#### Creating SPM's `Package.swift` File + +In the plugin's root directory, create a new file called `Package.swift` with the following content: + +```swift +// swift-tools-version:5.5 + +import PackageDescription + +let package = Package( + name: "cordova-plugin-echo", + platforms: [.iOS(.v13)], + products: [ + .library(name: "cordova-plugin-echo", targets: ["cordova-plugin-echo"]) + ], + dependencies: [ + .package(url: "https://github.com/apache/cordova-ios.git", branch: "master") + ], + targets: [ + .target( + name: "cordova-plugin-echo", + dependencies: [ + .product(name: "Cordova", package: "cordova-ios") + ], + path: "src/ios", + resources: [], + publicHeadersPath: "." + ) + ] +) +``` -@implementation Echo +If the plugin has a privacy manifest to declare, you can add the following line `.copy("Resources/PrivacyInfo.xcprivacy")` to the `cordova-plugin-echo` `target` `resources` element. + +If the plugin requires for any third-party dependencies, it should be added to the `dependencies` element, and the `target`'s `dependencies`. + +For example: + +```swift +dependencies: [ + ... + .package(name: "SomePackageName", url: "...", from: "1.0.0"), +], +targets: [ + .target( + ... + dependencies: [ + .product(name: "Cordova", package: "cordova-ios"), + .product(name: "SomePackageLibraryName", package: "SomePackageName") + ], + ) +] +``` -- (void)echo:(CDVInvokedUrlCommand*)command -{ - CDVPluginResult* pluginResult = nil; - NSString* echo = [command.arguments objectAtIndex:0]; +### Additional Native Side Implementation - if (echo != nil && [echo length] > 0) { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:echo]; - } else { - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]; - } +#### Executing Plugin Initialization Logic - [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; -} +If the plugin has any logic that should execute on the during the plugin's initialization process, the `pluginInitialize` method should be defined in the plugin's class. -@end -``` +For example, if the plugin has defined `onload` as `true`, when the app loads, the `pluginInitialize` method will be executed. Because this is triggered during app load, there is no `callbackID` so the `pluginInitialize` method can not return any results to the WebView. If results matter, they would need to be stored in some manar and later fetched with a JavaScript API call. -The necessary imports at the top of the file extends the class from -`CDVPlugin`. In this case, the plugin only supports a single `echo` -action. It obtains the echo string by calling the `objectAtIndex` -method get the first parameter of the `arguments` array, which -corresponds to the arguments passed in by the JavaScript `exec()` -function. +#### Handeling Long-running & Background Activities -It checks the parameter to make sure it is not `nil` or an empty -string, returning a `PluginResult` with an `ERROR` status if so. If -the parameter passes the check, it returns a `PluginResult` with an -`OK` status, passing in the original `echo` string. Finally, it sends -the result to `self.commandDelegate`, which executes the `exec` -method's success or failure callbacks on the JavaScript side. If the -success callback is called, it passes in the `echo` parameter. +Plugins with long-running requests or background activities, such as media playback, listeners, or those that maintain internal state, should implement the `onReset` method to cancel these requests or clean up after those activities. -## iOS Integration +The `onReset` method is called when the `WKWebView` navigates to a new page or refreshes, triggering a reload of the JavaScript. -The `CDVPlugin` class features other methods that your plugin can -override. For example, you can capture the [pause][PauseEvent], [resume][ResumeEvent], app -terminate and `handleOpenURL` events. See the -[CDVPlugin.h][CDVPlugin.h] and [CDVPlugin.m][CDVPlugin.m] -classes for guidance. +#### Hooking into WKURLSchemeTask -### WKURLSchemeTask Hook +The [WKURLSchemeTask](https://developer.apple.com/documentation/webkit/wkurlschemetask) is an interface Cordova's main WKWebView uses to load files from your app's bundle. You can create your own custom schemes or custom loading code for the WebView by implementing the `- (BOOL) overrideSchemeTask: (id )urlSchemeTask` method in a plugin. -The [WKURLSchemeTask](https://developer.apple.com/documentation/webkit/wkurlschemetask) is an interface Cordova's main WKWebView uses to load files from your app's bundle. You can create your own custom schemes or custom loading code for the webview by implementing the `- (BOOL) overrideSchemeTask: (id )urlSchemeTask` method in a plugin. +#### Using Background Threads -## Threading +Plugin methods ordinarily execute in the same thread as the main interface. If your plugin requires a great deal of processing or requires a blocking call, you should use a background thread. -Plugin methods ordinarily execute in the same thread as the main -interface. If your plugin requires a great deal of processing or -requires a blocking call, you should use a background thread. For -example: +For example: -```objective_c +```objc - (void)myPluginMethod:(CDVInvokedUrlCommand*)command { // Check command.arguments here. @@ -250,19 +340,70 @@ example: } ``` -## Debugging iOS Plugins +## CDVPluginResult Message Types + +You can use `CDVPluginResult` to return a variety of result types back to the JavaScript callbacks, using class methods that follow this pattern: + +```objc ++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAs... +``` -To debug on the Objective-C side, you need Xcode's built-in debugger. -For JavaScript, you can attach Safari to the app running within the iOS Simulator/Device. +The following types can be used: + +- `String` +- `Int` +- `Double` +- `Bool` +- `Array` +- `Dictionary` +- `ArrayBuffer` +- `Multipart` + +You can also leave out any arguments to send a status, or return an error, or even choose not to send any plugin result, in which case neither callback fires. + +Note the following for complex return values: + +- `messageAsArrayBuffer` expects `NSData*` and will convert it to an `ArrayBuffer` in the JavaScript callback. Likewise, any `ArrayBuffer` the JavaScript sends to a native side will be converted to `NSData*`. + +- `messageAsMultipart` expects an `NSArray*` containing any of the other supported types, and sends the entire array as the `arguments` to your JavaScript callback. This way, all of the arguments are serialized or deserialized as necessary, so it is safe to return `NSData*` as multipart, but not as `Array`/`Dictionary`. + +## Other Supported `CDVPlugin` Features + +The `CDVPlugin` class features other methods that a plugin can override. + +For example, the plugin can capture: +- [`pause`][PauseEvent] Event +- [`resume`][ResumeEvent] Event +- App Terminate Event +- `handleOpenURL` events + +For additional reference, see the following classes: + +- [CDVPlugin.h][CDVPlugin.h] +- [CDVPlugin.m][CDVPlugin.m] + +## Debugging Plugins for iOS + +To debug the native side, you will need to use Xcode's built-in debugger. + +For JavaScript, you can launch the Safari Web Inspector and attach it to the running application process. The app can be running on either an iOS Simulator or device. + +Generally, its recommended to use a debug build for testing as it should already allow the WebView to be inspectable. If for any reason you need to test on a release build, you can enable WebView Inspector by setting the `InspectableWebview` config preference to `true` in the application's `config.xml`. + +E.g. + +```xml + +``` + +For security purpose, its highly unrecommended to enable the `InspectableWebview` for release builds. If you do set it, remove the setting before deploy the app to the app store. ## Common Pitfalls -- Don't forget to add your plugin's mapping to `config.xml`. If you - forget, an error is logged in the Xcode console. +- Don't forget to add your plugin's mapping to `plugin.xml`. If you forget, an error is logged in the Xcode console. + +- Don't forget to add any hosts you connect to in the allow list, as described in Domain [Allow List Guide](../../appdev/allowlist/index.html). If you forget, an error is logged in the Xcode console. -- Don't forget to add any hosts you connect to in the allow list, as - described in Domain [Allow List Guide](../../appdev/allowlist/index.html). If you forget, an error is - logged in the Xcode console. [plugin-dev]: ../../hybrid/plugins/index.html [CDVInvokedUrlCommand.h]: https://github.com/apache/cordova-ios/blob/master/CordovaLib/Classes/Public/CDVInvokedUrlCommand.h From be77259df5747ffa8777d0ec283f93a7ea09f2f5 Mon Sep 17 00:00:00 2001 From: Erisu Date: Sat, 21 Jun 2025 16:34:18 +0900 Subject: [PATCH 2/5] doc: update create a plugin guide --- www/docs/en/dev/guide/hybrid/plugins/index.md | 441 ++++++++---------- 1 file changed, 188 insertions(+), 253 deletions(-) diff --git a/www/docs/en/dev/guide/hybrid/plugins/index.md b/www/docs/en/dev/guide/hybrid/plugins/index.md index ab8c58f735..7c7b652ac6 100644 --- a/www/docs/en/dev/guide/hybrid/plugins/index.md +++ b/www/docs/en/dev/guide/hybrid/plugins/index.md @@ -24,268 +24,101 @@ description: Develop your own Cordova plugin. # Create a Plugin -A _plugin_ is a package of injected code that allows the Cordova webview within -which the app renders to communicate with the native platform on -which it runs. Plugins provide access to device and platform -functionality that is ordinarily unavailable to web-based apps. All -the main Cordova API features are implemented as plugins, and many -others are available that enable features such as bar code scanners, -NFC communication, or to tailor calendar interfaces. You can search for available plugins -on [Cordova Plugin Search page](/plugins/). - -Plugins comprise a single JavaScript interface along with -corresponding native code libraries for each supported platform. In essence -this hides the various native code implementations behind a common -JavaScript interface. - -This section steps through a simple _echo_ plugin that passes a string from -JavaScript to the native platform and back, one that you can use as a -model to build far more complex features. This section discusses the -basic plugin structure and the outward-facing JavaScript interface. -For each corresponding native interface, see the list at the end of -this section. - -In addition to these instructions, when preparing to write a plugin it -is best to look over [existing plugins](https://cordova.apache.org/contribute) -for guidance. - -## Building a Plugin - -Application developers use the CLI's [plugin add command][cdv_plugin] to add a plugin to a project. The -command takes the URL for a _git_ repository containing -the plugin code as an argument. This example implements Cordova's Device API: - -```bash -cordova plugin add https://github.com/apache/cordova-plugin-device -``` +- [Create a Plugin](#create-a-plugin) + - [Creating an npm Package](#creating-an-npm-package) + - [Updating the npm Package for Cordova](#updating-the-npm-package-for-cordova) + - [Adding the plugin's `id`](#adding-the-plugins-id) + - [Specifying supported platforms](#specifying-supported-platforms) + - [Adding keywords for discoverability](#adding-keywords-for-discoverability) + - [Adding engine requirements](#adding-engine-requirements) + - [Upper Bounds](#upper-bounds) + - [Creating the `plugin.xml` file](#creating-the-pluginxml-file) + - [Adding a Front-End JavaScript API](#adding-a-front-end-javascript-api) + - [`cordova.exec` Command Syntax](#cordovaexec-command-syntax) + - [Creating the `www/api.js` File](#creating-the-wwwapijs-file) + - [Injecting the JavaScript API to the `window` Object](#injecting-the-javascript-api-to-the-window-object) + - [Implementing Native Interfaces](#implementing-native-interfaces) + - [Testing a Plugin during development](#testing-a-plugin-during-development) + - [Publishing Plugins](#publishing-plugins) -If the plugin is published to _npm_, the command can also receive the package name as the argument: -```bash -cordova plugin add cordova-plugin-device -``` +A Cordova _plugin_ is a package that enables the Cordova apps to access native device features and functionality that is ordinarily unavailable to web-based apps. All of the core Cordova API features are implemented as plugins. Many third-party plugins are also available to provide additional capabilities such as barcode scanning, NFC communication, push notification, or even customizing interfaces. -The plugin repository must feature a top-level `plugin.xml` manifest -file. There are many ways to configure this file, details for which -are available in the [Plugin Specification](../../../plugin_ref/spec.html). +Check out these locations for Cordova plugins: -This abbreviated version of the `Device` plugin provides a simple example to use as a model: +- Official Apache Cordova plugins on the [Cordova Plugin page](/plugins/). +- Third-party plugins on the [npmjs registry](https://www.npmjs.com/search?q=keywords:ecosystem:cordova). -```xml - - - Device - Cordova Device Plugin - Apache 2.0 - cordova,device - - - - - - - - - - - - - -``` +Plugins consist of a single JavaScript interface paired with corresponding native code libraries for each supported platform. In essence, this hides the platform-specific native implementations behind a common JavaScript interface. -- The top-level `plugin` tag's `id` attribute usually follows the `cordova-plugin-{plugin name}` schema and matches the plugin's npm package name. -- The `js-module` tag specifies the path to the [common -JavaScript interface](#the-javascript-interface). -- The `platform` tag specifies a corresponding -set of native code, for the `ios` platform in this case. -- The `config-file` tag encapsulates a `feature` tag that is injected into -the platform-specific `config.xml` file to make the platform aware of -the additional code library. -- The `header-file` and `source-file` tags -specify the path to the library's component files. - -## The JavaScript Interface - -The JavaScript interface provides the front-facing interface, making it perhaps -the most important part of the plugin. You can structure your -plugin's JavaScript however you like, but you need to call -`cordova.exec` to communicate with the native platform, using the -following syntax: +This page will walk through the steps to create a basic _echo_ plugin that passes a string from the frontend JavaScript to the native platform and back. The purpose of this guide is to provide a model for how to build and publish a Cordova plugin. It focuses on the fundamentals of plugin structure and the outward-facing JavaScript interface. -```javascript -cordova.exec(function(winParam) {}, - function(error) {}, - "service", - "action", - ["firstArgument", "secondArgument", 42, false]); -``` - -Here is how each parameter works: +For the corresponding native implementations, see the list at the end of this section. -- `function(winParam) {}`: A success callback function. Assuming your - `exec` call completes successfully, this function executes along - with any parameters you pass to it. +In addition to following these instructions, it is recommended to review [existing plugins](https://cordova.apache.org/contribute) for further guidance. -- `function(error) {}`: An error callback function. If the operation - does not complete successfully, this function executes with an - optional error parameter. +## Creating an npm Package -- `"service"`: The service name to call on the native side. This - corresponds to a native class, for which more information is - available in the native guides listed below. +In essence, a Cordova plugin is an extension of an npm package. By leveraging the npm ecosystem, plugin developers can easily publish their plugins to the npm registry, allowing app developers to install them into their Cordova apps using the Cordova CLI. -- `"action"`: The action name to call on the native side. This - generally corresponds to the native class method. See the native - guides listed below. +Even if you don't plan to publish your plugin publicly, you still need to structure it as an npm package for installation purposes. The [`cordova plugin add`][cdv_plugin] command relies on npm under the hood to fetch and install plugins. -- `[/* arguments */]`: An array of arguments to pass into the native - environment. +First, we'll create the directory for our `echo` plugin and change to this newly created directory: -## Sample JavaScript - -This example shows one way to implement the plugin's JavaScript -interface: - -```javascript -window.echo = function(str, callback) { - cordova.exec(callback, function(err) { - callback('Nothing to echo.'); - }, "Echo", "echo", [str]); -}; +```zsh +mkdir cordova-plugin-echo +cd cordova-plugin-echo ``` -In this example, the plugin attaches itself to the `window` object as -the `echo` function, which plugin users would call as follows: +Next, we'll initialize it as an npm package using the `npm init` command. In this example, we'll accept all default values for the initialization process by appending the `-y` flag. If you want to customize the values, you can omit the flag or change the values later by editing the `package.json` file. -```javascript -window.echo("echome", function(echoValue) { - alert(echoValue == "echome"); // should alert true. -}); +```zsh +npm init -y ``` -Look at the last three arguments passed to the `cordova.exec` function. The -first calls the `Echo` _service_, a class name. The second requests -the `echo` _action_, a method within that class. The third is an array -of arguments containing the echo string, which is the `window.echo` -function's first parameter. - -The success callback passed into `exec` is simply a reference to the -callback function of `window.echo`. If the native platform fires -the error callback, it simply calls the success callback and passes it -a default string. +**One important note:** the directory name `cordova-plugin-echo` will be used as the default package name and will be published as such to the npm registry. If the name is already taken, you'll need to choose a different name or use [scoped packages](https://docs.npmjs.com/cli/v10/using-npm/scope). -## Native Interfaces +### Updating the npm Package for Cordova -Once you define JavaScript for your plugin, you need to complement it -with at least one native implementation. Details for each platform are -listed below, and each builds on the simple Echo Plugin example above: +In addition to the standard properties that the `package.json` file includes for npm, Cordova-specific properties will also be added. These are necessary to define the plugin's ID, supported platforms, relevant keywords for discoverability, and engine requirements. -- [Android Plugins](../../platforms/android/plugin.html) -- [iOS Plugins](../../platforms/ios/plugin.html) +#### Adding the plugin's `id` -## Testing a Plugin during development - -The simplest way to manually test a plugin during development is to create a -Cordova app as usual and add the plugin with the `--link` option: +This uniquely identifies your plugin within the Cordova ecosystem. It's generally recommended to match the plugin ID with the npm package name so that when a Cordova project is restored using the `cordova prepare` command, the package can be easily located in the npm registry. -```bash -cordova plugin add ../path/to/my/plugin/relative/to/project --link +```zsh +npm pkg set cordova.id=cordova-plugin-echo ``` -This creates a symbolic link instead of copying the plugin files, which enables you to work on your plugin and then simply rebuild the app to use your changes. The plugin should be added after the platform, or the link will not work. The link will also be lost if you re-add the platform or [restore the project](../../../platform_plugin_versioning_ref/index.md) with `cordova prepare`. In that case, you'll need to re-add the plugin to restore the link. +#### Specifying supported platforms -## Validating a Plugin using Plugman +The following example shows how to add support for both Android and iOS. You can modify this to include only the platforms your plugin supports. -You can use the `plugman` utility to check whether the plugin installs -correctly for each platform. Install `plugman` with the following -[node](https://nodejs.org/) command: - -```bash -npm install -g plugman +```zsh +npm pkg set "cordova.platforms[]=android" +npm pkg set "cordova.platforms[]=ios" ``` -You need a valid app source directory, such as the top-level `www` -directory included in a default CLI-generated project, as described in the -[Create your first app](../../cli/index.html) guide. +#### Adding keywords for discoverability -Then run a command such as the following to test whether iOS -dependencies load properly: +Keywords help others find your plugin via search. -```bash -plugman install --platform ios --project /path/to/my/project/www --plugin /path/to/my/plugin +```zsh +npm pkg set "keywords[]=cordova" +npm pkg set "keywords[]=echosystem:cordova" +npm pkg set "keywords[]=cordova-android" +npm pkg set "keywords[]=cordova-ios" ``` -For details on `plugman` options, see [Using Plugman to Manage Plugins](../../../plugin_ref/plugman.html). For information on how to actually _debug_ plugins, see [each platform's native interface listed above](#native-interfaces). - -## Publishing Plugins - -You can publish your plugin to any `npmjs`-based registry, but the recommended one is the [npm registry](https://www.npmjs.com). Other developers can install your plugin automatically using either `plugman` or the Cordova CLI. - -To publish a plugin to npm you need to follow these steps: - - * install the `plugman` CLI: +#### Adding engine requirements - ```bash - $ npm install -g plugman - ``` +**Cordova 6.1.0** added support for specifying the Cordova-related dependencies of a plugin as part of the plugin's `package.json` file. Plugins may list the dependencies for multiple releases to provide guidance to the Cordova CLI when it is selecting the version of a plugin to fetch from npm. The CLI will choose the latest release of a plugin that is compatible with the local project's installed platforms and plugins as well as the the local Cordova CLI version. If no releases of the plugin are compatible, the CLI will warn the user about the failed requirements and fall back to the old behavior of fetching the latest release. - * create a `package.json` file for your plugin: +This feature is intended to eventually replace the [engines element](../../../plugin_ref/spec.html#engines-and-engine) in `plugin.xml`. - ```bash - $ plugman createpackagejson /path/to/your/plugin - ``` +Listing dependencies is a good way to ensure that your plugin will not appear broken or cause build errors when fetched from npm. If the latest release of the plugin is not compatible with a project, the CLI will give the app developer a list of unmet project requirements so that they are aware of incompatibilites and can update their project to support your plugin. This allows your plugin to respond to breaking changes without fear of confusing devlopers who are building against old platforms and plugins. - * publish it: - - ```bash - $ npm adduser # that is if you don't have an account yet - $ npm publish /path/to/your/plugin - ``` - -For more details on npm usage, refer to [Publishing npm Packages](https://docs.npmjs.com/getting-started/publishing-npm-packages) on the npm documentation site. - -## Integrating with Plugin Search - -To surface the plugin in [Cordova Plugin Search](/plugins/), add the `ecosystem:cordova` keyword to the `package.json` file of your plugin before publishing. - -To indicate support for a particular platform, add a keyword in the format `cordova-` to the list of keywords in `package.json`. -Plugman's `createpackagejson` command does this for you, but if you did not use it to generate your `package.json`, you should manually edit it as shown below. - -For example, for a plugin that supports Android & iOS the keywords in `package.json` should include: - -```json -"keywords": [ - "ecosystem:cordova", - "cordova-android", - "cordova-ios" -] -``` - -For a more detailed example of a package.json, review the [package.json file of cordova-plugin-device](https://github.com/apache/cordova-plugin-device/blob/master/package.json). - -## Specifying Cordova Dependencies - -**Cordova 6.1.0** added support for specifying the Cordova-related dependencies of a plugin -as part of the plugin's `package.json` file. Plugins may list the dependencies for multiple -releases to provide guidance to the Cordova CLI when it is selecting the version of a -plugin to fetch from npm. The CLI will choose the latest release of a plugin that is -compatible with the local project's installed platforms and plugins as well as the -the local Cordova CLI version. If no releases of the plugin are compatible, the CLI will warn -the user about the failed requirements and fall back to the old behavior of fetching the -latest release. - -This feature is intended to eventually replace the [engines element](../../../plugin_ref/spec.html#engines-and-engine) in plugin.xml. -Listing dependencies is a good way to ensure that your plugin will not appear broken or cause -build errors when fetched from npm. If the latest release of the plugin is not compatible with -a project, the CLI will give the app developer a list of unmet project requirements so that -they are aware of incompatibilites and can update their project to support your plugin. This -allows your plugin to respond to breaking changes without fear of confusing devlopers who -are building against old platforms and plugins. - -To specify Cordova-related dependencies for a plugin, alter the `engines` element in -`package.json` to include a `cordovaDependencies` object with the following -structure: +To specify Cordova-related dependencies for a plugin, alter the `engines` element in `package.json` to include a `cordovaDependencies` object with the following structure: ```javascript "engines": { @@ -307,14 +140,9 @@ structure: * Another Cordova plugin: `"cordova-plugin-camera"`, etc. * `SEMVER_RANGE` should adhere to the syntax for a range as defined by [npm's semver package][npm-semver] -**NOTE:** A Cordova platform `DEPENDENCY` refers to the Cordova platform and not -the OS, i.e. `cordova-android` rather than the Android OS. +**NOTE:** A Cordova platform `DEPENDENCY` refers to the Cordova platform and not the OS, i.e. `cordova-android` rather than the Android OS. -Your `cordovaDependencies` may list any number of `PLUGIN_VERSION` requirements -and any number of `DEPENDENCY` constraints. Versions of your plugin -that do not have their dependencies listed will be assumed to have the same -dependency information as the highest `PLUGIN_VERSION` listed below them. For -example, consider the following entry: +Your `cordovaDependencies` may list any number of `PLUGIN_VERSION` requirements and any number of `DEPENDENCY` constraints. Versions of your plugin that do not have their dependencies listed will be assumed to have the same dependency information as the highest `PLUGIN_VERSION` listed below them. For example, consider the following entry: ```javascript "engines": { @@ -324,22 +152,12 @@ example, consider the following entry: } } ``` -All plugin versions below the lowest entry (1.0.0 in this example) are assumed -to have no dependencies. Any version of the plugin between 1.0.0 and 2.1.0 is -assumed to have the same dependencies as version 1.0.0 (a cordova-android -version less than 3.0.0). This lets you only update your `cordovaDependencies` +All plugin versions below the lowest entry (1.0.0 in this example) are assumed to have no dependencies. Any version of the plugin between 1.0.0 and 2.1.0 is assumed to have the same dependencies as version 1.0.0 (a cordova-android version less than 3.0.0). This lets you only update your `cordovaDependencies` information when there are breaking changes. -### Upper Bounds +##### Upper Bounds -In addition to a single version, a `PLUGIN_VERSION` in `cordovaDependencies` -may also specify an upper bound to amend entries for older releases -of your plugin. This is useful when a breaking change occurs in a `DEPENDENCY` -and a new constraint must be added for all older versions of a plugin that do -not support it. These bounds should be written as a `<` followed by a single -[semver][npm-semver] version (**Not an arbitrary range!**). This will apply -whatever `DEPENDENCY` values are given to all versions of the plugin below the -specified version. For example, consider the following entry: +In addition to a single version, a `PLUGIN_VERSION` in `cordovaDependencies` may also specify an upper bound to amend entries for older releases of your plugin. This is useful when a breaking change occurs in a `DEPENDENCY` and a new constraint must be added for all older versions of a plugin that do not support it. These bounds should be written as a `<` followed by a single [semver][npm-semver] version (**Not an arbitrary range!**). This will apply whatever `DEPENDENCY` values are given to all versions of the plugin below the specified version. For example, consider the following entry: ```javascript "engines": { @@ -351,18 +169,135 @@ specified version. For example, consider the following entry: } ``` -Here we specify one plugin version (0.0.1) and two upper bounds (<1.0.0 and <2.0.0) -that constrain cordova-ios. The two upper bounds do not override the constraint -of 0.0.1, they are combined via AND at evaluation time. When the CLI checks the -cordova-ios version of the project, the constraint that will be evaluated for -plugin version 0.0.1 will be the combination of these three: +Here we specify one plugin version (0.0.1) and two upper bounds (<1.0.0 and <2.0.0) that constrain cordova-ios. The two upper bounds do not override the constraint of 0.0.1, they are combined via AND at evaluation time. When the CLI checks the cordova-ios version of the project, the constraint that will be evaluated for plugin version 0.0.1 will be the combination of these three: + +> cordova-ios >1.0.0 AND cordova-ios <2.0.0 AND cordova-ios <5.0.0 + +Please note that the only `PLUGIN_VERSION` values allowed are single versions or upper bounds; no other semver ranges are supported. + +## Creating the `plugin.xml` file + +Plugins must also be paired with a top-level `plugin.xml` manifest file. This file is used for configuring the plugin. See the [Plugin.xml Specification](../../../plugin_ref/spec.html) for more information of the elements that can be defined. + +Below is a simple example of the `plugin.xml` file that will be used for the `Echo` plugin and a model to follow for creating your own plugins. +```xml + + + Echo + Cordova Echo Plugin + Apache 2.0 + cordova,plugin,echo + ``` - cordova-ios >1.0.0 AND cordova-ios <2.0.0 AND cordova-ios <5.0.0 + +> Note: The top-level `plugin` tag's `id` attribute usually follows the `cordova-plugin-{plugin name}` schema and matches the plugin's npm package name. + +## Adding a Front-End JavaScript API + +Plugin developers typically include a front-end JavaScript API. The primary purpose is to abstract away Cordova's internal APIs, eliminate the need for app developers to understand the specific naming of your plugin's service or methods, and simplify the overall usage of the plugin. + + +### `cordova.exec` Command Syntax + +```javascript +exec(, , , , []); +``` + +The `cordova.exec` method is is what triggeres the request from the front-end WebView to the native side of the platform, invoking an action method on the specified service class with the provided arguments. Depending on the outcome, either the success or failure callback will be triggered. + +- **`successCallback`**: The first argument is the success callback. If the native operation completes successfully, this function is invoked with any returned data. +- **`failCallback`**: The second argument is the error callback. If the operation fails, this function is called with an error object or message. +- **`service`**: A string representing the service name on the native side. This typically matches a native class defined in your plugin. +- **`action`**: A string representing the method name to invoke on the native service. +- **`[arguments]`**: An array of arguments to be passed to the native method. + +### Creating the `www/api.js` File + +In this example, we'll create a folder named `www` in the plugin's root directory and add a file named `api.js`. + +> Note: The directory and file names are customizable and do not need to follow this exact structure. However, if you choose to rename the directory or file, be sure to update the corresponding `js-module` path in the `plugin.xml` file accordingly. + +The `www/api.js` file will contain the front-end JavaScript API. For this example, the contents of the Echo plugin will be as follows: + +```javascript +const exec = require('cordova/exec'); +const serviceName = 'Echo'; + +const Echo = function () { }; + +Echo.prototype.echo = function (message) { + return new Promise((resolve, reject) => { + const _successCb = function (result) { + resolve(result); + }; + + const _errorCb = function (err) { + reject(new Error(err)); + }; + + exec(_successCb, _errorCb, serviceName, 'echo', [message]); + }); +}; + +module.exports = new Echo(); +``` + +This example demonstrates how to build a front-end plugin API that returns a Promise, offering a modern and user-friendly interface for app developers. + +### Injecting the JavaScript API to the `window` Object + +To make the Echo JavaScript API available on the WebView's `window` object, we need to update the `plugin.xml` to add the injection our API using the `` element. + +```xml + + + +``` + +The above wil take the `www/api.js` and clobber it onto the `window` object as `window.Echo`. + +Usually, when supporting multiple platforms, all platforms has the same JavaScript API. In this case, the above XML does not need to be posted inside the `` element. If there was a case where each platform has their own own JavaScript file, then the `` should be added to the `` element. + +## Implementing Native Interfaces + +Once you created the core structure of the plugin with the above section, we can how complement it with at least one native implementation. + +Details for each platform are listed below, and each section is a continuation of the simple Echo Plugin: + +- [Android Plugin Development Guide](../../platforms/android/plugin.html) +- [iOS Plugin Development Guide](../../platforms/ios/plugin.html) + +## Testing a Plugin during development + +Usually, the simplest way to manually test a plugin during development is to create a Cordova app and add the plugin with the `--link` option: + +```zsh +cordova plugin add ../path/to/my/plugin/relative/to/project --link +``` + +This will creates a symbolic link instead of copying the plugin files, which enables you to work on your plugin and then simply rebuild the app to use your changes. The plugin should be added after the platform, or the link will not work. The link will also be lost if you re-add the platform or [restore the project](../../../platform_plugin_versioning_ref/index.md) with `cordova prepare`. In that case, you'll need to re-add the plugin to restore the link. + +## Publishing Plugins + +You can publish your plugin to any `npmjs`-based registry, but the recommended one is the [npm registry](https://www.npmjs.com). This allows other developers to easily install your plugin using the Cordova CLI. + +To publish, + +```zsh +$ npm adduser # that is if you don't have an account yet +$ npm publish /path/to/your/plugin +``` + +If you do not plan to publish your plugin publicly, it is recommended to set the `private` flag in the `package.json` to `true` to prevent accidental publication. + +```zsh +npm pkg set private=true --json ``` -Please note that the only `PLUGIN_VERSION` values allowed are single versions or -upper bounds; no other semver ranges are supported. +For more details on npm usage, refer to [Contributing packages to the registry](https://docs.npmjs.com/packages-and-modules/contributing-packages-to-the-registry) on the npm documentation site. [cdv_plugin]: ../../../reference/cordova-cli/index.html#cordova-plugin-command [npm-semver]: https://www.npmjs.com/package/semver From 51139581b6672fb911fa83289d4a2ac0130d2dd4 Mon Sep 17 00:00:00 2001 From: Erisu Date: Sat, 21 Jun 2025 23:48:54 +0900 Subject: [PATCH 3/5] doc: various updates to plugin guide --- www/docs/en/dev/guide/hybrid/plugins/index.md | 2 +- www/docs/en/dev/guide/platforms/ios/plugin.md | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/www/docs/en/dev/guide/hybrid/plugins/index.md b/www/docs/en/dev/guide/hybrid/plugins/index.md index 7c7b652ac6..02e0e4f1d4 100644 --- a/www/docs/en/dev/guide/hybrid/plugins/index.md +++ b/www/docs/en/dev/guide/hybrid/plugins/index.md @@ -206,7 +206,7 @@ Plugin developers typically include a front-end JavaScript API. The primary purp exec(, , , , []); ``` -The `cordova.exec` method is is what triggeres the request from the front-end WebView to the native side of the platform, invoking an action method on the specified service class with the provided arguments. Depending on the outcome, either the success or failure callback will be triggered. +The `cordova.exec` method is what triggeres the request from the front-end WebView to the native side of the platform, invoking an action method on the specified service class with the provided arguments. Depending on the outcome, either the success or failure callback will be triggered. - **`successCallback`**: The first argument is the success callback. If the native operation completes successfully, this function is invoked with any returned data. - **`failCallback`**: The second argument is the error callback. If the operation fails, this function is called with an error object or message. diff --git a/www/docs/en/dev/guide/platforms/ios/plugin.md b/www/docs/en/dev/guide/platforms/ios/plugin.md index 45deefb565..2d76c3d1f1 100644 --- a/www/docs/en/dev/guide/platforms/ios/plugin.md +++ b/www/docs/en/dev/guide/platforms/ios/plugin.md @@ -43,7 +43,7 @@ toc_title: iOS - [Common Pitfalls](#common-pitfalls) -This guide provides details on implementing native plugin code for the iOS platform. The plugin's native code can be written in either Objective-C or Swift. +This guide provides details on implementing native plugin code for the iOS platform. The plugin's platform-native code can be written in either Objective-C or Swift. Before proceeding, refer to the [Plugin Development Guide][plugin-dev] for an overview of plugin structure, plugin core files, and its common JavaScript interface. This guide will continue to use the _echo_ plugin, as an exmaple, which enables communication between the Cordova WebView and the native platform. @@ -103,7 +103,7 @@ In the following example, we will place all files in the `src/ios/` directory. T In this example, we are exposing the `echo` method: ```objc - #import + #import @interface Echo : CDVPlugin @@ -120,7 +120,7 @@ In the following example, we will place all files in the `src/ios/` directory. T ```objc #import "Echo.h" - #import + #import @implementation Echo @@ -158,7 +158,7 @@ In the following example, we will place all files in the `src/ios/` directory. T Objective-C based projects will added the following to the header & source files: ```objc - #import + #import ``` **Additional References:** @@ -264,6 +264,7 @@ let package = Package( .library(name: "cordova-plugin-echo", targets: ["cordova-plugin-echo"]) ], dependencies: [ + // This must be included as a dependency, with this format for it to work. .package(url: "https://github.com/apache/cordova-ios.git", branch: "master") ], targets: [ From ab886cfeaaf9af5498fbc1652e88de336780bd18 Mon Sep 17 00:00:00 2001 From: Erisu Date: Sun, 22 Jun 2025 13:13:18 +0900 Subject: [PATCH 4/5] doc: add section for Privacy Manifest --- www/docs/en/dev/guide/platforms/ios/plugin.md | 54 ++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/www/docs/en/dev/guide/platforms/ios/plugin.md b/www/docs/en/dev/guide/platforms/ios/plugin.md index 2d76c3d1f1..c7391c12a1 100644 --- a/www/docs/en/dev/guide/platforms/ios/plugin.md +++ b/www/docs/en/dev/guide/platforms/ios/plugin.md @@ -37,6 +37,7 @@ toc_title: iOS - [Handeling Long-running \& Background Activities](#handeling-long-running--background-activities) - [Hooking into WKURLSchemeTask](#hooking-into-wkurlschemetask) - [Using Background Threads](#using-background-threads) + - [Adding a Privacy Manifest File](#adding-a-privacy-manifest-file) - [CDVPluginResult Message Types](#cdvpluginresult-message-types) - [Other Supported `CDVPlugin` Features](#other-supported-cdvplugin-features) - [Debugging Plugins for iOS](#debugging-plugins-for-ios) @@ -246,7 +247,7 @@ For example: ### Supporting Swift Package Manager (SPM) -Starting from Cordova-iOS 8 and greater, support for the Swift Package Manager has been implemented. To start using SPM with your plugin, a `Package.swift` file will need to be created in the plugin's root directory and a couple of things needs to be set and made aware in the `plugin.xml`. +Starting from Cordova-iOS 8 and greater, support for the Swift Package Manager (SPM) has been implemented. To start using SPM with your plugin, a `Package.swift` file will need to be created in the plugin's root directory and a couple of things needs to be set and made aware in the `plugin.xml`. #### Creating SPM's `Package.swift` File @@ -281,7 +282,8 @@ let package = Package( ) ``` -If the plugin has a privacy manifest to declare, you can add the following line `.copy("Resources/PrivacyInfo.xcprivacy")` to the `cordova-plugin-echo` `target` `resources` element. +If the plugin is required to provide a privacy manifest file, the following line should be added to the `resources` element of the `cordova-plugin-echo` target: `.copy("Resources/PrivacyInfo.xcprivacy")`. +On top of the SPM declaration, be sure to also refer to the section titled [Adding a Privacy Manifest File](#adding-a-privacy-manifest-file) to ensure that the actual resource file is properly declared in the `plugin.xml` so it is correctly injected into the app. If the plugin requires for any third-party dependencies, it should be added to the `dependencies` element, and the `target`'s `dependencies`. @@ -341,6 +343,54 @@ For example: } ``` +#### Adding a Privacy Manifest File + +As of May 1, 2024, Apple requires a privacy manifest file to be created for apps and third-party SDKs. The purpose of the privacy manifest file is to explain the data being collected and the reasons for the required APIs it uses. + +Plugins can include a pre-bundled `PrivacyInfo.xcprivacy` file that lists any privacy-sensitive APIs they use, along with the reasons for their usage. + +It is recommended to review the following Apple Developer document, "[Describing data use in privacy manifests](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests)", to understand the list of known `NSPrivacyCollectedDataTypes` and `NSPrivacyCollectedDataTypePurposes`. + +Ensure all four keys—`NSPrivacyTracking`, `NSPrivacyTrackingDomains`, `NSPrivacyAccessedAPITypes`, and `NSPrivacyCollectedDataTypes`—are defined, even if you are not making an addition to the other items. Apple requires all to be defined. + +Once you've identified what the contents of the `PrivacyInfo.xcprivacy` will look like, lets start creating the bundle and loading it as a resource. + +1. Create a directory named `CDVEcho.bundle` inside the `src/ios` directory. Make sure the bundle name is unique enough to avoid conflicts with other plugins. + +2. Inside the new `CDVEcho.bundle` directory, create a privacy manifest file named `PrivacyInfo.xcprivacy`. + +3. Add the contents you've identified for this file. Here's an example: + + ```xml + + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + + + ``` + +4. Update your `plugin.xml` to load the `CDVEcho.bundle` into the app's resources. + + Inside the iOS `` element, add a `` element pointing to the `CDVEcho.bundle` directory: + + ```xml + + + + ``` + +5. **Optional:** If your plugin supports Swift Package Manager, refer to the section [Creating SPM's `Package.swift` File](#creating-spms-packageswift-file) to ensure the privacy manifest is also included as a resource file. + ## CDVPluginResult Message Types You can use `CDVPluginResult` to return a variety of result types back to the JavaScript callbacks, using class methods that follow this pattern: From ea788ad6ed5faeba30624d422004236cc4cdec3c Mon Sep 17 00:00:00 2001 From: Erisu Date: Sun, 22 Jun 2025 22:47:17 +0900 Subject: [PATCH 5/5] doc: additional cleanup changes --- www/docs/en/dev/guide/hybrid/plugins/index.md | 8 +++----- www/docs/en/dev/guide/platforms/ios/plugin.md | 2 -- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/www/docs/en/dev/guide/hybrid/plugins/index.md b/www/docs/en/dev/guide/hybrid/plugins/index.md index 02e0e4f1d4..50f025fa67 100644 --- a/www/docs/en/dev/guide/hybrid/plugins/index.md +++ b/www/docs/en/dev/guide/hybrid/plugins/index.md @@ -41,17 +41,16 @@ description: Develop your own Cordova plugin. - [Testing a Plugin during development](#testing-a-plugin-during-development) - [Publishing Plugins](#publishing-plugins) - -A Cordova _plugin_ is a package that enables the Cordova apps to access native device features and functionality that is ordinarily unavailable to web-based apps. All of the core Cordova API features are implemented as plugins. Many third-party plugins are also available to provide additional capabilities such as barcode scanning, NFC communication, push notification, or even customizing interfaces. +A Cordova _plugin_ is a package that enables the Cordova apps to access native device features and functionality that is ordinarily unavailable to web-based apps. All of the core Cordova API features are implemented as plugins. Many third-party plugins are also available to provide additional capabilities such as barcode scanning, near-field communication (NFC), push notification, or even customizing interfaces. Check out these locations for Cordova plugins: - Official Apache Cordova plugins on the [Cordova Plugin page](/plugins/). - Third-party plugins on the [npmjs registry](https://www.npmjs.com/search?q=keywords:ecosystem:cordova). -Plugins consist of a single JavaScript interface paired with corresponding native code libraries for each supported platform. In essence, this hides the platform-specific native implementations behind a common JavaScript interface. +Plugins usually consist of a JavaScript interface paired with corresponding platform-native code. In essence, this hides the platform-specific native implementations behind a common JavaScript interface. -This page will walk through the steps to create a basic _echo_ plugin that passes a string from the frontend JavaScript to the native platform and back. The purpose of this guide is to provide a model for how to build and publish a Cordova plugin. It focuses on the fundamentals of plugin structure and the outward-facing JavaScript interface. +This page will walk through the steps to create a basic _echo_ plugin that passes a string from the front-end JavaScript to the native platform and back. The purpose of this guide is to provide a model for how to build and publish a Cordova plugin. It focuses on the fundamentals of plugin structure and the outward-facing JavaScript interface. For the corresponding native implementations, see the list at the end of this section. @@ -199,7 +198,6 @@ Below is a simple example of the `plugin.xml` file that will be used for the `Ec Plugin developers typically include a front-end JavaScript API. The primary purpose is to abstract away Cordova's internal APIs, eliminate the need for app developers to understand the specific naming of your plugin's service or methods, and simplify the overall usage of the plugin. - ### `cordova.exec` Command Syntax ```javascript diff --git a/www/docs/en/dev/guide/platforms/ios/plugin.md b/www/docs/en/dev/guide/platforms/ios/plugin.md index c7391c12a1..db38f81eb1 100644 --- a/www/docs/en/dev/guide/platforms/ios/plugin.md +++ b/www/docs/en/dev/guide/platforms/ios/plugin.md @@ -43,7 +43,6 @@ toc_title: iOS - [Debugging Plugins for iOS](#debugging-plugins-for-ios) - [Common Pitfalls](#common-pitfalls) - This guide provides details on implementing native plugin code for the iOS platform. The plugin's platform-native code can be written in either Objective-C or Swift. Before proceeding, refer to the [Plugin Development Guide][plugin-dev] for an overview of plugin structure, plugin core files, and its common JavaScript interface. This guide will continue to use the _echo_ plugin, as an exmaple, which enables communication between the Cordova WebView and the native platform. @@ -455,7 +454,6 @@ For security purpose, its highly unrecommended to enable the `InspectableWebview - Don't forget to add any hosts you connect to in the allow list, as described in Domain [Allow List Guide](../../appdev/allowlist/index.html). If you forget, an error is logged in the Xcode console. - [plugin-dev]: ../../hybrid/plugins/index.html [CDVInvokedUrlCommand.h]: https://github.com/apache/cordova-ios/blob/master/CordovaLib/Classes/Public/CDVInvokedUrlCommand.h [CDVPluginResult.h]: https://github.com/apache/cordova-ios/blob/master/CordovaLib/Classes/Public/CDVPluginResult.h