Flutter PDF处理插件pdftron_flutter的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter PDF处理插件pdftron_flutter的使用

关于PDFTron Flutter

PDFTron的Flutter PDF库为iOS和Android应用程序带来了流畅、灵活且独立的文档查看和编辑解决方案。以下是该库的一些主要特点:

  • 直接查看和转换MS Office文档
  • 完全可自定义的开源UI以提高应用参与度
  • 文档重排以提高移动设备上的可读性和可访问性
  • 文件流式传输以更快地查看远程和复杂文档
  • 夜间模式以在低光环境下改善查看体验
  • 更多功能…

更多信息可以在官方文档中找到。

目录

前提条件

  • 试用期间不需要许可证密钥。但是,试用期结束后需要有效的商业许可证密钥。
  • PDFTron SDK >= 6.9.0
  • Flutter >= 2.0.0

空安全

Dart现在支持空安全,从Dart 2.12.0和Flutter 2.0.0开始可用。有关迁移指南,请参阅迁移指南

如果您希望使用我们的空安全SDK,可以在以下地方找到:

遗留UI

版本0.0.6是遗留UI的最后一个稳定版本。可以在这里找到该版本。

安装

1. 创建Flutter项目

首先按照Flutter入门指南安装设置编辑器创建Flutter项目。假设您的项目是通过运行flutter create myapp创建的。

2. 添加依赖

myapp/pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  pdftron_flutter:

或者从GitHub添加:

dependencies:
  flutter:
    sdk: flutter
  pdftron_flutter:
    git:
      url: git://github.com/ApryseSDK/pdftron-flutter.git

3. 获取包

myapp目录中运行flutter packages get

4. Android配置

myapp/android/app/build.gradle文件中添加以下内容:

defaultConfig {
    applicationId "com.example.myapp"
    minSdkVersion 21
    multiDexEnabled true
    manifestPlaceholders += [pdftronLicenseKey:PDFTRON_LICENSE_KEY]
    targetSdkVersion flutter.targetSdkVersion
    versionCode flutterVersionCode.toInteger()
    versionName flutterVersionName
}

myapp/android/gradle.properties文件中添加以下内容:

# Add the PDFTRON_LICENSE_KEY variable here. 
# For trial purposes leave it blank.
# For production add a valid commercial license key.
PDFTRON_LICENSE_KEY=

myapp/android/app/src/main/AndroidManifest.xml文件中添加以下内容:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.myapp">

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.RECORD_AUDIO" />

  <application
    android:largeHeap="true"
    android:usesCleartextTraffic="true">

    <meta-data
      android:name="pdftron_license_key"
      android:value="${pdftronLicenseKey}"/>
  </application>
</manifest>

如果使用DocumentView小部件,将MainActivity文件(Kotlin或Java)的父类更改为FlutterFragmentActivity

import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant

class MainActivity : FlutterFragmentActivity() {
    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine);
    }
}

5. iOS配置

myapp/ios/Podfile文件中添加以下内容:

platform :ios, '10.0'

target 'Runner' do
  use_frameworks!

  pod 'PDFTron', podspec: 'https://pdftron.com/downloads/ios/flutter/pdftron/latest.podspec'
  pod 'PDFTronTools', podspec: 'https://pdftron.com/downloads/ios/flutter/pdftron-tools/latest.podspec'
end

确保集成过程成功,运行flutter build ios --no-codesign

Widget或插件

有2种不同的方式使用PDFTron Flutter API:

  • 通过插件呈现文档。
  • 通过小部件显示PDFTron文档视图。

您必须选择其中一种方式,并在所有API中使用它。混合使用小部件和插件API将无法正常工作。

如果您选择Android小部件,需要为操作系统入侵(如设备顶部的状态栏)添加填充。一种方法是设置启用的系统UI,然后将小部件包装在SafeArea或使用AppBar中:

