9.9 KiB
9.9 KiB
高级功能指南
本文档介绍 yx_only_office_flutter 插件的高级功能,这些功能基于对官方 Android 和 iOS 项目的深入研究实现。
概述
高级功能通过 YxOnlyOfficeAdvancedViewer 提供,包括:
- ✅ WebViewController 直接访问 - 完全控制 WebView
- ✅ 编辑器方法调用 - 直接调用 DocsAPI 方法
- ✅ 图片插入 - 从相机/相册插入图片
- ✅ 文件下载 - 自动处理文件下载
- ✅ 生命周期管理 - 完整的编辑器生命周期事件
- ✅ 自定义 JavaScript 执行 - 执行任意 JS 代码
快速开始
基础使用
import 'package:yx_only_office_flutter/yx_only_office_flutter.dart';
YxOnlyOfficeAdvancedViewer(
serverUrl: 'https://your-server.com',
config: config,
onControllerReady: (controller) {
// WebViewController 已准备好
print('Controller ready!');
},
onDocumentReady: () {
// 文档已加载完成,可以调用编辑器方法
print('Document ready!');
},
)
核心功能
1. WebViewController 访问
获取底层 WebViewController 进行高级操作:
WebViewController? _controller;
YxOnlyOfficeAdvancedViewer(
serverUrl: serverUrl,
config: config,
onControllerReady: (controller) {
_controller = controller;
// 现在可以直接使用 WebViewController
controller.runJavaScript('console.log("Hello from Flutter!")');
},
)
2. 编辑器方法调用
直接调用 DocsAPI 提供的方法:
插入图片
final GlobalKey<_YxOnlyOfficeAdvancedViewerState> viewerKey = GlobalKey();
// 在 Widget 中
YxOnlyOfficeAdvancedViewer(
key: viewerKey,
serverUrl: serverUrl,
config: config,
)
// 调用方法
final result = await viewerKey.currentState!.insertImage(
'https://example.com/image.jpg'
);
if (result.success) {
print('图片插入成功');
} else {
print('失败: ${result.error}');
}
下载文档
// 下载为 PDF
final result = await viewerKey.currentState!.downloadAs('pdf');
// 下载为 DOCX
final result = await viewerKey.currentState!.downloadAs('docx');
// 支持的格式: docx, pdf, txt, rtf, odt, html, epub 等
设置审阅模式
// 启用审阅模式
await viewerKey.currentState!.setReviewerMode(true);
// 显示修订
await viewerKey.currentState!.showReviewChanges(true);
销毁编辑器
await viewerKey.currentState!.destroyEditor();
执行自定义 JavaScript
final result = await viewerKey.currentState!.executeJavaScript('''
if (window.docEditor) {
return window.docEditor.getDocumentName();
}
return null;
''');
print('文档名称: ${result.data}');
3. 图片插入功能
方式 1:使用内置处理器
YxOnlyOfficeAdvancedViewer(
serverUrl: serverUrl,
config: config,
onRequestImageFromGallery: () async {
// 从相册选择图片
final image = await ImagePicker().pickImage(
source: ImageSource.gallery,
);
if (image == null) return null;
// 上传到服务器
final imageUrl = await uploadToServer(image.path);
return imageUrl;
},
onRequestImageFromCamera: () async {
// 从相机拍照
final image = await ImagePicker().pickImage(
source: ImageSource.camera,
);
if (image == null) return null;
final imageUrl = await uploadToServer(image.path);
return imageUrl;
},
)
方式 2:手动调用
// 选择图片
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
final imageUrl = await uploadToServer(image!.path);
// 插入到文档
final result = await viewerKey.currentState!.insertImage(imageUrl);
4. 文件下载处理
自动拦截并处理文件下载请求:
YxOnlyOfficeAdvancedViewer(
serverUrl: serverUrl,
config: config,
enableFileDownload: true,
onDownloadFile: (url, filename) async {
// 下载文件
final response = await http.get(Uri.parse(url));
// 保存到本地
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/$filename');
await file.writeAsBytes(response.bodyBytes);
print('文件已保存: ${file.path}');
},
)
5. 生命周期事件
完整的编辑器生命周期管理:
YxOnlyOfficeAdvancedViewer(
serverUrl: serverUrl,
config: config,
onAppReady: () {
print('✅ 编辑器应用已准备好');
},
onDocumentReady: () {
print('✅ 文档已加载完成');
// 现在可以调用编辑器方法
},
onDocumentStateChange: (data) {
final hasChanges = data == true;
print('📝 文档${hasChanges ? "已修改" : "未修改"}');
},
onError: (error) {
print('❌ 错误: $error');
},
)
完整示例
查看 example/lib/main_advanced.dart 获取完整的可运行示例,包括:
- ✅ 图片插入(相机/相册)
- ✅ 文件下载(多种格式)
- ✅ 审阅模式切换
- ✅ 自定义 JavaScript 执行
- ✅ 完整的错误处理
- ✅ 用户友好的 UI
运行高级示例
cd example
flutter run -t lib/main_advanced.dart \
--dart-define ONLYOFFICE_SERVER_URL=https://your-server.com \
--dart-define ONLYOFFICE_FILE_URL=https://example.com/doc.docx \
--dart-define ONLYOFFICE_JWT_SECRET=your-secret \
--dart-define UPLOAD_URL=https://your-upload-server.com/upload
API 参考
EditorMethodResult
所有编辑器方法返回 EditorMethodResult:
class EditorMethodResult {
final bool success; // 是否成功
final dynamic data; // 返回数据
final String? error; // 错误信息
}
可用方法
| 方法 | 说明 | 返回值 |
|---|---|---|
insertImage(String url) |
插入图片 | EditorMethodResult |
downloadAs(String fileType) |
下载文档 | EditorMethodResult |
destroyEditor() |
销毁编辑器 | EditorMethodResult |
setReviewerMode(bool enabled) |
设置审阅模式 | EditorMethodResult |
showReviewChanges(bool show) |
显示修订 | EditorMethodResult |
executeJavaScript(String code) |
执行 JS 代码 | EditorMethodResult |
高级配置
自定义图片上传
Future<String?> uploadImage(File imageFile) async {
final request = http.MultipartRequest(
'POST',
Uri.parse('https://your-server.com/upload'),
);
request.files.add(
await http.MultipartFile.fromPath('file', imageFile.path),
);
final response = await request.send();
if (response.statusCode == 200) {
final body = await response.stream.bytesToString();
final json = jsonDecode(body);
return json['url'];
}
return null;
}
自定义文件下载
Future<void> downloadFile(String url, String filename) async {
// 显示进度对话框
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
content: Row(
children: [
CircularProgressIndicator(),
SizedBox(width: 16),
Text('正在下载...'),
],
),
),
);
try {
final response = await http.get(Uri.parse(url));
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/$filename');
await file.writeAsBytes(response.bodyBytes);
Navigator.pop(context); // 关闭进度对话框
// 显示成功提示
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('文件已保存: ${file.path}')),
);
} catch (e) {
Navigator.pop(context);
// 显示错误
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('下载失败: $e')),
);
}
}
与基础版本的对比
| 功能 | YxOnlyOfficeViewer | YxOnlyOfficeAdvancedViewer |
|---|---|---|
| 查看文档 | ✅ | ✅ |
| 编辑文档 | ✅ | ✅ |
| 基础事件 | ✅ | ✅ |
| WebViewController 访问 | ❌ | ✅ |
| 编辑器方法调用 | ❌ | ✅ |
| 图片插入 | ❌ | ✅ |
| 文件下载处理 | ❌ | ✅ |
| 生命周期事件 | 部分 | ✅ 完整 |
| 自定义 JS 执行 | ❌ | ✅ |
最佳实践
1. 等待文档准备好
bool _isDocumentReady = false;
YxOnlyOfficeAdvancedViewer(
onDocumentReady: () {
setState(() => _isDocumentReady = true);
},
)
// 只在文档准备好后调用方法
if (_isDocumentReady) {
await viewerKey.currentState!.insertImage(url);
}
2. 错误处理
final result = await viewerKey.currentState!.downloadAs('pdf');
if (result.success) {
print('成功');
} else {
print('失败: ${result.error}');
// 显示错误提示给用户
}
3. 内存管理
@override
void dispose() {
// 在页面销毁时销毁编辑器
viewerKey.currentState?.destroyEditor();
super.dispose();
}
常见问题
Q: 如何判断编辑器是否准备好?
A: 监听 onDocumentReady 回调:
bool _isReady = false;
onDocumentReady: () {
setState(() => _isReady = true);
}
Q: 图片插入失败怎么办?
A: 检查:
- 文档是否已准备好(
onDocumentReady已触发) - 图片 URL 是否可访问
- 是否有编辑权限(
mode: 'edit')
Q: 如何获取编辑器的当前状态?
A: 使用 executeJavaScript:
final result = await viewerKey.currentState!.executeJavaScript('''
if (window.docEditor) {
return {
name: window.docEditor.getDocumentName(),
// 其他信息...
};
}
return null;
''');
Q: 支持哪些下载格式?
A: 支持的格式取决于文档类型:
- Word: docx, pdf, txt, rtf, odt, html, epub
- Excel: xlsx, pdf, csv, ods
- PowerPoint: pptx, pdf, odp
更多资源
贡献
欢迎提交 Issue 和 Pull Request!如果您发现了 Bug 或有功能建议,请在 GitHub 上告诉我们。