Loading...
Loading...
Compare original and translation side by side
| Feature | Native Plugins | Native UI |
|---|---|---|
| Purpose | Functional capabilities | Visual components |
| Examples | Share, Camera, Payment | Button, TextField, DatePicker |
| Extends | | |
| Registration | | |
| Invocation | | DOM APIs (properties, methods, events) |
| Rendering | No visual output | Renders Flutter widgets |
| Use Case | Platform features, data processing | Native-looking UI components |
| 特性 | 原生插件 | 原生UI |
|---|---|---|
| 用途 | 功能能力 | 视觉组件 |
| 示例 | 分享、相机、支付 | 按钮、输入框、日期选择器 |
| 继承类 | | |
| 注册方式 | | |
| 调用方式 | | DOM API(属性、方法、事件) |
| 渲染 | 无视觉输出 | 渲染Flutter组件 |
| 使用场景 | 平台功能、数据处理 | 原生风格UI组件 |
fetch()localStoragewebf-native-pluginsfetch()localStoragewebf-native-pluginswebf-native-ui-devwebf-native-pluginswebf-native-ui-devwebf-native-plugins┌─────────────────────────────────────────┐
│ JavaScript/TypeScript │ ← Generated by CLI
│ @openwebf/webf-my-plugin │
│ import { MyPlugin } from '...' │
├─────────────────────────────────────────┤
│ TypeScript Definitions (.d.ts) │ ← You write this
│ interface MyPlugin { ... } │
├─────────────────────────────────────────┤
│ Dart (Flutter) │ ← You write this
│ class MyPluginModule extends ... │
│ webf_my_plugin package │
└─────────────────────────────────────────┘┌─────────────────────────────────────────┐
│ JavaScript/TypeScript │ ← 由CLI生成
│ @openwebf/webf-my-plugin │
│ import { MyPlugin } from '...' │
├─────────────────────────────────────────┤
│ TypeScript定义文件 (.d.ts) │ ← 由你编写
│ interface MyPlugin { ... } │
├─────────────────────────────────────────┤
│ Dart (Flutter) │ ← 由你编写
│ class MyPluginModule extends ... │
│ webf_my_plugin 包 │
└─────────────────────────────────────────┘undefinedundefinedundefinedundefinedundefinedundefined
**Directory structure:**
**pubspec.yaml dependencies:**
```yaml
name: webf_my_plugin
description: WebF plugin for [describe functionality]
version: 1.0.0
homepage: https://github.com/yourusername/webf_my_plugin
environment:
sdk: ^3.6.0
flutter: ">=3.0.0"
dependencies:
flutter:
sdk: flutter
webf: ^0.24.0
# Add the Flutter package you're wrapping
some_flutter_package: ^1.0.0
**目录结构:**
**pubspec.yaml依赖:**
```yaml
name: webf_my_plugin
description: WebF插件,用于[描述功能]
version: 1.0.0
homepage: https://github.com/yourusername/webf_my_plugin
environment:
sdk: ^3.6.0
flutter: ">=3.0.0"
dependencies:
flutter:
sdk: flutter
webf: ^0.24.0
# 添加要封装的Flutter包
some_flutter_package: ^1.0.0import 'dart:async';
import 'package:webf/bridge.dart';
import 'package:webf/module.dart';
import 'package:some_flutter_package/some_flutter_package.dart';
import 'my_plugin_module_bindings_generated.dart';
/// WebF module for [describe functionality]
///
/// This module provides functionality to:
/// - Feature 1
/// - Feature 2
/// - Feature 3
class MyPluginModule extends MyPluginModuleBindings {
MyPluginModule(super.moduleManager);
void dispose() {
// Clean up resources when module is disposed
// Close streams, cancel timers, release native resources
}
// Implement methods from TypeScript interface
Future<String> myAsyncMethod(String input) async {
try {
// Call the underlying Flutter package
final result = await SomeFlutterPackage.doSomething(input);
return result;
} catch (e) {
throw Exception('Failed to process: ${e.toString()}');
}
}
String mySyncMethod(String input) {
// Synchronous operations
return 'Processed: $input';
}
Future<MyResultType> complexMethod(MyOptionsType options) async {
// Handle complex types
final value = options.someField ?? 'default';
final timeout = options.timeout ?? 5000;
try {
// Do the work
final result = await SomeFlutterPackage.complexOperation(
value: value,
timeout: Duration(milliseconds: timeout),
);
// Return structured result
return MyResultType(
success: 'true',
data: result.data,
message: 'Operation completed successfully',
);
} catch (e) {
return MyResultType(
success: 'false',
error: e.toString(),
message: 'Operation failed',
);
}
}
// Helper methods (not exposed to JavaScript)
Future<void> _internalHelper() async {
// Internal implementation details
}
}import 'dart:async';
import 'package:webf/bridge.dart';
import 'package:webf/module.dart';
import 'package:some_flutter_package/some_flutter_package.dart';
import 'my_plugin_module_bindings_generated.dart';
/// WebF模块,用于[描述功能]
///
/// 本模块提供以下功能:
/// - 功能1
/// - 功能2
/// - 功能3
class MyPluginModule extends MyPluginModuleBindings {
MyPluginModule(super.moduleManager);
void dispose() {
// 当模块销毁时清理资源
// 关闭流、取消定时器、释放原生资源
}
// 实现TypeScript接口中的方法
Future<String> myAsyncMethod(String input) async {
try {
// 调用底层Flutter包
final result = await SomeFlutterPackage.doSomething(input);
return result;
} catch (e) {
throw Exception('处理失败: ${e.toString()}');
}
}
String mySyncMethod(String input) {
// 同步操作
return '已处理: $input';
}
Future<MyResultType> complexMethod(MyOptionsType options) async {
// 处理复杂类型
final value = options.someField ?? '默认值';
final timeout = options.timeout ?? 5000;
try {
// 执行操作
final result = await SomeFlutterPackage.complexOperation(
value: value,
timeout: Duration(milliseconds: timeout),
);
// 返回结构化结果
return MyResultType(
success: 'true',
data: result.data,
message: '操作成功完成',
);
} catch (e) {
return MyResultType(
success: 'false',
error: e.toString(),
message: '操作失败',
);
}
}
// 辅助方法(不暴露给JavaScript)
Future<void> _internalHelper() async {
// 内部实现细节
}
}.d.ts/**
* Type-safe JavaScript API for the WebF MyPlugin module.
*
* This interface is used by the WebF CLI (`webf module-codegen`) to generate:
* - An npm package wrapper that forwards calls to `webf.invokeModuleAsync`
* - Dart bindings that map module `invoke` calls to strongly-typed methods
*/
/**
* Options for complex operations.
*/
interface MyOptionsType {
/** The value to process. */
someField?: string;
/** Timeout in milliseconds. */
timeout?: number;
/** Enable verbose logging. */
verbose?: boolean;
}
/**
* Result returned from complex operations.
*/
interface MyResultType {
/** "true" on success, "false" on failure. */
success: string;
/** Data returned from the operation. */
data?: any;
/** Human-readable message. */
message: string;
/** Error message if operation failed. */
error?: string;
}
/**
* Public WebF MyPlugin module interface.
*
* Methods here map 1:1 to the Dart `MyPluginModule` methods.
*
* Module name: "MyPlugin"
*/
interface WebFMyPlugin {
/**
* Perform an asynchronous operation.
*
* @param input Input string to process.
* @returns Promise with processed result.
*/
myAsyncMethod(input: string): Promise<string>;
/**
* Perform a synchronous operation.
*
* @param input Input string to process.
* @returns Processed result.
*/
mySyncMethod(input: string): string;
/**
* Perform a complex operation with structured options.
*
* @param options Configuration options.
* @returns Promise with operation result.
*/
complexMethod(options: MyOptionsType): Promise<MyResultType>;
}WebF{ModuleName}?Promise<T>string.d.ts/**
* WebF MyPlugin模块的类型安全JavaScript API。
*
* 此接口由WebF CLI (`webf module-codegen`)用于生成:
* - 将调用转发给`webf.invokeModuleAsync`的npm包封装
* - 将模块`invoke`调用映射到强类型方法的Dart绑定
*/
/**
* 复杂操作的选项。
*/
interface MyOptionsType {
/** 要处理的值。 */
someField?: string;
/** 超时时间(毫秒)。 */
timeout?: number;
/** 启用详细日志。 */
verbose?: boolean;
}
/**
* 复杂操作返回的结果。
*/
interface MyResultType {
/** 成功为"true",失败为"false"。 */
success: string;
/** 操作返回的数据。 */
data?: any;
/** 人类可读消息。 */
message: string;
/** 操作失败时的错误消息。 */
error?: string;
}
/**
* WebF MyPlugin模块的公开接口。
*
* 此处的方法与Dart`MyPluginModule`中的方法一一对应。
*
* 模块名称: "MyPlugin"
*/
interface WebFMyPlugin {
/**
* 执行异步操作。
*
* @param input 要处理的输入字符串。
* @returns 包含处理结果的Promise。
*/
myAsyncMethod(input: string): Promise<string>;
/**
* 执行同步操作。
*
* @param input 要处理的输入字符串。
* @returns 处理后的结果。
*/
mySyncMethod(input: string): string;
/**
* 使用结构化选项执行复杂操作。
*
* @param options 配置选项。
* @returns 包含操作结果的Promise。
*/
complexMethod(options: MyOptionsType): Promise<MyResultType>;
}WebF{ModuleName}?Promise<T>string/// WebF MyPlugin module for [describe functionality]
///
/// This module provides functionality to:
/// - Feature 1
/// - Feature 2
/// - Feature 3
///
/// Example usage:
/// ```dart
/// // Register module globally (in main function)
/// WebF.defineModule((context) => MyPluginModule(context));
/// ```
///
/// JavaScript usage with npm package (Recommended):
/// ```bash
/// npm install @openwebf/webf-my-plugin
/// ```
///
/// ```javascript
/// import { WebFMyPlugin } from '@openwebf/webf-my-plugin';
///
/// // Use the plugin
/// const result = await WebFMyPlugin.myAsyncMethod('input');
/// console.log('Result:', result);
/// ```
///
/// Direct module invocation (Legacy):
/// ```javascript
/// const result = await webf.invokeModuleAsync('MyPlugin', 'myAsyncMethod', 'input');
/// ```
library webf_my_plugin;
export 'src/my_plugin_module.dart';/// WebF MyPlugin模块,用于[描述功能]
///
/// 本模块提供以下功能:
/// - 功能1
/// - 功能2
/// - 功能3
///
/// 示例用法:
/// ```dart
/// // 在main函数中全局注册模块
/// WebF.defineModule((context) => MyPluginModule(context));
/// ```
///
/// 使用npm包的JavaScript用法(推荐):
/// ```bash
/// npm install @openwebf/webf-my-plugin
/// ```
///
/// ```javascript
/// import { WebFMyPlugin } from '@openwebf/webf-my-plugin';
///
/// // 使用插件
/// const result = await WebFMyPlugin.myAsyncMethod('input');
/// console.log('结果:', result);
/// ```
///
/// 直接模块调用(旧版):
/// ```javascript
/// const result = await webf.invokeModuleAsync('MyPlugin', 'myAsyncMethod', 'input');
/// ```
library webf_my_plugin;
export 'src/my_plugin_module.dart';undefinedundefined
**What the CLI does:**
1. ✅ Parses your `.d.ts` file
2. ✅ Generates Dart binding classes (`*_bindings_generated.dart`)
3. ✅ Creates npm package with TypeScript types
4. ✅ Generates JavaScript wrapper that calls `webf.invokeModuleAsync`
5. ✅ Creates `package.json` with correct metadata
6. ✅ Runs `npm run build` if a build script exists
**Generated output structure:**undefined
**CLI执行的操作:**
1. ✅ 解析你的`.d.ts`文件
2. ✅ 生成Dart绑定类(`*_bindings_generated.dart`)
3. ✅ 创建带有TypeScript类型的npm包
4. ✅ 生成调用`webf.invokeModuleAsync`的JavaScript封装
5. ✅ 创建带有正确元数据的`package.json`
6. ✅ 如果存在构建脚本,运行`npm run build`
**生成的输出结构:**undefinedimport 'package:webf/webf.dart';
import 'package:webf_my_plugin/webf_my_plugin.dart';
void main() {
WebFControllerManager.instance.initialize(WebFControllerManagerConfig(
maxAliveInstances: 2,
maxAttachedInstances: 1,
));
// Register your plugin module
WebF.defineModule((context) => MyPluginModule(context));
runApp(MyApp());
}import 'package:webf/webf.dart';
import 'package:webf_my_plugin/webf_my_plugin.dart';
void main() {
WebFControllerManager.instance.initialize(WebFControllerManagerConfig(
maxAliveInstances: 2,
maxAttachedInstances: 1,
));
// 注册你的插件模块
WebF.defineModule((context) => MyPluginModule(context));
runApp(MyApp());
}npm install @openwebf/webf-my-pluginimport { WebFMyPlugin } from '@openwebf/webf-my-plugin';
async function testPlugin() {
try {
// Test async method
const result = await WebFMyPlugin.myAsyncMethod('test input');
console.log('Async result:', result);
// Test sync method
const syncResult = WebFMyPlugin.mySyncMethod('test');
console.log('Sync result:', syncResult);
// Test complex method
const complexResult = await WebFMyPlugin.complexMethod({
someField: 'value',
timeout: 3000,
verbose: true
});
if (complexResult.success === 'true') {
console.log('Success:', complexResult.message);
} else {
console.error('Error:', complexResult.error);
}
} catch (error) {
console.error('Plugin error:', error);
}
}
testPlugin();npm install @openwebf/webf-my-pluginimport { WebFMyPlugin } from '@openwebf/webf-my-plugin';
async function testPlugin() {
try {
// 测试异步方法
const result = await WebFMyPlugin.myAsyncMethod('测试输入');
console.log('异步结果:', result);
// 测试同步方法
const syncResult = WebFMyPlugin.mySyncMethod('测试');
console.log('同步结果:', syncResult);
// 测试复杂方法
const complexResult = await WebFMyPlugin.complexMethod({
someField: '值',
timeout: 3000,
verbose: true
});
if (complexResult.success === 'true') {
console.log('成功:', complexResult.message);
} else {
console.error('错误:', complexResult.error);
}
} catch (error) {
console.error('插件错误:', error);
}
}
testPlugin();undefinedundefinedundefinedundefinedundefinedundefined
**For custom npm registry:**
```bash
webf module-codegen webf-my-plugin-npm \
--flutter-package-src=./webf_my_plugin \
--module-name=MyPlugin \
--publish-to-npm \
--npm-registry=https://registry.your-company.com/
**对于自定义npm注册表:**
```bash
webf module-codegen webf-my-plugin-npm \\
--flutter-package-src=./webf_my_plugin \\
--module-name=MyPlugin \\
--publish-to-npm \\
--npm-registry=https://registry.your-company.com/pubspec.yamldependencies:
flutter:
sdk: flutter
webf: ^0.24.0
# Add your custom plugin
webf_my_plugin: ^1.0.0 # From pub.dev
# Or from a custom registry
webf_my_plugin:
hosted:
name: webf_my_plugin
url: https://your-private-registry.com
version: ^1.0.0
# Or from a local path during development
webf_my_plugin:
path: ../webf_my_pluginflutter pub getpubspec.yamldependencies:
flutter:
sdk: flutter
webf: ^0.24.0
# 添加自定义插件
webf_my_plugin: ^1.0.0 # 来自pub.dev
# 或来自自定义注册表
webf_my_plugin:
hosted:
name: webf_my_plugin
url: https://your-private-registry.com
version: ^1.0.0
# 或开发时使用本地路径
webf_my_plugin:
path: ../webf_my_pluginflutter pub getmain.dartimport 'package:flutter/material.dart';
import 'package:webf/webf.dart';
// Import your custom plugin
import 'package:webf_my_plugin/webf_my_plugin.dart';
void main() {
// Initialize WebFControllerManager
WebFControllerManager.instance.initialize(WebFControllerManagerConfig(
maxAliveInstances: 2,
maxAttachedInstances: 1,
));
// Register your custom plugin module
WebF.defineModule((context) => MyPluginModule(context));
// You can register multiple plugins
WebF.defineModule((context) => AnotherPluginModule(context));
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: WebF(
initialUrl: 'http://192.168.1.100:3000', // Your dev server
),
),
);
}
}main.dartimport 'package:flutter/material.dart';
import 'package:webf/webf.dart';
// 导入自定义插件
import 'package:webf_my_plugin/webf_my_plugin.dart';
void main() {
// 初始化WebFControllerManager
WebFControllerManager.instance.initialize(WebFControllerManagerConfig(
maxAliveInstances: 2,
maxAttachedInstances: 1,
));
// 注册自定义插件模块
WebF.defineModule((context) => MyPluginModule(context));
// 可以注册多个插件
WebF.defineModule((context) => AnotherPluginModule(context));
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: WebF(
initialUrl: 'http://192.168.1.100:3000', // 你的开发服务器
),
),
);
}
}undefinedundefinedundefinedundefinedimport { WebFMyPlugin } from '@openwebf/webf-my-plugin';
async function useMyPlugin() {
try {
// Call async methods
const result = await WebFMyPlugin.myAsyncMethod('input');
console.log('Result:', result);
// Call sync methods
const syncResult = WebFMyPlugin.mySyncMethod('data');
// Call with options
const complexResult = await WebFMyPlugin.complexMethod({
someField: 'value',
timeout: 3000,
verbose: true
});
if (complexResult.success === 'true') {
console.log('Success:', complexResult.message);
console.log('Data:', complexResult.data);
} else {
console.error('Error:', complexResult.error);
}
} catch (error) {
console.error('Plugin error:', error);
}
}import React, { useState, useEffect } from 'react';
import { WebFMyPlugin } from '@openwebf/webf-my-plugin';
function MyComponent() {
const [result, setResult] = useState<string | null>(null);
const handleButtonClick = async () => {
try {
const data = await WebFMyPlugin.myAsyncMethod('test');
setResult(data);
} catch (error) {
console.error('Failed:', error);
}
};
return (
<div>
<button onClick={handleButtonClick}>
Use My Plugin
</button>
{result && <p>Result: {result}</p>}
</div>
);
}<template>
<div>
<button @click="usePlugin">Use My Plugin</button>
<p v-if="result">Result: {{ result }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { WebFMyPlugin } from '@openwebf/webf-my-plugin';
const result = ref(null);
const usePlugin = async () => {
try {
result.value = await WebFMyPlugin.myAsyncMethod('test');
} catch (error) {
console.error('Failed:', error);
}
};
</script>import { WebFMyPlugin } from '@openwebf/webf-my-plugin';
async function useMyPlugin() {
try {
// 调用异步方法
const result = await WebFMyPlugin.myAsyncMethod('输入');
console.log('结果:', result);
// 调用同步方法
const syncResult = WebFMyPlugin.mySyncMethod('数据');
// 带选项调用
const complexResult = await WebFMyPlugin.complexMethod({
someField: '值',
timeout: 3000,
verbose: true
});
if (complexResult.success === 'true') {
console.log('成功:', complexResult.message);
console.log('数据:', complexResult.data);
} else {
console.error('错误:', complexResult.error);
}
} catch (error) {
console.error('插件错误:', error);
}
}import React, { useState, useEffect } from 'react';
import { WebFMyPlugin } from '@openwebf/webf-my-plugin';
function MyComponent() {
const [result, setResult] = useState<string | null>(null);
const handleButtonClick = async () => {
try {
const data = await WebFMyPlugin.myAsyncMethod('测试');
setResult(data);
} catch (error) {
console.error('失败:', error);
}
};
return (
<div>
<button onClick={handleButtonClick}>
使用我的插件
</button>
{result && <p>结果: {result}</p>}
</div>
);
}<template>
<div>
<button @click="usePlugin">使用我的插件</button>
<p v-if="result">结果: {{ result }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { WebFMyPlugin } from '@openwebf/webf-my-plugin';
const result = ref(null);
const usePlugin = async () => {
try {
result.value = await WebFMyPlugin.myAsyncMethod('测试');
} catch (error) {
console.error('失败:', error);
}
};
</script>// Direct invocation (not type-safe)
const result = await webf.invokeModuleAsync(
'MyPlugin', // Module name (must match what you registered)
'myAsyncMethod', // Method name
'input' // Arguments
);
// With multiple arguments
const complexResult = await webf.invokeModuleAsync(
'MyPlugin',
'complexMethod',
{
someField: 'value',
timeout: 3000,
verbose: true
}
);
// Sync method invocation
const syncResult = webf.invokeModuleSync(
'MyPlugin',
'mySyncMethod',
'data'
);// 直接调用(非类型安全)
const result = await webf.invokeModuleAsync(
'MyPlugin', // 模块名称(必须与注册的名称一致)
'myAsyncMethod', // 方法名称
'输入' // 参数
);
// 带多个参数
const complexResult = await webf.invokeModuleAsync(
'MyPlugin',
'complexMethod',
{
someField: '值',
timeout: 3000,
verbose: true
}
);
// 同步方法调用
const syncResult = webf.invokeModuleSync(
'MyPlugin',
'mySyncMethod',
'数据'
);// Check if plugin exists
if (typeof WebFMyPlugin !== 'undefined') {
// Plugin is available
await WebFMyPlugin.myAsyncMethod('test');
} else {
// Plugin not registered or npm package not installed
console.warn('MyPlugin is not available');
// Provide fallback behavior
}// 检查插件是否存在
if (typeof WebFMyPlugin !== 'undefined') {
// 插件可用
await WebFMyPlugin.myAsyncMethod('测试');
} else {
// 插件未注册或npm包未安装
console.warn('MyPlugin不可用');
// 提供回退行为
}async function safePluginCall() {
// Check availability
if (typeof WebFMyPlugin === 'undefined') {
throw new Error('MyPlugin is not installed');
}
try {
const result = await WebFMyPlugin.complexMethod({
someField: 'value'
});
// Check result status
if (result.success === 'true') {
return result.data;
} else {
throw new Error(result.error || 'Unknown error');
}
} catch (error) {
console.error('Plugin call failed:', error);
throw error;
}
}async function safePluginCall() {
// 检查可用性
if (typeof WebFMyPlugin === 'undefined') {
throw new Error('MyPlugin未安装');
}
try {
const result = await WebFMyPlugin.complexMethod({
someField: '值'
});
// 检查结果状态
if (result.success === 'true') {
return result.data;
} else {
throw new Error(result.error || '未知错误');
}
} catch (error) {
console.error('插件调用失败:', error);
throw error;
}
}undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedwebf_my_plugin: ^1.0.0npm install @openwebf/webf-my-pluginwebf_my_plugin: ^1.0.0npm install @openwebf/webf-my-pluginundefinedundefined
**npm Package:**
```bash
**npm包:**
```bashundefinedundefineddependencies:
webf_my_plugin:
path: ../webf_my_plugin # Relative pathnpm install ../webf-my-plugin-npmdependencies:
webf_my_plugin:
path: ../webf_my_plugin # 相对路径npm install ../webf-my-plugin-npmundefinedundefinedimport 'package:webf/webf.dart';
import 'package:webf_camera/webf_camera.dart'; // Your plugin
void main() {
WebFControllerManager.instance.initialize(WebFControllerManagerConfig(
maxAliveInstances: 2,
maxAttachedInstances: 1,
));
// Register your camera plugin
WebF.defineModule((context) => CameraModule(context));
runApp(MyApp());
}import { WebFCamera } from '@openwebf/webf-camera';
function CameraApp() {
const [cameras, setCameras] = useState([]);
useEffect(() => {
async function loadCameras() {
// Check if plugin is available
if (typeof WebFCamera === 'undefined') {
console.error('Camera plugin not installed');
return;
}
try {
const result = await WebFCamera.getCameras();
if (result.success === 'true') {
setCameras(JSON.parse(result.cameras));
}
} catch (error) {
console.error('Failed to load cameras:', error);
}
}
loadCameras();
}, []);
const capturePhoto = async () => {
try {
const photoPath = await WebFCamera.capturePhoto(cameras[0].id);
console.log('Photo saved to:', photoPath);
} catch (error) {
console.error('Failed to capture:', error);
}
};
return (
<div>
<h1>Camera App</h1>
<button onClick={capturePhoto}>Capture Photo</button>
<ul>
{cameras.map(cam => (
<li key={cam.id}>{cam.name}</li>
))}
</ul>
</div>
);
}import 'package:webf/webf.dart';
import 'package:webf_camera/webf_camera.dart'; // 你的插件
void main() {
WebFControllerManager.instance.initialize(WebFControllerManagerConfig(
maxAliveInstances: 2,
maxAttachedInstances: 1,
));
// 注册相机插件
WebF.defineModule((context) => CameraModule(context));
runApp(MyApp());
}import { WebFCamera } from '@openwebf/webf-camera';
function CameraApp() {
const [cameras, setCameras] = useState([]);
useEffect(() => {
async function loadCameras() {
// 检查插件是否可用
if (typeof WebFCamera === 'undefined') {
console.error('相机插件未安装');
return;
}
try {
const result = await WebFCamera.getCameras();
if (result.success === 'true') {
setCameras(JSON.parse(result.cameras));
}
} catch (error) {
console.error('加载相机失败:', error);
}
}
loadCameras();
}, []);
const capturePhoto = async () => {
try {
const photoPath = await WebFCamera.capturePhoto(cameras[0].id);
console.log('照片保存到:', photoPath);
} catch (error) {
console.error('拍照失败:', error);
}
};
return (
<div>
<h1>相机应用</h1>
<button onClick={capturePhoto}>拍照</button>
<ul>
{cameras.map(cam => (
<li key={cam.id}>{cam.name}</li>
))}
</ul>
</div>
);
}import 'package:camera/camera.dart';
class CameraPluginModule extends CameraPluginModuleBindings {
CameraPluginModule(super.moduleManager);
List<CameraDescription>? _cameras;
Future<CameraListResult> getCameras() async {
try {
_cameras = await availableCameras();
final cameraList = _cameras!.map((cam) => {
'id': cam.name,
'name': cam.name,
'facing': cam.lensDirection.toString(),
}).toList();
return CameraListResult(
success: 'true',
cameras: jsonEncode(cameraList),
);
} catch (e) {
return CameraListResult(
success: 'false',
error: e.toString(),
);
}
}
Future<String> capturePhoto(String cameraId) async {
// Implementation for capturing photos
// Return file path or base64 data
}
}import 'package:camera/camera.dart';
class CameraPluginModule extends CameraPluginModuleBindings {
CameraPluginModule(super.moduleManager);
List<CameraDescription>? _cameras;
Future<CameraListResult> getCameras() async {
try {
_cameras = await availableCameras();
final cameraList = _cameras!.map((cam) => {
'id': cam.name,
'name': cam.name,
'facing': cam.lensDirection.toString(),
}).toList();
return CameraListResult(
success: 'true',
cameras: jsonEncode(cameraList),
);
} catch (e) {
return CameraListResult(
success: 'false',
error: e.toString(),
);
}
}
Future<String> capturePhoto(String cameraId) async {
// 拍照实现
// 返回文件路径或base64数据
}
}
Future<bool> processImageData(NativeByteData imageData) async {
try {
// Access raw bytes
final bytes = imageData.bytes;
// Process the data
await SomeFlutterPackage.processImage(bytes);
return true;
} catch (e) {
return false;
}
}interface WebFMyPlugin {
processImageData(imageData: ArrayBuffer | Uint8Array): Promise<boolean>;
}
Future<bool> processImageData(NativeByteData imageData) async {
try {
// 访问原始字节
final bytes = imageData.bytes;
// 处理数据
await SomeFlutterPackage.processImage(bytes);
return true;
} catch (e) {
return false;
}
}interface WebFMyPlugin {
processImageData(imageData: ArrayBuffer | Uint8Array): Promise<boolean>;
}class SensorPluginModule extends SensorPluginModuleBindings {
StreamSubscription? _subscription;
Future<void> startListening(String sensorType) async {
_subscription = SensorPackage.stream.listen((data) {
// Send events to JavaScript
moduleManager.emitModuleEvent(
'SensorPlugin',
'data',
{'value': data.value, 'timestamp': data.timestamp.toString()},
);
});
}
Future<void> stopListening() async {
await _subscription?.cancel();
_subscription = null;
}
void dispose() {
_subscription?.cancel();
super.dispose();
}
}// Listen for events
webf.on('SensorPlugin:data', (event) => {
console.log('Sensor data:', event.detail);
});
await WebFSensorPlugin.startListening('accelerometer');class SensorPluginModule extends SensorPluginModuleBindings {
StreamSubscription? _subscription;
Future<void> startListening(String sensorType) async {
_subscription = SensorPackage.stream.listen((data) {
// 向JavaScript发送事件
moduleManager.emitModuleEvent(
'SensorPlugin',
'data',
{'value': data.value, 'timestamp': data.timestamp.toString()},
);
});
}
Future<void> stopListening() async {
await _subscription?.cancel();
_subscription = null;
}
void dispose() {
_subscription?.cancel();
super.dispose();
}
}// 监听事件
webf.on('SensorPlugin:data', (event) => {
console.log('传感器数据:', event.detail);
});
await WebFSensorPlugin.startListening('accelerometer');import 'package:permission_handler/permission_handler.dart';
class PermissionPluginModule extends PermissionPluginModuleBindings {
Future<PermissionResult> requestPermission(String permissionType) async {
Permission permission;
switch (permissionType) {
case 'camera':
permission = Permission.camera;
break;
case 'microphone':
permission = Permission.microphone;
break;
default:
return PermissionResult(
granted: 'false',
message: 'Unknown permission type',
);
}
final status = await permission.request();
return PermissionResult(
granted: status.isGranted ? 'true' : 'false',
status: status.toString(),
message: _getPermissionMessage(status),
);
}
String _getPermissionMessage(PermissionStatus status) {
switch (status) {
case PermissionStatus.granted:
return 'Permission granted';
case PermissionStatus.denied:
return 'Permission denied';
case PermissionStatus.permanentlyDenied:
return 'Permission permanently denied. Please enable in settings.';
default:
return 'Unknown permission status';
}
}
}import 'package:permission_handler/permission_handler.dart';
class PermissionPluginModule extends PermissionPluginModuleBindings {
Future<PermissionResult> requestPermission(String permissionType) async {
Permission permission;
switch (permissionType) {
case 'camera':
permission = Permission.camera;
break;
case 'microphone':
permission = Permission.microphone;
break;
default:
return PermissionResult(
granted: 'false',
message: '未知权限类型',
);
}
final status = await permission.request();
return PermissionResult(
granted: status.isGranted ? 'true' : 'false',
status: status.toString(),
message: _getPermissionMessage(status),
);
}
String _getPermissionMessage(PermissionStatus status) {
switch (status) {
case PermissionStatus.granted:
return '权限已授予';
case PermissionStatus.denied:
return '权限被拒绝';
case PermissionStatus.permanentlyDenied:
return '权限被永久拒绝,请在设置中启用。';
default:
return '未知权限状态';
}
}
}import 'dart:io';
class PlatformPluginModule extends PlatformPluginModuleBindings {
Future<PlatformInfoResult> getPlatformInfo() async {
String platformName;
String platformVersion;
if (Platform.isAndroid) {
platformName = 'Android';
// Get Android version
} else if (Platform.isIOS) {
platformName = 'iOS';
// Get iOS version
} else if (Platform.isMacOS) {
platformName = 'macOS';
} else {
platformName = 'Unknown';
}
return PlatformInfoResult(
platform: platformName,
version: platformVersion,
isAndroid: Platform.isAndroid,
isIOS: Platform.isIOS,
);
}
}import 'dart:io';
class PlatformPluginModule extends PlatformPluginModuleBindings {
Future<PlatformInfoResult> getPlatformInfo() async {
String platformName;
String platformVersion;
if (Platform.isAndroid) {
platformName = 'Android';
// 获取Android版本
} else if (Platform.isIOS) {
platformName = 'iOS';
// 获取iOS版本
} else if (Platform.isMacOS) {
platformName = 'macOS';
} else {
platformName = 'Unknown';
}
return PlatformInfoResult(
platform: platformName,
version: platformVersion,
isAndroid: Platform.isAndroid,
isIOS: Platform.isIOS,
);
}
}
Future<OperationResult> performOperation(OperationOptions options) async {
// Validate input
if (options.value == null || options.value!.isEmpty) {
return OperationResult(
success: 'false',
error: 'InvalidInput',
message: 'Value cannot be empty',
);
}
if (options.timeout != null && options.timeout! < 0) {
return OperationResult(
success: 'false',
error: 'InvalidTimeout',
message: 'Timeout must be positive',
);
}
try {
// Perform operation with timeout
final result = await Future.timeout(
_doOperation(options.value!),
Duration(milliseconds: options.timeout ?? 5000),
onTimeout: () => throw TimeoutException('Operation timed out'),
);
return OperationResult(
success: 'true',
data: result,
message: 'Operation completed',
);
} on TimeoutException catch (e) {
return OperationResult(
success: 'false',
error: 'Timeout',
message: e.message ?? 'Operation timed out',
);
} catch (e) {
return OperationResult(
success: 'false',
error: 'UnknownError',
message: e.toString(),
);
}
}
Future<OperationResult> performOperation(OperationOptions options) async {
// 验证输入
if (options.value == null || options.value!.isEmpty) {
return OperationResult(
success: 'false',
error: 'InvalidInput',
message: '值不能为空',
);
}
if (options.timeout != null && options.timeout! < 0) {
return OperationResult(
success: 'false',
error: 'InvalidTimeout',
message: '超时时间必须为正数',
);
}
try {
// 带超时执行操作
final result = await Future.timeout(
_doOperation(options.value!),
Duration(milliseconds: options.timeout ?? 5000),
onTimeout: () => throw TimeoutException('操作超时'),
);
return OperationResult(
success: 'true',
data: result,
message: '操作完成',
);
} on TimeoutException catch (e) {
return OperationResult(
success: 'false',
error: 'Timeout',
message: e.message ?? '操作超时',
);
} catch (e) {
return OperationResult(
success: 'false',
error: 'UnknownError',
message: e.toString(),
);
}
}class ResourcePluginModule extends ResourcePluginModuleBindings {
final Map<String, Resource> _activeResources = {};
Future<String> createResource(ResourceOptions options) async {
final id = DateTime.now().millisecondsSinceEpoch.toString();
final resource = Resource(options);
await resource.initialize();
_activeResources[id] = resource;
return id;
}
Future<void> releaseResource(String resourceId) async {
final resource = _activeResources.remove(resourceId);
await resource?.dispose();
}
void dispose() {
// Clean up all resources
for (final resource in _activeResources.values) {
resource.dispose();
}
_activeResources.clear();
super.dispose();
}
}class ResourcePluginModule extends ResourcePluginModuleBindings {
final Map<String, Resource> _activeResources = {};
Future<String> createResource(ResourceOptions options) async {
final id = DateTime.now().millisecondsSinceEpoch.toString();
final resource = Resource(options);
await resource.initialize();
_activeResources[id] = resource;
return id;
}
Future<void> releaseResource(String resourceId) async {
final resource = _activeResources.remove(resourceId);
await resource?.dispose();
}
void dispose() {
// 清理所有资源
for (final resource in _activeResources.values) {
resource.dispose();
}
_activeResources.clear();
super.dispose();
}
}
Future<BatchResult> batchProcess(String itemsJson) async {
final List<dynamic> items = jsonDecode(itemsJson);
final results = <String, dynamic>{};
final errors = <String, String>{};
await Future.wait(
items.asMap().entries.map((entry) async {
final index = entry.key;
final item = entry.value;
try {
final result = await _processItem(item);
results[index.toString()] = result;
} catch (e) {
errors[index.toString()] = e.toString();
}
}),
);
return BatchResult(
success: errors.isEmpty ? 'true' : 'false',
results: jsonEncode(results),
errors: errors.isEmpty ? null : jsonEncode(errors),
processedCount: results.length,
totalCount: items.length,
);
}
Future<BatchResult> batchProcess(String itemsJson) async {
final List<dynamic> items = jsonDecode(itemsJson);
final results = <String, dynamic>{};
final errors = <String, String>{};
await Future.wait(
items.asMap().entries.map((entry) async {
final index = entry.key;
final item = entry.value;
try {
final result = await _processItem(item);
results[index.toString()] = result;
} catch (e) {
errors[index.toString()] = e.toString();
}
}),
);
return BatchResult(
success: errors.isEmpty ? 'true' : 'false',
results: jsonEncode(results),
errors: errors.isEmpty ? null : jsonEncode(errors),
processedCount: results.length,
totalCount: items.length,
);
}undefinedundefinedundefinedundefinedundefinedundefinedundefinedundefinedwebf_{feature}webf_sharewebf_camera{Feature}ModuleShareModuleCameraModule@openwebf/webf-{feature}@yourscope/webf-{feature}webf_{feature}webf_sharewebf_camera{Feature}ModuleShareModuleCameraModule@openwebf/webf-{feature}@yourscope/webf-{feature}// Always return structured error information
return ResultType(
success: 'false',
error: 'ErrorCode', // Machine-readable error code
message: 'Human-readable error message',
);
// Never throw exceptions to JavaScript
// Catch and convert to result objects// 始终返回结构化错误信息
return ResultType(
success: 'false',
error: 'ErrorCode', // 机器可读的错误码
message: '人类可读的错误消息',
);
// 永远不要向JavaScript抛出异常
// 捕获并转换为结果对象/// Brief one-line description.
///
/// Detailed explanation of what this method does.
///
/// Parameters:
/// - [param1]: Description of first parameter
/// - [param2]: Description of second parameter
///
/// Returns a [ResultType] with:
/// - `success`: "true" on success, "false" on failure
/// - `data`: The actual result data
/// - `error`: Error message if failed
///
/// Throws:
/// - Never throws to JavaScript. Returns error in result object.
///
/// Example:
/// ```dart
/// final result = await module.myMethod('input');
/// if (result.success == 'true') {
/// print('Success: ${result.data}');
/// }
/// ```
Future<ResultType> myMethod(String param1, int? param2) async {
// Implementation
}/// 简短的单行描述。
///
/// 此方法功能的详细说明。
///
/// 参数:
/// - [param1]: 第一个参数的描述
/// - [param2]: 第二个参数的描述
///
/// 返回带有以下内容的[ResultType]:
/// - `success`: 成功为"true",失败为"false"
/// - `data`: 实际结果数据
/// - `error`: 失败时的错误消息
///
/// 抛出:
/// - 永远不会向JavaScript抛出异常。在结果对象中返回错误。
///
/// 示例:
/// ```dart
/// final result = await module.myMethod('input');
/// if (result.success == 'true') {
/// print('成功: ${result.data}');
/// }
/// ```
Future<ResultType> myMethod(String param1, int? param2) async {
// 实现
}// Use interfaces for complex types
interface MyOptions {
value: string;
timeout?: number;
retries?: number;
}
// Use specific result types
interface MyResult {
success: string;
data?: any;
error?: string;
}
// Avoid 'any' when possible
// Use union types for enums
type Platform = 'ios' | 'android' | 'macos' | 'windows' | 'linux';// 为复杂类型使用接口
interface MyOptions {
value: string;
timeout?: number;
retries?: number;
}
// 使用特定的结果类型
interface MyResult {
success: string;
data?: any;
error?: string;
}
// 尽可能避免使用'any'
// 为枚举使用联合类型
type Platform = 'ios' | 'android' | 'macos' | 'windows' | 'linux';// Create tests for your module
import 'package:flutter_test/flutter_test.dart';
import 'package:webf_my_plugin/webf_my_plugin.dart';
void main() {
group('MyPluginModule', () {
late MyPluginModule module;
setUp(() {
module = MyPluginModule(mockModuleManager);
});
tearDown(() {
module.dispose();
});
test('myAsyncMethod returns correct result', () async {
final result = await module.myAsyncMethod('test');
expect(result, 'Processed: test');
});
test('handles errors gracefully', () async {
final result = await module.complexMethod(MyOptionsType(
someField: 'invalid',
));
expect(result.success, 'false');
expect(result.error, isNotNull);
});
});
}// 为模块创建测试
import 'package:flutter_test/flutter_test.dart';
import 'package:webf_my_plugin/webf_my_plugin.dart';
void main() {
group('MyPluginModule', () {
late MyPluginModule module;
setUp(() {
module = MyPluginModule(mockModuleManager);
});
tearDown(() {
module.dispose();
});
test('myAsyncMethod返回正确结果', () async {
final result = await module.myAsyncMethod('测试');
expect(result, '已处理: 测试');
});
test('优雅处理错误', () async {
final result = await module.complexMethod(MyOptionsType(
someField: '无效值',
));
expect(result.success, 'false');
expect(result.error, isNotNull);
});
});
}Error: Could not find 'my_plugin_module_bindings_generated.dart'.module.d.tsWebF{ModuleName}webf module-codegenError: Could not find 'my_plugin_module_bindings_generated.dart'.module.d.tsWebF{ModuleName}webf module-codegenModule 'MyPlugin' not foundpubspec.yamlWebF.defineModule()flutter pub getModule 'MyPlugin' not foundpubspec.yamlWebF.defineModule()flutter pub getundefinedundefinedundefinedundefinedshare_module.dartshare.module.d.tsshare_module.dartshare.module.d.tswebf-native-pluginswebf-native-ui-devwebf-native-pluginswebf-native-ui-devwebf module-codegenwebf module-codegenpubspec.yamlflutter pub getWebF.defineModule()npm install @openwebf/webf-my-pluginimport { WebFMyPlugin } from '@openwebf/webf-my-plugin'if (typeof WebFMyPlugin !== 'undefined')pubspec.yamlflutter pub getWebF.defineModule()npm install @openwebf/webf-my-pluginimport { WebFMyPlugin } from '@openwebf/webf-my-plugin'if (typeof WebFMyPlugin !== 'undefined')native_plugins/sharenative_plugins/share