// 如果使用Flutter v2.3.0-17.0.pre或更早版本
SystemChrome.setEnabledSystemUIOverlays(
  SystemUiOverlay.values
);
// 如果使用较新版本的Flutter
SystemChrome.setEnabledSystemUIMode(
  SystemUiMode.edgeToEdge,
);

// 如果使用SafeArea:
return SafeArea (
  child: DocumentView(
    onCreated: _onDocumentViewCreated,
  ));

// 如果使用AppBar:
return Scaffold(
  appBar: AppBar( toolbarHeight: 0 ),
  body: DocumentView(
    onCreated: _onDocumentViewCreated,
  ));

使用方法

1. 添加权限处理

如果您想使用本地文件,需要在myapp/pubspec.yaml中添加以下依赖:

  permission_handler: ^11.3.1

2. 替换lib/main.dart

打开lib/main.dart,替换整个文件内容如下:

import 'dart:async';
import 'dart:io' show Platform;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pdftron_flutter/pdftron_flutter.dart';
// 如果使用本地文件,取消注释以下行
// import 'package:permission_handler/permission_handler.dart';

// 设置此值以通过Widget查看文档
var enableWidget = true;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Viewer(),
    );
  }
}

class Viewer extends StatefulWidget {
  @override
  _ViewerState createState() => _ViewerState();
}

class _ViewerState extends State<Viewer> {
  String _version = 'Unknown';
  String _document = "https://pdftron.s3.amazonaws.com/downloads/pl/PDFTRON_mobile_about.pdf";
  bool _showViewer = true;

  @override
  void initState() {
    super.initState();
    initPlatformState();
    if (!enableWidget) {
      showViewer();
    }

    // 如果使用本地文件:
    // * 删除上面的 `showViewer();` 行。
    // * 更改 `_document` 字段为您的本地文件路径。
    // * 取消注释以下部分,包括 `launchWithPermission()`。
    // if (Platform.isIOS) {
    //   showViewer(); // iOS 不需要权限。
    // } else {
    //   launchWithPermission(); // Android 需要权限。
    // }
  }

  // 如果使用本地文件,取消注释以下部分:
  // Future<void> launchWithPermission() async {
  //   PermissionStatus permission = await Permission.storage.request();
  //   if (permission.isGranted) {
  //     showViewer();
  //   }
  // }

  // 平台消息是异步的,因此在异步方法中初始化。
  Future<void> initPlatformState() async {
    String version;
    // 平台消息可能失败,因此使用 try/catch PlatformException。
    try {
      // 初始化 PDFTron SDK,必须在使用任何功能之前调用。
      PdftronFlutter.initialize("your_pdftron_license_key");

      version = await PdftronFlutter.version;
    } on PlatformException {
      version = 'Failed to get platform version.';
    }

    // 如果在异步平台消息飞行过程中移除了小部件,则应丢弃回复而不是调用
    // setState 来更新我们不存在的外观。
    if (!mounted) return;

    setState(() {
      _version = version;
    });
  }

