362 lines
11 KiB
Markdown
362 lines
11 KiB
Markdown
# yx_only_office_flutter
|
||
|
||
面向 Flutter 项目的 ONLYOFFICE 文档查看与编辑插件。基于 `webview_flutter` 实现,完全遵循 [ONLYOFFICE Docs API](https://api.onlyoffice.com/docs/docs-api/get-started/basic-concepts/) 官方规范。
|
||
|
||
## 官方参考
|
||
|
||
- [ONLYOFFICE Docs API - Basic Concepts](https://api.onlyoffice.com/docs/docs-api/get-started/basic-concepts/)
|
||
- [ONLYOFFICE Documents App for Android](https://github.com/ONLYOFFICE/documents-app-android)
|
||
- [ONLYOFFICE Documents App for iOS](https://github.com/ONLYOFFICE/documents-app-ios)
|
||
|
||
## 功能特性
|
||
|
||
### 基础功能
|
||
- ✅ **完整的查看与编辑支持**:支持 `view` 和 `edit` 两种模式
|
||
- ✅ **标准配置结构**:完全遵循官方 DocsAPI 配置规范
|
||
- ✅ **丰富的事件桥接**:支持 `onError`、`onAppClose`、`onDownloadAs`、`onRequestSaveAs`、`onRequestInsertImage`、`onDocumentStateChange` 等事件
|
||
- ✅ **JWT 签名支持**:内置 HMAC-SHA256 JWT 签名工具
|
||
- ✅ **高度可定制**:支持自定义 UI、权限、语言、用户信息等
|
||
- ✅ **跨平台支持**:同时支持 Android 和 iOS
|
||
|
||
### 高级功能 🚀 NEW
|
||
- ✅ **WebViewController 直接访问**:完全控制底层 WebView
|
||
- ✅ **编辑器方法调用**:直接调用 DocsAPI 方法(插入图片、下载、审阅等)
|
||
- ✅ **图片插入**:从相机/相册插入图片到文档
|
||
- ✅ **文件下载处理**:自动拦截和处理文件下载
|
||
- ✅ **生命周期管理**:完整的编辑器生命周期事件
|
||
- ✅ **自定义 JavaScript**:执行任意 JS 代码
|
||
|
||
查看 [高级功能指南](docs/ADVANCED_FEATURES.md) 了解详情。
|
||
|
||
## 环境要求
|
||
|
||
1. 可访问的 ONLYOFFICE Document Server(云端或自建)
|
||
2. 能够提供可下载的文件地址(HTTP/HTTPS)
|
||
3. Flutter 3.3+,Dart 3.9.2+
|
||
|
||
## 安装
|
||
|
||
```yaml
|
||
dependencies:
|
||
yx_only_office_flutter: ^0.1.0
|
||
```
|
||
|
||
或使用命令:
|
||
|
||
```sh
|
||
flutter pub add yx_only_office_flutter
|
||
```
|
||
|
||
## 快速开始
|
||
|
||
> 💡 **提示**: 对于高级功能(图片插入、文件下载、编辑器方法调用等),请查看 [高级功能指南](docs/ADVANCED_FEATURES.md)
|
||
|
||
### 1. 查看文档(只读模式)
|
||
|
||
```dart
|
||
import 'package:flutter/material.dart';
|
||
import 'package:yx_only_office_flutter/yx_only_office_flutter.dart';
|
||
|
||
class DocumentViewerPage extends StatelessWidget {
|
||
const DocumentViewerPage({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(title: const Text('文档查看')),
|
||
body: YxOnlyOfficeViewer.create(
|
||
serverUrl: 'https://your-onlyoffice-server.com',
|
||
fileUrl: 'https://example.com/document.docx',
|
||
mode: 'view', // 只读模式
|
||
title: '示例文档.docx',
|
||
allowDownload: true,
|
||
allowPrint: false,
|
||
user: const OnlyOfficeUser(
|
||
id: 'user123',
|
||
name: '张三',
|
||
),
|
||
onError: (error) {
|
||
debugPrint('文档加载错误: $error');
|
||
},
|
||
),
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 编辑文档
|
||
|
||
```dart
|
||
YxOnlyOfficeViewer.create(
|
||
serverUrl: 'https://your-onlyoffice-server.com',
|
||
fileUrl: 'https://example.com/document.docx',
|
||
mode: 'edit', // 编辑模式
|
||
title: '可编辑文档.docx',
|
||
user: const OnlyOfficeUser(
|
||
id: 'user123',
|
||
name: '张三',
|
||
email: 'zhangsan@example.com',
|
||
),
|
||
onDocumentStateChange: (data) {
|
||
// 文档状态变化(是否有未保存的修改)
|
||
final isModified = data ?? false;
|
||
debugPrint('文档已修改: $isModified');
|
||
},
|
||
onRequestSaveAs: (data) {
|
||
// 用户点击"另存为"
|
||
debugPrint('请求保存: $data');
|
||
},
|
||
onRequestInsertImage: (data) {
|
||
// 用户请求插入图片(可以打开 Flutter 图片选择器)
|
||
debugPrint('请求插入图片: $data');
|
||
},
|
||
)
|
||
```
|
||
|
||
### 3. 使用 JWT 签名(推荐用于生产环境)
|
||
|
||
```dart
|
||
const jwtSecret = String.fromEnvironment('ONLYOFFICE_JWT_SECRET');
|
||
|
||
YxOnlyOfficeViewer.create(
|
||
serverUrl: 'https://your-onlyoffice-server.com',
|
||
fileUrl: 'https://example.com/document.docx',
|
||
mode: 'edit',
|
||
tokenFactory: jwtSecret.isNotEmpty
|
||
? OnlyOfficeJwtSigner(jwtSecret)
|
||
: null,
|
||
onError: (error) => debugPrint('错误: $error'),
|
||
)
|
||
```
|
||
|
||
### 4. 高级配置(手动构建配置)
|
||
|
||
```dart
|
||
final config = OnlyOfficeConfigFactory.create(
|
||
fileUrl: 'https://example.com/document.docx',
|
||
mode: 'edit',
|
||
title: '高级配置文档.docx',
|
||
lang: 'zh-CN',
|
||
user: const OnlyOfficeUser(
|
||
id: 'user123',
|
||
name: '张三',
|
||
email: 'zhangsan@example.com',
|
||
),
|
||
customization: const OnlyOfficeCustomization(
|
||
compactToolbar: true,
|
||
hideRightMenu: false,
|
||
toolbarNoTabs: false,
|
||
),
|
||
tokenFactory: OnlyOfficeJwtSigner('your-secret-key'),
|
||
);
|
||
|
||
YxOnlyOfficeViewer(
|
||
serverUrl: 'https://your-onlyoffice-server.com',
|
||
config: config,
|
||
onEvent: (event, data) {
|
||
// 通用事件处理器,捕获所有事件
|
||
debugPrint('事件: $event, 数据: $data');
|
||
},
|
||
)
|
||
```
|
||
|
||
## 支持的文档格式
|
||
|
||
插件自动识别以下文档类型:
|
||
|
||
### 文字处理 (word)
|
||
`doc`, `docx`, `docm`, `dot`, `dotx`, `dotm`, `odt`, `fodt`, `ott`, `rtf`, `txt`, `html`, `htm`, `mht`, `xml`, `pdf`, `djvu`, `fb2`, `epub`, `xps`
|
||
|
||
### 电子表格 (cell)
|
||
`xls`, `xlsx`, `xlsm`, `xlt`, `xltx`, `xltm`, `ods`, `fods`, `ots`, `csv`
|
||
|
||
### 演示文稿 (slide)
|
||
`ppt`, `pptx`, `pptm`, `pps`, `ppsx`, `ppsm`, `pot`, `potx`, `potm`, `odp`, `fodp`, `otp`
|
||
|
||
## 事件回调说明
|
||
|
||
| 事件 | 说明 | 回调参数 |
|
||
|------|------|----------|
|
||
| `onError` | 文档加载或编辑错误 | `String error` |
|
||
| `onAppClose` | 用户请求关闭编辑器 | 无 |
|
||
| `onDownloadAs` | 文档下载完成 | `String fileType, String url` |
|
||
| `onRequestSaveAs` | 用户点击"另存为" | `dynamic data` |
|
||
| `onRequestInsertImage` | 用户请求插入图片 | `dynamic data` |
|
||
| `onDocumentStateChange` | 文档修改状态变化 | `dynamic data` (boolean) |
|
||
| `onMetaChange` | 文档元数据变化 | `dynamic data` |
|
||
| `onMakeActionLink` | 创建操作链接 | `dynamic data` |
|
||
| `onEvent` | 通用事件处理器 | `String event, dynamic data` |
|
||
|
||
## 配置类说明
|
||
|
||
### OnlyOfficeConfig
|
||
|
||
顶层配置对象,包含:
|
||
- `document`: 文档元数据(`OnlyOfficeDocument`)
|
||
- `documentType`: 文档类型(`word`/`cell`/`slide`)
|
||
- `editorConfig`: 编辑器配置(`OnlyOfficeEditorConfig`)
|
||
- `type`: 客户端类型(默认 `mobile`)
|
||
- `token`: JWT 令牌(可选)
|
||
|
||
### OnlyOfficeDocument
|
||
|
||
文档信息:
|
||
- `fileType`: 文件扩展名(如 `docx`)
|
||
- `key`: 文档唯一标识(自动生成或手动指定)
|
||
- `title`: 文档标题
|
||
- `url`: 文档下载地址
|
||
- `permissions`: 文档权限(`OnlyOfficePermissions`)
|
||
|
||
### OnlyOfficeEditorConfig
|
||
|
||
编辑器设置:
|
||
- `mode`: 模式(`view` 或 `edit`)
|
||
- `lang`: 界面语言(默认 `zh-CN`)
|
||
- `user`: 用户信息(`OnlyOfficeUser`)
|
||
- `customization`: UI 自定义(`OnlyOfficeCustomization`)
|
||
- `callbackUrl`: 回调地址(可选,用于服务端保存)
|
||
|
||
### OnlyOfficePermissions
|
||
|
||
权限控制:
|
||
- `edit`: 是否允许编辑
|
||
- `download`: 是否允许下载
|
||
- `print`: 是否允许打印
|
||
- `review`: 是否允许审阅
|
||
- `comment`: 是否允许评论
|
||
- `copy`: 是否允许复制
|
||
- `fillForms`: 是否允许填写表单
|
||
|
||
### OnlyOfficeCustomization
|
||
|
||
UI 定制:
|
||
- `compactToolbar`: 紧凑工具栏
|
||
- `hideRightMenu`: 隐藏右侧菜单
|
||
- `hideLeftMenu`: 隐藏左侧菜单
|
||
- `hideRulers`: 隐藏标尺
|
||
- `toolbarNoTabs`: 工具栏无标签页
|
||
- `showReviewChanges`: 显示审阅更改
|
||
|
||
## JWT 签名
|
||
|
||
### ⚠️ 重要更新:OnlyOffice Docs 7.1+ 身份验证
|
||
|
||
从 OnlyOffice Docs 7.1 版本开始,当服务器启用 JWT 验证时,**必须使用 JWT Secret 对整个配置进行签名**。
|
||
|
||
**正确用法**(传入 JWT Secret,而非预生成的 Token):
|
||
|
||
```dart
|
||
OnlyOfficeViewer(
|
||
onlyOfficeServerUrl: 'https://your-onlyoffice-server.com',
|
||
fileUrl: 'https://example.com/document.docx',
|
||
jwtSecret: 'your-jwt-secret-key', // ✅ 传入 secret,插件会自动签名
|
||
)
|
||
```
|
||
|
||
插件会自动使用 HMAC-SHA256 算法对整个配置进行签名,并将生成的 token 添加到配置中。
|
||
|
||
**错误用法**(旧版本的做法,在 7.1+ 会报错):
|
||
|
||
```dart
|
||
// ❌ 不要这样做!
|
||
OnlyOfficeViewer(
|
||
onlyOfficeServerUrl: 'https://your-onlyoffice-server.com',
|
||
fileUrl: 'https://example.com/document.docx',
|
||
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', // ❌ 错误
|
||
)
|
||
```
|
||
|
||
**安全提示**:
|
||
- ⚠️ 不要在客户端硬编码 JWT 密钥
|
||
- ✅ 推荐通过环境变量或服务端 API 获取签名
|
||
- ✅ 生产环境应在服务端完成签名
|
||
- 📖 参考:[JWT 修复指南](JWT_FIX_GUIDE.md) 和 [ONLYOFFICE 官方文档](https://api.onlyoffice.com/docs/docs-api/additional-api/signature/)
|
||
|
||
## 示例工程
|
||
|
||
查看 `example/` 目录获取完整示例,包括:
|
||
- 基础查看功能
|
||
- 编辑模式演示
|
||
- JWT 签名集成
|
||
- 事件处理示例
|
||
- 集成测试
|
||
|
||
运行示例:
|
||
|
||
```sh
|
||
cd example
|
||
flutter run \
|
||
--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
|
||
```
|
||
|
||
## 常见问题
|
||
|
||
### 1. 文档无法加载?DocsAPI is not loaded 错误?
|
||
|
||
**这是最常见的问题!** 通常是因为:
|
||
|
||
- ❌ **使用了示例 URL** (`https://doc.example.com/`) - 这不是真实服务器
|
||
- ❌ **服务器 URL 不正确** - 无法访问 ONLYOFFICE Document Server
|
||
- ❌ **网络连接问题** - 无法连接到服务器
|
||
- ❌ **CORS 未启用** - 服务器未配置跨域访问
|
||
- ❌ **权限配置缺失** - Android/iOS 未配置网络权限 ⚠️ **最常见**
|
||
|
||
**解决方案**:
|
||
1. **首先检查权限配置** - 查看 [权限和网络配置指南](docs/PERMISSIONS_AND_NETWORK_CONFIG.md) ⚠️ **重要**
|
||
2. 确保使用**真实的** ONLYOFFICE Document Server 地址
|
||
3. 在浏览器中测试 API 脚本 URL: `https://your-server.com/web-apps/apps/api/documents/api.js`
|
||
4. 检查网络连接和防火墙设置
|
||
5. 查看 [故障排除指南](docs/TROUBLESHOOTING.md) 获取详细帮助
|
||
|
||
**快速修复权限问题**:
|
||
- Android: 确保 `AndroidManifest.xml` 包含 `INTERNET` 权限和 `network_security_config`
|
||
- iOS: 确保 `Info.plist` 包含 `NSAppTransportSecurity` 配置
|
||
- 配置后执行 `flutter clean` 并重新构建
|
||
|
||
**快速检查**:
|
||
```bash
|
||
# 在浏览器中打开这个 URL,应该能看到 JavaScript 代码
|
||
https://your-server.com/web-apps/apps/api/documents/api.js
|
||
```
|
||
|
||
### 2. 其他常见问题
|
||
|
||
检查:
|
||
- Document Server 是否可访问
|
||
- 文件 URL 是否可下载
|
||
- JWT 签名是否正确(如果启用)
|
||
- 网络权限是否配置(Android/iOS)
|
||
|
||
### 2. 编辑模式不生效?
|
||
|
||
确保:
|
||
- `mode` 设置为 `'edit'`
|
||
- `document.permissions.edit` 为 `true`
|
||
- 用户信息已正确配置
|
||
|
||
### 3. 如何保存编辑后的文档?
|
||
|
||
ONLYOFFICE 支持两种保存方式:
|
||
1. **服务端回调**:配置 `callbackUrl`,Document Server 会将修改推送到你的服务器
|
||
2. **客户端下载**:监听 `onDownloadAs` 事件,获取修改后的文档 URL
|
||
|
||
## 兼容性
|
||
|
||
- ✅ Android 5.0+
|
||
- ✅ iOS 11.0+
|
||
- ✅ ONLYOFFICE Document Server 6.1+
|
||
|
||
## 许可证
|
||
|
||
本项目采用 MIT 许可证,详见 [LICENSE](LICENSE) 文件。
|
||
|
||
## 贡献
|
||
|
||
欢迎提交 Issue 和 Pull Request!
|
||
|
||
## 更新日志
|
||
|
||
查看 [CHANGELOG.md](CHANGELOG.md) 了解版本更新历史。
|