Skip to content

Commit 6e25749

Browse files
committed
Add Plugins documentation section for Mobile v2
New documentation covering the NativePHP Mobile plugin system: - Introduction to plugins - Using plugins (installation, events) - Creating plugins (scaffolding, structure, manifest) - Bridge functions (Swift/Kotlin implementations) - Events (native-to-PHP dispatching) - Lifecycle hooks (pre_compile, copy_assets, etc.) - Permissions & dependencies (Android, iOS, CocoaPods) - Validation & testing
1 parent 28b7dcc commit 6e25749

File tree

9 files changed

+894
-0
lines changed

9 files changed

+894
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
title: Plugins
3+
order: 60
4+
---
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
---
2+
title: Bridge Functions
3+
order: 400
4+
---
5+
6+
## How Bridge Functions Work
7+
8+
Bridge functions are the connection between your PHP code and native platform code. When you call a method like
9+
`MyPlugin::doSomething()`, NativePHP routes that to your Swift or Kotlin implementation running on the device.
10+
11+
The flow:
12+
1. PHP calls `nativephp_call('MyPlugin.DoSomething', $params)`
13+
2. The native bridge locates the registered function
14+
3. Your native code executes and returns a response
15+
4. PHP receives the result
16+
17+
## Declaring Bridge Functions
18+
19+
In your `nativephp.json`, declare each function with its platform implementations:
20+
21+
```json
22+
{
23+
"bridge_functions": [
24+
{
25+
"name": "MyPlugin.DoSomething",
26+
"ios": "MyPluginFunctions.DoSomething",
27+
"android": "com.vendor.plugin.myplugin.MyPluginFunctions.DoSomething",
28+
"description": "Does something useful"
29+
}
30+
]
31+
}
32+
```
33+
34+
The `name` is what PHP uses. The platform-specific values point to your native class and method.
35+
36+
## Swift Implementation (iOS)
37+
38+
Create your functions in `resources/ios/Sources/`:
39+
40+
```swift
41+
import Foundation
42+
43+
enum MyPluginFunctions {
44+
45+
class DoSomething: BridgeFunction {
46+
func execute(parameters: [String: Any]) throws -> [String: Any] {
47+
let option = parameters["option"] as? String ?? ""
48+
49+
// Do your native work here
50+
51+
return BridgeResponse.success(data: [
52+
"result": "completed",
53+
"option": option
54+
])
55+
}
56+
}
57+
}
58+
```
59+
60+
Key points:
61+
- Implement the `BridgeFunction` protocol
62+
- Parameters come as a dictionary
63+
- Return using `BridgeResponse.success()` or `BridgeResponse.error()`
64+
65+
## Kotlin Implementation (Android)
66+
67+
Create your functions in `resources/android/src/.../`:
68+
69+
```kotlin
70+
package com.vendor.plugin.myplugin
71+
72+
import com.example.androidphp.bridge.BridgeFunction
73+
import com.example.androidphp.bridge.BridgeResponse
74+
75+
object MyPluginFunctions {
76+
77+
class DoSomething : BridgeFunction {
78+
override fun execute(parameters: Map<String, Any>): Map<String, Any> {
79+
val option = parameters["option"] as? String ?: ""
80+
81+
// Do your native work here
82+
83+
return BridgeResponse.success(mapOf(
84+
"result" to "completed",
85+
"option" to option
86+
))
87+
}
88+
}
89+
}
90+
```
91+
92+
<aside>
93+
94+
#### Package Naming
95+
96+
Use your plugin's namespace in the Kotlin package name. The scaffolding command sets this up correctly.
97+
98+
</aside>
99+
100+
## Calling from PHP
101+
102+
Create a facade method that calls your bridge function:
103+
104+
```php
105+
class MyPlugin
106+
{
107+
public function doSomething(array $options = []): mixed
108+
{
109+
$result = nativephp_call('MyPlugin.DoSomething', json_encode($options));
110+
111+
return json_decode($result)?->data;
112+
}
113+
}
114+
```
115+
116+
## Error Handling
117+
118+
Return errors from native code using `BridgeResponse.error()`:
119+
120+
```swift
121+
// Swift
122+
return BridgeResponse.error(message: "Something went wrong")
123+
```
124+
125+
```kotlin
126+
// Kotlin
127+
return BridgeResponse.error("Something went wrong")
128+
```
129+
130+
The error message is available in PHP through the response.
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
---
2+
title: Creating Plugins
3+
order: 300
4+
---
5+
6+
## Scaffolding a Plugin
7+
8+
The quickest way to create a plugin is with the interactive scaffolding command:
9+
10+
```shell
11+
php artisan native:plugin:create
12+
```
13+
14+
This walks you through naming, namespace selection, and feature options, then generates a complete plugin structure.
15+
16+
## Plugin Structure
17+
18+
A plugin follows a standard layout:
19+
20+
```
21+
my-plugin/
22+
├── composer.json # Package metadata, type must be "nativephp-plugin"
23+
├── nativephp.json # Plugin manifest
24+
├── src/
25+
│ ├── MyPluginServiceProvider.php
26+
│ ├── MyPlugin.php # Main class
27+
│ ├── Facades/
28+
│ │ └── MyPlugin.php
29+
│ ├── Events/
30+
│ │ └── SomethingHappened.php
31+
│ └── Commands/ # Lifecycle hook commands
32+
├── resources/
33+
│ ├── android/src/ # Kotlin bridge functions
34+
│ ├── ios/Sources/ # Swift bridge functions
35+
│ └── js/ # JavaScript library stubs
36+
```
37+
38+
## The composer.json
39+
40+
Your `composer.json` must specify the plugin type:
41+
42+
```json
43+
{
44+
"name": "vendor/my-plugin",
45+
"type": "nativephp-plugin",
46+
"extra": {
47+
"laravel": {
48+
"providers": ["Vendor\\MyPlugin\\MyPluginServiceProvider"]
49+
},
50+
"nativephp": {
51+
"manifest": "nativephp.json"
52+
}
53+
}
54+
}
55+
```
56+
57+
The `type: nativephp-plugin` tells NativePHP to look for native code in this package.
58+
59+
## The nativephp.json Manifest
60+
61+
The manifest declares everything about your plugin:
62+
63+
```json
64+
{
65+
"name": "vendor/my-plugin",
66+
"namespace": "MyPlugin",
67+
"bridge_functions": [
68+
{
69+
"name": "MyPlugin.DoSomething",
70+
"ios": "MyPluginFunctions.DoSomething",
71+
"android": "com.vendor.plugin.myplugin.MyPluginFunctions.DoSomething"
72+
}
73+
],
74+
"events": ["Vendor\\MyPlugin\\Events\\SomethingHappened"],
75+
"permissions": {
76+
"android": ["android.permission.SOME_PERMISSION"],
77+
"ios": {
78+
"NSCameraUsageDescription": "We need camera access"
79+
}
80+
}
81+
}
82+
```
83+
84+
The key fields:
85+
86+
- **namespace** — Used to generate bridge function registration code
87+
- **bridge_functions** — Maps PHP calls to native implementations
88+
- **events** — Event classes your plugin dispatches
89+
- **permissions** — Platform permissions your plugin requires
90+
91+
## Local Development
92+
93+
During development, add your plugin to your app's `composer.json` as a path repository:
94+
95+
```json
96+
{
97+
"repositories": [
98+
{"type": "path", "url": "../packages/my-plugin"}
99+
]
100+
}
101+
```
102+
103+
Then require it:
104+
105+
```shell
106+
composer require vendor/my-plugin
107+
```
108+
109+
Changes to your plugin's PHP code are picked up immediately. Changes to native code require a rebuild with
110+
`php artisan native:run`.
111+
112+
<aside>
113+
114+
#### Validate Early and Often
115+
116+
Run `php artisan native:plugin:validate` to catch manifest errors, missing native code, or mismatched function
117+
declarations before you try to build.
118+
119+
</aside>
120+
121+
## JavaScript Library
122+
123+
Plugins can provide a JavaScript library for SPA frameworks. The scaffolding creates a stub in `resources/js/`:
124+
125+
```js
126+
// resources/js/myPlugin.js
127+
const baseUrl = '/_native/api/call';
128+
129+
async function bridgeCall(method, params = {}) {
130+
const response = await fetch(baseUrl, {
131+
method: 'POST',
132+
headers: { 'Content-Type': 'application/json' },
133+
body: JSON.stringify({ method, params })
134+
});
135+
return response.json();
136+
}
137+
138+
export async function doSomething(options = {}) {
139+
return bridgeCall('MyPlugin.DoSomething', options);
140+
}
141+
```
142+
143+
Users can then import your functions directly in Vue, React, or vanilla JS.
144+
145+
## Plugin Writer Agent
146+
147+
If you're building a complex plugin, install the plugin-writer agent to help with native code patterns:
148+
149+
```shell
150+
php artisan native:plugin:install-agent
151+
```
152+
153+
This copies a specialized agent configuration to your project's `.claude/agents/` directory. The agent understands
154+
NativePHP plugin patterns and can help write Swift/Kotlin bridge functions, event dispatching, and hook commands.

0 commit comments

Comments
 (0)