  void showViewer() async {
    // 没有配置文件打开时将启用所有功能。
    // await PdftronFlutter.openDocument(_document);

    var config = Config();
    // 如何禁用功能:
    //      config.disabledElements = [Buttons.shareButton, Buttons.searchButton];
    //      config.disabledTools = [Tools.annotationCreateLine, Tools.annotationCreateRectangle];
    // 其他查看器配置:
    //      config.multiTabEnabled = true;
    //      config.customHeaders = {'headerName': 'headerValue'};

    // 文档加载事件监听器
    var documentLoadedCancel = startDocumentLoadedListener((filePath) {
      print("document loaded: $filePath");
    });

    await PdftronFlutter.openDocument(_document, config: config);

    try {
      // 导入注释命令,格式为XFDF,告诉是否在当前文档中添加、修改或删除注释。
      PdftronFlutter.importAnnotationCommand(
          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
              "<xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\n" +
              "  <add>\n" +
              "    <square style=\"solid\" width=\"5\" color=\"#E44234\" opacity=\"1\" creationdate=\"D:20200619203211Z\" flags=\"print\" date=\"D:20200619203211Z\" name=\"c684da06-12d2-4ccd-9361-0a1bf2e089e3\" page=\"1\" rect=\"113.312,277.056,235.43,350.173\" title=\"\" />\n" +
              "  </add>\n" +
              "  <modify />\n" +
              "  <delete />\n" +
              "  <pdf-info import-version=\"3\" version=\"2\" xmlns=\"http://www.pdftron.com/pdfinfo\" />\n" +
              "</xfdf>");
    } on PlatformException catch (e) {
      print("Failed to importAnnotationCommand '${e.message}'.");
    }

    try {
      PdftronFlutter.importBookmarkJson('{"0":"Page 1"}');
    } on PlatformException catch (e) {
      print("Failed to importBookmarkJson '${e.message}'.");
    }

    // 当本地注释更改提交到文档时的事件监听器。
    // xfdfCommand 是最后更改的注释的 XFDF 命令。
    var annotCancel = startExportAnnotationCommandListener((xfdfCommand) {
      // 本地注释更改。
      // 在此处将 XFDF 命令上传到服务器。
      String command = xfdfCommand;
      // Dart 限制了打印到控制台的字符数。
      // 以下代码确保所有 XFDF 命令都被打印。
      if (command.length > 1024) {
        print("flutter xfdfCommand:\n");
        int start = 0;
        int end = 1023;
        while (end < command.length) {
          print(command.substring(start, end) + "\n");
          start += 1024;
          end += 1024;
        }
        print(command.substring(start));
      } else {
        print(command);
      }
    });

    // 当本地书签更改提交到文档时的事件监听器。
    // bookmarkJson 是包含更改时存在的所有书签的 JSON 字符串。
    var bookmarkCancel = startExportBookmarkListener((bookmarkJson) {
      print("flutter bookmark: $bookmarkJson");
    });

    var path = await PdftronFlutter.saveDocument();
    print("flutter save: $path");

    // 取消事件:
    // annotCancel();
    // bookmarkCancel();
    // documentLoadedCancel();
  }

  @override
  Widget build(BuildContext context) {
    Widget documentChild = Container();

    if (enableWidget) {
      // 如果使用 Android 小部件,取消注释以下行之一:
      // 如果使用 Flutter v2.3.0-17.0.pre 或更早版本。
      // SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
      // 如果使用较新版本的 Flutter。
      SystemChrome.setEnabledSystemUIMode(
        SystemUiMode.edgeToEdge,
      );
      documentChild = _showViewer
          ? SafeArea(
              child: DocumentView(
                onCreated: _onDocumentViewCreated,
              ))
          : Container();
    }

    return Scaffold(
      body: Container(
        width: double.infinity,
        height: double.infinity,
        child: documentChild,
      ),
    );
  }

  // 此函数用于在创建后控制 DocumentView 小部件。
  // 小部件需要传递一个 void Function(DocumentViewController controller) 才能工作。
  void _onDocumentViewCreated(DocumentViewController controller) async {
    Config config = new Config();

    var leadingNavCancel = startLeadingNavButtonPressedListener(() {
      // 取消注释此行以在按下前导导航按钮时退出查看器:
      // this.setState(() {
      //   _showViewer = !_showViewer;
      // });

      // 在按下前导导航按钮时显示对话框。
      _showMyDialog();
    });

    await controller.openDocument(_document, config: config);
  }

  Future<void> _showMyDialog() async {
    print('hello');
    return showDialog<void>(
      context: context,
      barrierDismissible: false, // 用户必须点击按钮!
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('AlertDialog'),
          content: SingleChildScrollView(
            child: Text('前导导航按钮已被按下。'),
          ),
          actions: <Widget>[
            TextButton(
              child: Text('OK'),
              onPressed: () {
                Navigator.of(context).pop();
              },
            ),
          ],
        );
      },
    );
  }
}

