Creating Plugins
Scaffolding a Plugin#
The quickest way to create a plugin is with the interactive scaffolding command:
php artisan native:plugin:create
This walks you through naming, namespace selection, and feature options, then generates a complete plugin structure.
Plugin Structure#
A plugin follows a standard layout:
my-plugin/├── composer.json # Package metadata, type must be "nativephp-plugin"├── nativephp.json # Plugin manifest├── src/│ ├── MyPluginServiceProvider.php│ ├── MyPlugin.php # Main class│ ├── Facades/│ │ └── MyPlugin.php│ ├── Events/│ │ └── SomethingHappened.php│ └── Commands/ # Lifecycle hook commands├── resources/│ ├── android/src/ # Kotlin bridge functions│ ├── ios/Sources/ # Swift bridge functions│ └── js/ # JavaScript library stubs
Android Package Naming#
Android/Kotlin code must declare a package at the top of each file. Use your own vendor-namespaced package to avoid conflicts:
// resources/android/src/MyPluginFunctions.ktpackage com.myvendor.plugins.myplugin import com.nativephp.mobile.bridge.BridgeFunctionimport com.nativephp.mobile.bridge.BridgeResponse object MyPluginFunctions { class DoSomething : BridgeFunction { override fun execute(parameters: Map<String, Any>): Map<String, Any> { return BridgeResponse.success(mapOf("status" to "done")) } }}
The compiler places files based on their package declaration, so package com.myvendor.plugins.myplugin results in the file
being placed at app/src/main/java/com/myvendor/plugins/myplugin/MyPluginFunctions.kt.
Reference the full package path in your manifest's bridge functions:
{ "bridge_functions": [{ "name": "MyPlugin.DoSomething", "android": "com.myvendor.plugins.myplugin.MyPluginFunctions.DoSomething" }]}
The composer.json#
Your composer.json must specify the plugin type:
{ "name": "vendor/my-plugin", "type": "nativephp-plugin", "extra": { "laravel": { "providers": ["Vendor\\MyPlugin\\MyPluginServiceProvider"] }, "nativephp": { "manifest": "nativephp.json" } }}
The type: nativephp-plugin tells NativePHP to look for native code in this package.
The nativephp.json Manifest#
The manifest declares native-specific configuration for your plugin. Package metadata (name, version, description,
service_provider) comes from your composer.json — don't duplicate it here.
{ "namespace": "MyPlugin", "bridge_functions": [ { "name": "MyPlugin.DoSomething", "ios": "MyPluginFunctions.DoSomething", "android": "com.nativephp.plugins.myplugin.MyPluginFunctions.DoSomething" } ], "events": ["Vendor\\MyPlugin\\Events\\SomethingHappened"], "android": { "permissions": ["android.permission.CAMERA"], "dependencies": { "implementation": ["com.google.mlkit:barcode-scanning:17.2.0"] } }, "ios": { "info_plist": { "NSCameraUsageDescription": "Camera is used for scanning" }, "dependencies": { "pods": [{"name": "GoogleMLKit/BarcodeScanning", "version": "~> 4.0"}] } }}
Manifest Fields#
| Field | Required | Description |
|---|---|---|
namespace |
Yes | Namespace for the plugin (used for code generation and directory structure) |
bridge_functions |
No | Array of native function mappings |
events |
No | Event classes the plugin dispatches |
android.permissions |
No | Android permission strings |
android.features |
No | Android uses-feature declarations |
android.dependencies |
No | Gradle dependencies |
android.repositories |
No | Custom Maven repositories |
android.activities |
No | Activities to register in manifest |
android.services |
No | Services to register in manifest |
android.receivers |
No | Broadcast receivers to register |
android.providers |
No | Content providers to register |
android.meta_data |
No | Application meta-data entries |
android.min_version |
No | Minimum Android SDK version required |
android.init_function |
No | Native function to call during app initialization |
ios.info_plist |
No | Info.plist entries (permissions, API keys) |
ios.dependencies |
No | Swift packages and CocoaPods |
ios.background_modes |
No | UIBackgroundModes values |
ios.entitlements |
No | App entitlements |
ios.capabilities |
No | iOS capabilities for Xcode project |
ios.min_version |
No | Minimum iOS version required |
ios.init_function |
No | Native function to call during app initialization |
assets |
No | Declarative asset copying |
hooks |
No | Lifecycle hook commands |
secrets |
No | Required environment variables |
See Advanced Configuration for detailed documentation on each field.
Local Development#
During development, add your plugin to your app's composer.json as a path repository:
{ "repositories": [ {"type": "path", "url": "../packages/my-plugin"} ]}
Then require it:
composer require vendor/my-plugin
Changes to your plugin's PHP code are picked up immediately. Changes to native code require a rebuild with
php artisan native:run.
When testing significant changes to your plugin's native code or manifest, you may need to force a fresh install of the native projects:
php artisan native:install --force
This ensures the native projects are rebuilt from scratch with your latest plugin configuration.
Registering Plugins#
After installing a plugin with Composer, you need to register it so it gets compiled into your native builds.
First Time Setup#
Publish the NativeServiceProvider:
php artisan vendor:publish --tag=nativephp-plugins-provider
This creates app/Providers/NativeServiceProvider.php.
Register a Plugin#
php artisan native:plugin:register vendor/plugin-name
This automatically adds the plugin's service provider to your plugins() array:
public function plugins(): array{ return [ \Vendor\PluginName\PluginNameServiceProvider::class, ];}
List Plugins#
# Show registered pluginsphp artisan native:plugin:list # Show all installed plugins (including unregistered)php artisan native:plugin:list --all
Remove a Plugin#
php artisan native:plugin:register vendor/plugin-name --remove
JavaScript Library#
Plugins can provide a JavaScript library for SPA frameworks. The scaffolding creates a stub in resources/js/:
// resources/js/myPlugin.jsconst baseUrl = '/_native/api/call'; async function bridgeCall(method, params = {}) { const response = await fetch(baseUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ method, params }) }); return response.json();} export async function doSomething(options = {}) { return bridgeCall('MyPlugin.DoSomething', options);}
Users can then import your functions directly in Vue, React, or vanilla JS.
NativePHP Plugin Development Kit#
If you're using Claude Code, the Plugin Development Kit supercharges your workflow with specialized agents trained on NativePHP's architecture.
What's Included#
- Kotlin/Android Expert Agent — Writes correct bridge functions, handles Android lifecycles, configures Gradle
- Swift/iOS Expert Agent — Implements iOS bridge functions, manages Info.plist, configures SPM/CocoaPods
- Plugin Architect Agent — Designs plugin structure, manifest configuration, and Laravel integration
- Interactive Commands —
/create-nativephp-pluginscaffolds complete plugins from a description - Validation Tools —
/validate-nativephp-plugincatches errors before you build
Why It's Worth It#
Writing native mobile code is hard. These agents understand:
- NativePHP's bridge function patterns and response formats
- Platform-specific APIs and how to expose them to PHP
- Permission declarations, entitlements, and manifest configuration
- Event dispatching from native code to Livewire components
- Dependency management across Gradle, CocoaPods, and SPM
Instead of learning two new languages and their ecosystems, describe what you need and let the agents handle the implementation details.
AI Development Tools#
NativePHP includes built-in commands for AI-assisted plugin development.
Install Development Agents#
Install specialized AI agents for plugin development:
php artisan native:plugin:install-agent
This copies agent definition files to your project's .claude/agents/ directory. Available agents include:
- kotlin-android-expert — Deep Android/Kotlin native development
- swift-ios-expert — Deep iOS/Swift native development
- js-bridge-expert — JavaScript/TypeScript client integration
- plugin-writer — General plugin scaffolding and structure
- plugin-docs-writer — Documentation and Boost guidelines
Use --all to install all agents without prompting, or --force to overwrite existing files.
Create Boost Guidelines#
If you're using Boost, create AI guidelines for your plugin:
php artisan native:plugin:boost
This generates a resources/boost/guidelines/core.blade.php file in your plugin that documents:
- How to use your plugin's facade
- Available methods and their descriptions
- Events and how to listen for them
- JavaScript usage examples
When users install your plugin and run php artisan boost:install, these guidelines are automatically loaded,
helping AI assistants understand how to use your plugin correctly.
Ready to Build?#
You now have everything you need to create NativePHP plugins. For most developers, the Plugin Development Kit is the fastest path from idea to working plugin — it handles the native code complexity so you can focus on what your plugin does, not how to write Kotlin and Swift.