变更日志

参见变更日志

贡献

参见贡献指南

许可证

参见许可证


更多关于Flutter PDF处理插件pdftron_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter PDF处理插件pdftron_flutter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用pdftron_flutter插件来处理PDF文件的示例代码。这个示例将展示如何加载、渲染和保存PDF文档。

首先,确保你已经在pubspec.yaml文件中添加了pdftron_flutter依赖:

dependencies:
  flutter:
    sdk: flutter
  pdftron_flutter: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

示例代码

1. 导入必要的包

在你的Dart文件中导入pdftron_flutter包:

import 'package:flutter/material.dart';
import 'package:pdftron_flutter/pdftron_flutter.dart';

2. 创建一个Flutter应用

下面是一个完整的Flutter应用示例,展示如何使用pdftron_flutter加载、渲染和保存PDF文档。

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('PDFtron Flutter Example'),
        ),
        body: PDFViewerScreen(),
      ),
    );
  }
}

class PDFViewerScreen extends StatefulWidget {
  @override
  _PDFViewerScreenState createState() => _PDFViewerScreenState();
}

class _PDFViewerScreenState extends State<PDFViewerScreen> {
  late PDFDoc _pdfDoc;
  late PDFViewCtrl _pdfViewCtrl;
  late String _documentPath;

  @override
  void initState() {
    super.initState();
    // 初始化PDFTron库
    Pdftron.initialize();

    // 加载本地或远程PDF文件
    // 这里假设你有一个本地PDF文件路径
    _documentPath = 'assets/sample.pdf';  // 请确保你的assets文件夹中有这个文件
    _loadPDFDocument();
  }

  @override
  void dispose() {
    // 清理资源
    _pdfDoc.close();
    _pdfViewCtrl.close();
    super.dispose();
  }

  Future<void> _loadPDFDocument() async {
    // 打开PDF文档
    _pdfDoc = await PDFDoc.fromFile(_documentPath);

    // 创建PDFViewCtrl对象
    _pdfViewCtrl = await PDFViewCtrl.create();
    
    // 设置文档到PDFViewCtrl
    await _pdfViewCtrl.setDoc(_pdfDoc);

    // 跳转到第一页
    await _pdfViewCtrl.goToPage(0);

    // 这里你可以将PDFViewCtrl嵌入到你的Flutter Widget树中
    // 由于PDFViewCtrl是一个原生视图,我们需要使用PlatformViewLink来嵌入
    if (mounted) {
      setState(() {});
    }
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: _pdfViewCtrl.platformView != null
          ? Container(
              height: 600,  // 设置容器高度
              child: PlatformViewLink(
                viewType: 'plugins.flutter.io/pdftron_flutter',
                surfaceId: _pdfViewCtrl.platformView!.id,
                onCreatePlatformView: (id, viewType) {
                  // 这里不需要处理,因为PDFViewCtrl已经创建了平台视图
                },
              ),
            )
          : CircularProgressIndicator(),  // 显示加载指示器直到PDF加载完成
    );
  }
}

3. 确保资源文件存在

如果你使用的是本地PDF文件,请确保在pubspec.yaml中声明了资源文件:

flutter:
  assets:
    - assets/sample.pdf

注意事项

  1. 权限:如果你从设备存储加载PDF文件,确保你的应用有读取存储的权限。
  2. 平台特定配置pdftron_flutter是一个跨平台插件,但你可能需要在iOS和Android项目中进行一些特定的配置,比如添加依赖和配置权限。
  3. 错误处理:在实际应用中,你应该添加适当的错误处理逻辑来处理文件加载失败等情况。

这个示例展示了基本的PDF处理功能,pdftron_flutter插件提供了更丰富的功能,如注释、搜索、编辑等,你可以参考官方文档获取更多信息。

回到顶部