3 Commits ff3ab3b90d ... e8d0a11a27

Author SHA1 Message Date
  liuxiaolong e8d0a11a27 ComPDFKit(flutter) - 2.2.0-beta.1 ios plugin file 5 days ago
  liuxiaolong ee936eb088 ComPDFKit(flutter) - 2.2.0-beta.1 android新增注释交互接口,ios未完成 5 days ago
  liuxiaolong bc88734edb ComPDFKit(flutter) - 2.2.0 安卓端新增部分document相关接口 1 week ago

+ 6 - 6
README.md

@@ -151,7 +151,7 @@ Alternatively you can update the `AndroidManifest.xml` file to use `FlutterFragm
  dependencies:
    flutter:
      sdk: flutter
-+  compdfkit_flutter: ^2.1.3
++  compdfkit_flutter: ^2.2.0
 ```
 
 8. Add the PDF documents you want to display in the project
@@ -197,7 +197,7 @@ cd example
  dependencies:
    flutter:
      sdk: flutter
-+  compdfkit_flutter: ^2.1.3
++  compdfkit_flutter: ^2.2.0
 ```
 
 4. Open your project's Podfile in a text editor:
@@ -220,8 +220,8 @@ open ios/Podfile
    use_modular_headers!`
 
    flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
-+  pod 'ComPDFKit_Tools', podspec:'https://www.compdf.com/download/ios/cocoapods/xcframeworks/compdfkit_tools/2.1.3.podspec'
-+  pod 'ComPDFKit', podspec:'https://www.compdf.com/download/ios/cocoapods/xcframeworks/compdfkit/2.1.3.podspec'
++  pod 'ComPDFKit_Tools', podspec:'https://www.compdf.com/download/ios/cocoapods/xcframeworks/compdfkit_tools/2.2.0.podspec'
++  pod 'ComPDFKit', podspec:'https://www.compdf.com/download/ios/cocoapods/xcframeworks/compdfkit/2.2.0.podspec'
 
  end
 ```
@@ -557,8 +557,8 @@ target 'PDFView_RN' do
     # Pods for testing
   end
 
-+  pod 'ComPDFKit', :git => 'https://github.com/ComPDFKit/compdfkit-pdf-sdk-ios-swift.git', :tag => '2.1.3'
-+  pod 'ComPDFKit_Tools', :git => 'https://github.com/ComPDFKit/compdfkit-pdf-sdk-ios-swift.git', :tag => '2.1.3'
++  pod 'ComPDFKit', :git => 'https://github.com/ComPDFKit/compdfkit-pdf-sdk-ios-swift.git', :tag => '2.2.0'
++  pod 'ComPDFKit_Tools', :git => 'https://github.com/ComPDFKit/compdfkit-pdf-sdk-ios-swift.git', :tag => '2.2.0'
 
   # Enables Flipper.
   #

+ 1 - 1
android/build.gradle

@@ -40,7 +40,7 @@ android {
         implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
 
         // dependencies compdfkit pdf sdk
-        api 'com.compdf:compdfkit-tools:2.1.3'
+        api 'com.compdf:compdfkit-tools:2.2.0-SNAPSHOT'
 
         testImplementation 'junit:junit:4.13.2'
         testImplementation 'org.mockito:mockito-core:5.0.0'

+ 24 - 3
android/src/main/java/com/compdfkit/flutter/compdfkit_flutter/constants/CPDFConstants.java

@@ -11,9 +11,6 @@
 package com.compdfkit.flutter.compdfkit_flutter.constants;
 
 
-import io.flutter.plugin.common.MethodCall;
-import io.flutter.plugin.common.MethodChannel.Result;
-
 public class CPDFConstants {
 
   public static class ChannelMethod {
@@ -39,6 +36,7 @@ public class CPDFConstants {
     public static final String OPEN_DOCUMENT = "open_document";
 
     public static final String GET_TEMP_DIRECTORY = "get_temporary_directory";
+    public static final String REMOVE_SIGN_FILE_LIST = "remove_sign_file_list";
 
     public static final String SAVE = "save";
 
@@ -64,6 +62,8 @@ public class CPDFConstants {
 
     public static final String SET_MARGIN = "set_margin";
 
+    public static final String SET_PAGE_SPACING = "set_page_spacing";
+
     public static final String SET_CONTINUE_MODE = "set_continue_mode";
 
     public static final String IS_CONTINUE_MODE = "is_continue_mode";
@@ -92,8 +92,29 @@ public class CPDFConstants {
 
     public static final String GET_PAGE_SIZE = "get_page_size";
 
+    public static final String GET_FILE_NAME = "get_file_name";
+
+    public static final String IS_ENCRYPTED = "is_encrypted";
+
+    public static final String IS_IMAGE_DOC = "is_image_doc";
+
+    public static final String GET_PERMISSIONS = "get_permissions";
+
+    public static final String CHECK_OWNER_UNLOCKED = "check_owner_unlocked";
+
+    public static final String CHECK_PASSWORD = "check_password";
+
+    public static final String CLOSE = "close";
+
     public static final String HAS_CHANGE = "has_change";
 
+    public static final String IMPORT_ANNOTATIONS = "import_annotations";
+
+    public static final String EXPORT_ANNOTATIONS = "export_annotations";
+
+    public static final String REMOVE_ALL_ANNOTATIONS = "remove_all_annotations";
+
+    public static final String GET_PAGE_COUNT = "get_page_count";
   }
 
 }

+ 3 - 1
android/src/main/java/com/compdfkit/flutter/compdfkit_flutter/platformview/CPDFViewCtrlFlutter.java

@@ -55,9 +55,11 @@ public class CPDFViewCtrlFlutter implements PlatformView {
         Log.e(LOG_TAG, "CPDFViewCtrlFlutter:Create CPDFDocumentFragment");
         initCPDFViewCtrl(context, creationParams);
 
+        // Register plug-ins related to interaction with the document
+        // interface to control document display, such as setting the document scrolling direction.
         methodChannel = new CPDFViewCtrlPlugin(context, binaryMessenger, viewId);
-        methodChannel.setDocumentFragment(documentFragment);
         methodChannel.register();
+        methodChannel.setDocumentFragment(documentFragment);
 
     }
 

+ 174 - 0
android/src/main/java/com/compdfkit/flutter/compdfkit_flutter/plugin/CPDFDocumentPlugin.java

@@ -0,0 +1,174 @@
+/*
+ * Copyright © 2014-2024 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ *
+ */
+
+package com.compdfkit.flutter.compdfkit_flutter.plugin;
+
+
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.CHECK_OWNER_UNLOCKED;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.CHECK_PASSWORD;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.CLOSE;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.GET_PAGE_COUNT;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.REMOVE_ALL_ANNOTATIONS;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.EXPORT_ANNOTATIONS;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.GET_FILE_NAME;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.GET_PERMISSIONS;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.HAS_CHANGE;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.IMPORT_ANNOTATIONS;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.IS_ENCRYPTED;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.IS_IMAGE_DOC;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.OPEN_DOCUMENT;
+
+import android.content.Context;
+import android.net.Uri;
+import android.text.TextUtils;
+import androidx.annotation.NonNull;
+import com.compdfkit.core.document.CPDFDocument;
+import com.compdfkit.core.document.CPDFDocument.PDFDocumentError;
+import com.compdfkit.core.page.CPDFPage;
+import com.compdfkit.tools.common.utils.CFileUtils;
+import com.compdfkit.tools.common.utils.threadpools.CThreadPoolUtils;
+import com.compdfkit.ui.reader.CPDFReaderView;
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel.Result;
+import java.io.File;
+
+public class CPDFDocumentPlugin extends BaseMethodChannelPlugin {
+
+  private String documentUid;
+
+  private CPDFReaderView readerView;
+
+  public CPDFDocumentPlugin(Context context,
+      BinaryMessenger binaryMessenger, String documentUid) {
+    super(context, binaryMessenger);
+    this.documentUid = documentUid;
+  }
+
+  public void setReaderView(CPDFReaderView readerView) {
+    this.readerView = readerView;
+  }
+
+
+  @Override
+  public String methodName() {
+    return "com.compdfkit.flutter.document_" + documentUid;
+  }
+
+  @Override
+  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
+    if (readerView == null || readerView.getPDFDocument() == null) {
+      result.error("-1", "CPDFReaderView isnull or CPDFDocument is null", null);
+      return;
+    }
+    CPDFDocument document = readerView.getPDFDocument();
+    switch (call.method) {
+      case OPEN_DOCUMENT:
+        String filePath = call.argument("filePath");
+        String fileUri = call.argument("fileUri");
+        String openPwd = call.argument("password");
+        PDFDocumentError error;
+        if (!TextUtils.isEmpty(filePath)) {
+          error = document.open(filePath, openPwd);
+        } else {
+          error = document.open(Uri.parse(fileUri), openPwd);
+        }
+        if (error == PDFDocumentError.PDFDocumentErrorSuccess) {
+          readerView.setPDFDocument(document);
+        }
+        result.success(error.ordinal());
+        break;
+      case GET_FILE_NAME:
+        result.success(document.getFileName());
+        break;
+      case IS_ENCRYPTED:
+        result.success(document.isEncrypted());
+        break;
+      case IS_IMAGE_DOC:
+        CThreadPoolUtils.getInstance().executeIO(() -> {
+          boolean isImageDoc = document.isImageDoc();
+          result.success(isImageDoc);
+        });
+        break;
+      case GET_PERMISSIONS:
+        result.success(document.getPermissions().id);
+        break;
+      case CHECK_OWNER_UNLOCKED:
+        result.success(document.checkOwnerUnlocked());
+        break;
+      case CHECK_PASSWORD:
+        String password = call.argument("password");
+        boolean isOwnerPwd = call.argument("isOwnerPassword");
+        result.success(document.checkPassword(password, isOwnerPwd));
+      case CLOSE:
+        document.close();
+        result.success(true);
+        break;
+      case HAS_CHANGE:
+        result.success(document.hasChanges());
+        break;
+      case IMPORT_ANNOTATIONS:
+        try {
+          String xfdfFilePath = (String) call.arguments;
+          File file = new File(xfdfFilePath);
+          if (!file.exists()) {
+            result.success(false);
+            return;
+          }
+          File cacheFile = new File(context.getCacheDir(),
+              CFileUtils.CACHE_FOLDER + File.separator + "importAnnotCache/"
+                  + CFileUtils.getFileNameNoExtension(document.getFileName()));
+          cacheFile.mkdirs();
+          boolean importResult = document.importAnnotations(xfdfFilePath,
+              cacheFile.getAbsolutePath());
+          readerView.reloadPages();
+          result.success(importResult);
+        } catch (Exception e) {
+          e.printStackTrace();
+          result.success(false);
+        }
+        break;
+      case EXPORT_ANNOTATIONS:
+        try {
+          File dirFile = new File(context.getFilesDir(), "compdfkit/annotation/export/");
+          dirFile.mkdirs();
+          String fileName = CFileUtils.getFileNameNoExtension(document.getFileName());
+          File cacheFile = new File(context.getCacheDir(),
+              CFileUtils.CACHE_FOLDER + File.separator + "exportAnnotCache/" + fileName);
+          cacheFile.mkdirs();
+          File saveFile = new File(dirFile, fileName + ".xfdf");
+          saveFile = CFileUtils.renameNameSuffix(saveFile);
+          boolean exportResult = document.exportAnnotations(saveFile.getAbsolutePath(),
+              cacheFile.getAbsolutePath());
+          if (exportResult) {
+            result.success(saveFile.getAbsolutePath());
+          } else {
+            result.success("");
+          }
+        } catch (Exception e) {
+          e.printStackTrace();
+          result.success("");
+        }
+        break;
+      case REMOVE_ALL_ANNOTATIONS:
+        boolean deleteResult = document.removeAllAnnotations();
+        if (deleteResult) {
+          readerView.invalidateAllChildren();
+        }
+        result.success(deleteResult);
+        break;
+      case GET_PAGE_COUNT:
+        result.success(document.getPageCount());
+        break;
+      default:
+        break;
+    }
+  }
+}

+ 54 - 24
android/src/main/java/com/compdfkit/flutter/compdfkit_flutter/plugin/CPDFViewCtrlPlugin.java

@@ -11,9 +11,9 @@
 package com.compdfkit.flutter.compdfkit_flutter.plugin;
 
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.GET_CURRENT_PAGE_INDEX;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.GET_PAGE_SIZE;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.GET_READ_BACKGROUND_COLOR;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.GET_SCALE;
-import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.HAS_CHANGE;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.IS_CONTINUE_MODE;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.IS_COVER_PAGE_MODE;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.IS_CROP_MODE;
@@ -32,8 +32,9 @@ import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.Ch
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SET_FIXED_SCROLL;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SET_FORM_FIELD_HIGHLIGHT;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SET_LINK_HIGHLIGHT;
-import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SET_MARGIN;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SET_PAGE_SAME_WIDTH;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SET_MARGIN;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SET_PAGE_SPACING;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SET_READ_BACKGROUND_COLOR;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SET_SCALE;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SET_VERTICAL_MODE;
@@ -46,9 +47,10 @@ import android.util.Log;
 import androidx.annotation.NonNull;
 
 import com.compdfkit.core.document.CPDFDocument;
-import com.compdfkit.tools.common.pdf.CPDFDocumentFragment;
 
+import com.compdfkit.tools.common.pdf.CPDFDocumentFragment;
 import com.compdfkit.tools.common.utils.viewutils.CViewUtils;
+import com.compdfkit.tools.common.views.pdfview.CPDFIReaderViewCallback;
 import com.compdfkit.ui.reader.CPDFReaderView;
 import io.flutter.plugin.common.BinaryMessenger;
 import io.flutter.plugin.common.MethodCall;
@@ -63,13 +65,41 @@ public class CPDFViewCtrlPlugin extends BaseMethodChannelPlugin {
 
   private CPDFDocumentFragment documentFragment;
 
+  private CPDFDocumentPlugin documentPlugin;
+
   public CPDFViewCtrlPlugin(Context context, BinaryMessenger binaryMessenger, int viewId) {
     super(context, binaryMessenger);
     this.viewId = viewId;
+
+    // Register document plugin,get document info
+    documentPlugin = new CPDFDocumentPlugin(context, binaryMessenger, String.valueOf(viewId));
+    documentPlugin.register();
   }
 
   public void setDocumentFragment(CPDFDocumentFragment documentFragment) {
     this.documentFragment = documentFragment;
+    this.documentFragment.setInitListener((pdfView)->{
+      documentPlugin.setReaderView(pdfView.getCPdfReaderView());
+      pdfView.addReaderViewCallback(new CPDFIReaderViewCallback() {
+        @Override
+        public void onMoveToChild(int pageIndex) {
+          super.onMoveToChild(pageIndex);
+          io.flutter.Log.e("ComPDFKit", "onMoveToChild:" + pageIndex);
+          Map<String, Object> map = new HashMap<>();
+          map.put("pageIndex", pageIndex);
+          if (methodChannel != null) {
+            methodChannel.invokeMethod("onPageChanged", map);
+          }
+        }
+      });
+      pdfView.setSaveCallback((s, uri) -> {
+        if (methodChannel != null) {
+          methodChannel.invokeMethod("saveDocument", "");
+        }
+      }, e -> {
+
+      });
+    });
   }
 
   @Override
@@ -80,6 +110,7 @@ public class CPDFViewCtrlPlugin extends BaseMethodChannelPlugin {
   @Override
   public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
     Log.e(LOG_TAG, "CPDFViewCtrlFlutter:onMethodCall:" + call.method);
+
     if (documentFragment == null) {
       Log.e(LOG_TAG,
           "CPDFViewCtrlFlutter:onMethodCall: documentFragment is Null return not implemented.");
@@ -137,10 +168,14 @@ public class CPDFViewCtrlPlugin extends BaseMethodChannelPlugin {
         int right = call.argument("right");
         int bottom = call.argument("bottom");
         readerView.setFixReaderViewHorizontalMargin(true);
-        readerView.setReaderViewHorizontalMargin(left);
+        readerView.setReaderViewHorizontalMargin(left, right);
         readerView.setReaderViewTopMargin(top);
         readerView.setReaderViewBottomMargin(bottom);
-        readerView.setPageSpacing(top);
+        readerView.reloadPages();
+        break;
+      case SET_PAGE_SPACING:
+        int pageSpacing = (int) call.arguments;
+        readerView.setPageSpacing(pageSpacing);
         readerView.reloadPages();
         break;
       case SET_VERTICAL_MODE:
@@ -176,7 +211,6 @@ public class CPDFViewCtrlPlugin extends BaseMethodChannelPlugin {
         result.success(readerView.getPageNum());
         break;
       case SET_PAGE_SAME_WIDTH:
-        Log.e("ComPDFKit", "setPageSameWidth:" + call.arguments);
         readerView.setPageSameWidth((Boolean) call.arguments);
         readerView.reloadPages();
         break;
@@ -194,24 +228,20 @@ public class CPDFViewCtrlPlugin extends BaseMethodChannelPlugin {
       case SET_FIXED_SCROLL:
         readerView.setFixedScroll((Boolean) call.arguments);
         break;
-      case HAS_CHANGE:
-        CPDFDocument document = readerView.getPDFDocument();
-        result.success(document.hasChanges());
-        break;
-//      case GET_PAGE_SIZE:
-//        boolean noZoomPage = call.argument("noZoom");
-//        int page = call.argument("pageIndex");
-//        RectF rectF;
-//        if (noZoomPage){
-//          rectF = readerView.getPageNoZoomSize(page);
-//        }else {
-//          rectF = readerView.getPageSize(page);
-//        }
-//        Map<String, Float> pageSizeMap = new HashMap<>();
-//        pageSizeMap.put("width", rectF.width());
-//        pageSizeMap.put("height", rectF.height());
-//        result.success(pageSizeMap);
-//        break;
+      case GET_PAGE_SIZE:
+        boolean noZoomPage = call.argument("noZoom");
+        int page = call.argument("pageIndex");
+        RectF rectF;
+        if (noZoomPage){
+          rectF = readerView.getPageNoZoomSize(page);
+        }else {
+          rectF = readerView.getPageSize(page);
+        }
+        Map<String, Float> pageSizeMap = new HashMap<>();
+        pageSizeMap.put("width", rectF.width());
+        pageSizeMap.put("height", rectF.height());
+        result.success(pageSizeMap);
+        break;
       default:
         Log.e(LOG_TAG, "CPDFViewCtrlFlutter:onMethodCall:notImplemented");
         result.notImplemented();

+ 10 - 0
android/src/main/java/com/compdfkit/flutter/compdfkit_flutter/plugin/ComPDFKitSDKPlugin.java

@@ -13,6 +13,7 @@ import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.Ch
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.INIT_SDK;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.INIT_SDK_KEYS;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.OPEN_DOCUMENT;
+import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.REMOVE_SIGN_FILE_LIST;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SDK_BUILD_TAG;
 import static com.compdfkit.flutter.compdfkit_flutter.constants.CPDFConstants.ChannelMethod.SDK_VERSION_CODE;
 
@@ -23,11 +24,15 @@ import android.util.Log;
 import androidx.annotation.NonNull;
 
 import com.compdfkit.core.document.CPDFSdk;
+import com.compdfkit.core.utils.TFileUtils;
+import com.compdfkit.flutter.compdfkit_flutter.utils.FileUtils;
 import com.compdfkit.tools.common.pdf.CPDFConfigurationUtils;
 import com.compdfkit.tools.common.pdf.CPDFDocumentActivity;
 import com.compdfkit.tools.common.pdf.config.CPDFConfiguration;
+import com.compdfkit.tools.common.utils.CFileUtils;
 import com.compdfkit.tools.common.utils.CLog;
 
+import java.io.File;
 import java.util.Map;
 
 import io.flutter.plugin.common.BinaryMessenger;
@@ -83,6 +88,11 @@ public class ComPDFKitSDKPlugin extends BaseMethodChannelPlugin {
             case GET_TEMP_DIRECTORY:
                 result.success(context.getCacheDir().getPath());
                 break;
+            case REMOVE_SIGN_FILE_LIST:
+                File dirFile = new File(context.getFilesDir(), CFileUtils.SIGNATURE_FOLDER);
+                boolean deleteResult = FileUtils.deleteDirectory(dirFile.getAbsolutePath());
+                result.success(deleteResult);
+                break;
             default:
                 break;
         }

+ 89 - 0
android/src/main/java/com/compdfkit/flutter/compdfkit_flutter/utils/FileUtils.java

@@ -0,0 +1,89 @@
+/*
+ * Copyright © 2014-2024 PDF Technologies, Inc. All Rights Reserved.
+ *
+ * THIS SOURCE CODE AND ANY ACCOMPANYING DOCUMENTATION ARE PROTECTED BY INTERNATIONAL COPYRIGHT LAW
+ * AND MAY NOT BE RESOLD OR REDISTRIBUTED. USAGE IS BOUND TO THE ComPDFKit LICENSE AGREEMENT.
+ * UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
+ * This notice may not be removed from this file.
+ *
+ */
+
+package com.compdfkit.flutter.compdfkit_flutter.utils;
+
+import android.widget.Toast;
+import java.io.File;
+
+
+public class FileUtils {
+  /** 删除文件,可以是文件或文件夹
+   * @param delFile 要删除的文件夹或文件名
+   * @return 删除成功返回true,否则返回false
+   */
+  public static boolean delete(String delFile) {
+    File file = new File(delFile);
+    if (!file.exists()) {
+      return false;
+    } else {
+      if (file.isFile())
+        return deleteSingleFile(delFile);
+      else
+        return deleteDirectory(delFile);
+    }
+  }
+
+  /** 删除单个文件
+   * @param filePath$Name 要删除的文件的文件名
+   * @return 单个文件删除成功返回true,否则返回false
+   */
+  public static  boolean deleteSingleFile(String filePath$Name) {
+    File file = new File(filePath$Name);
+    // 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
+    if (file.exists() && file.isFile()) {
+      if (file.delete()) {
+        return true;
+      } else {
+        return false;
+      }
+    } else {
+      return false;
+    }
+  }
+
+  /** 删除目录及目录下的文件
+   * @param filePath 要删除的目录的文件路径
+   * @return 目录删除成功返回true,否则返回false
+   */
+  public static  boolean deleteDirectory(String filePath) {
+    // 如果dir不以文件分隔符结尾,自动添加文件分隔符
+    if (!filePath.endsWith(File.separator))
+      filePath = filePath + File.separator;
+    File dirFile = new File(filePath);
+    if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
+      return false;
+    }
+    boolean flag = true;
+    File[] files = dirFile.listFiles();
+    for (File file : files) {
+      if (file.isFile()) {
+        flag = deleteSingleFile(file.getAbsolutePath());
+        if (!flag)
+          break;
+      }
+      else if (file.isDirectory()) {
+        flag = deleteDirectory(file
+            .getAbsolutePath());
+        if (!flag)
+          break;
+      }
+    }
+    if (!flag) {
+      return false;
+    }
+    if (dirFile.delete()) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+}

+ 1 - 0
example/android/build.gradle

@@ -2,6 +2,7 @@ allprojects {
     repositories {
         google()
         mavenCentral()
+        mavenLocal()
     }
 }
 apply from: "config.gradle"

+ 1 - 1
example/android/config.gradle

@@ -3,6 +3,6 @@ ext {
             COMPILESDK: 33,
             MINSDK: 21,
             TARGETSDK: 33,
-            VERSIONCODE: 11
+            VERSIONCODE: 13
     ]
 }

+ 9 - 9
example/ios/Runner.xcodeproj/project.pbxproj

@@ -490,10 +490,10 @@
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
-				DEVELOPMENT_TEAM = 59AC9PMNH2;
+				DEVELOPMENT_TEAM = 4GGQPGRTSV;
 				ENABLE_BITCODE = NO;
-				FLUTTER_BUILD_NAME = 2.1.2;
-				FLUTTER_BUILD_NUMBER = 2.1.2;
+				FLUTTER_BUILD_NAME = 2.1.3;
+				FLUTTER_BUILD_NUMBER = 2.1.3;
 				INFOPLIST_FILE = Runner/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
 				LD_RUNPATH_SEARCH_PATHS = (
@@ -680,10 +680,10 @@
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
-				DEVELOPMENT_TEAM = 59AC9PMNH2;
+				DEVELOPMENT_TEAM = 4GGQPGRTSV;
 				ENABLE_BITCODE = NO;
-				FLUTTER_BUILD_NAME = 2.1.2;
-				FLUTTER_BUILD_NUMBER = 2.1.2;
+				FLUTTER_BUILD_NAME = 2.1.3;
+				FLUTTER_BUILD_NUMBER = 2.1.3;
 				INFOPLIST_FILE = Runner/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
 				LD_RUNPATH_SEARCH_PATHS = (
@@ -709,10 +709,10 @@
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
-				DEVELOPMENT_TEAM = 59AC9PMNH2;
+				DEVELOPMENT_TEAM = 4GGQPGRTSV;
 				ENABLE_BITCODE = NO;
-				FLUTTER_BUILD_NAME = 2.1.2;
-				FLUTTER_BUILD_NUMBER = 2.1.2;
+				FLUTTER_BUILD_NAME = 2.1.3;
+				FLUTTER_BUILD_NUMBER = 2.1.3;
 				INFOPLIST_FILE = Runner/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 12.0;
 				LD_RUNPATH_SEARCH_PATHS = (

+ 69 - 3
example/lib/cpdf_reader_widget_controller_example.dart

@@ -8,10 +8,14 @@
 import 'dart:io';
 import 'dart:math';
 
+import 'package:compdfkit_flutter/compdfkit.dart';
 import 'package:compdfkit_flutter/configuration/cpdf_configuration.dart';
 import 'package:compdfkit_flutter/configuration/cpdf_options.dart';
+import 'package:compdfkit_flutter/util/extension/cpdf_color_extension.dart';
 import 'package:compdfkit_flutter/widgets/cpdf_reader_widget.dart';
 import 'package:compdfkit_flutter/widgets/cpdf_reader_widget_controller.dart';
+import 'package:compdfkit_flutter_example/utils/file_util.dart';
+import 'package:file_picker/file_picker.dart';
 import 'package:flutter/material.dart';
 
 class CPDFReaderWidgetControllerExample extends StatefulWidget {
@@ -69,6 +73,12 @@ class _CPDFReaderWidgetControllerExampleState
               _controller = controller;
             });
           },
+          onPageChanged: (pageIndex){
+            debugPrint('pageIndex:${pageIndex}');
+          },
+          onSaveCallback: (){
+            debugPrint('CPDFDocument: save success');
+          },
         ));
   }
 
@@ -79,6 +89,9 @@ class _CPDFReaderWidgetControllerExampleState
 
   void handleClick(String value, CPDFReaderWidgetController controller) async {
     switch (value) {
+      case 'save':
+        await controller.save();
+        break;
       case 'setScale':
         controller.setScale(1.5);
         break;
@@ -109,7 +122,10 @@ class _CPDFReaderWidgetControllerExampleState
         final Random random = Random();
         int value = random.nextInt(50);
         debugPrint('ComPDFKit:setMargin:$value');
-        controller.setMargins(const CPDFEdgeInsets.symmetric(horizontal: 100, vertical: 10));
+        controller.setMargins(const CPDFEdgeInsets.only(left: 10, top:10, right: 10, bottom: 10));
+        break;
+      case "setPageSpacing":
+        await controller.setPageSpacing(20);
         break;
       case 'setContinueMode':
         bool isContinueMode = await controller.isContinueMode();
@@ -150,22 +166,66 @@ class _CPDFReaderWidgetControllerExampleState
         isFixedScroll = !isFixedScroll;
         await controller.setFixedScroll(isFixedScroll);
         break;
+      case 'setReadBackgroundColor':
+        var currentReadBackgroundColor = await controller.getReadBackgroundColor();
+        debugPrint('readBackgroundColor:${currentReadBackgroundColor.toHex()}');
+        await controller.setReadBackgroundColor(theme: CPDFThemes.light);
+        break;
       case 'isChanged':
         bool hasChange = await controller.hasChange();
         debugPrint('ComPDFKit:hasChange:$hasChange');
         break;
+      case "documentInfo":
+        var document = controller.document;
+        debugPrint('ComPDFKit:Document: fileName:${await document.getFileName()}');
+        debugPrint('ComPDFKit:Document: checkOwnerUnlocked:${await document.checkOwnerUnlocked()}');
+        debugPrint('ComPDFKit:Document: hasChange:${await document.hasChange()}');
+        debugPrint('ComPDFKit:Document: isEncrypted:${await document.isEncrypted()}');
+        debugPrint('ComPDFKit:Document: isImageDoc:${await document.isImageDoc()}');
+        debugPrint('ComPDFKit:Document: getPermissions:${await document.getPermissions()}');
+        debugPrint('ComPDFKit:Document: getPageCount:${await document.getPageCount()}');
+        break;
+      case "openDocument":
+        FilePickerResult? result = await FilePicker.platform.pickFiles(
+          type: FileType.custom,
+          allowedExtensions: ['pdf'],
+        );
+        if (result != null) {
+          var document = controller.document;
+          document.open(result.files.first.path!, "");
+        }
+        break;
+      case "importAnnotations":
+        File xfdfFile = await extractAsset(context, 'pdfs/test.xfdf');
+        bool result = await controller.document.importAnnotations(xfdfFile.path);
+        debugPrint('ComPDFKit:Document: importAnnotations:$result');
+        break;
+      case "exportAnnotations":
+        String xfdfPath = await controller.document.exportAnnotations();
+        debugPrint('ComPDFKit:Document: exportAnnotations:$xfdfPath');
+        break;
+      case "removeAllAnnotations":
+        await controller.document.removeAllAnnotations();
+        break;
+      case "removeSignFileList":
+        bool result = await ComPDFKit.removeSignFileList();
+        debugPrint('ComPDFKit:removeSignFileList:${result}');
+        break;
     }
   }
 }
 
 var actions = [
+  'save',
   'setScale',
   'getScale',
   if(Platform.isAndroid) ...[
     'setCanScale',
     'pageSameWidth',
     'isPageInScreen',
-    'setFixedScroll'
+    'setFixedScroll',
+    'setReadBackgroundColor',
+    'setPageSpacing'
   ],
   'setFormHighlight',
   'setLinkHighlight',
@@ -177,7 +237,13 @@ var actions = [
   'setDisplayPageIndex',
   'getCurrentPageIndex',
   'setCoverPageMode',
-  'isChanged'
+  'isChanged',
+  'documentInfo',
+  'openDocument',
+  'importAnnotations',
+  'exportAnnotations',
+  'removeAllAnnotations',
+  'removeSignFileList'
 ];
 
 Color randomColor() {

+ 1 - 1
example/pubspec.lock

@@ -55,7 +55,7 @@ packages:
       path: ".."
       relative: true
     source: path
-    version: "2.1.3"
+    version: "2.2.0"
   cross_file:
     dependency: transitive
     description:

+ 1 - 1
example/pubspec.yaml

@@ -1,6 +1,6 @@
 name: compdfkit_flutter_example
 description: Demonstrates how to use the compdfkit_flutter plugin.
-version: 2.1.3
+version: 2.2.0
 homepage: https://www.compdf.com
 repository: https://github.com/ComPDFKit/compdfkit-pdf-sdk-flutter
 issue_tracker: https://www.compdf.com/support

+ 7 - 1
ios/Classes/CompdfkitFlutterPlugin.swift

@@ -4,11 +4,17 @@ import ComPDFKit
 import ComPDFKit_Tools
 
 public class CompdfkitFlutterPlugin: NSObject, FlutterPlugin, CPDFViewBaseControllerDelete {
+
+    public var messager : FlutterBinaryMessenger?
+
+
     public static func register(with registrar: FlutterPluginRegistrar) {
         let channel = FlutterMethodChannel(name: "com.compdfkit.flutter.plugin", binaryMessenger: registrar.messenger())
+
         let instance = CompdfkitFlutterPlugin()
+        instance.messager = registrar.messenger()
         registrar.addMethodCallDelegate(instance, channel: channel)
-        
+
         let factory = CPDFViewCtrlFactory(messenger: registrar.messenger())
         registrar.register(factory, withId: "com.compdfkit.flutter.ui.pdfviewer")
     }

+ 115 - 0
ios/Classes/reader/CPDFDocumentPlugin.swift

@@ -0,0 +1,115 @@
+//
+//  CPDFDocumentPlugin.swift
+//  compdfkit_flutter
+//
+//  Created by Xiaolong Liu on 2024/7/19.
+//
+
+import Foundation
+import ComPDFKit
+import Flutter
+import ComPDFKit_Tools
+
+public class CPDFDocumentPlugin {
+    
+    private var document : CPDFDocument?
+    
+    private var _methodChannel : FlutterMethodChannel
+    
+    private var pdfViewController : CPDFViewController?
+    
+    
+    init(uid : String, binaryMessager : FlutterBinaryMessenger) {
+        _methodChannel = FlutterMethodChannel(name: "com.compdfkit.flutter.document_\(uid)", binaryMessenger: binaryMessager)
+        registeryMethodChannel()
+    }
+    
+    init(pdfViewController : CPDFViewController, uid : String, binaryMessager : FlutterBinaryMessenger){
+        self.pdfViewController = pdfViewController
+        _methodChannel = FlutterMethodChannel(name: "com.compdfkit.flutter.document_\(uid)", binaryMessenger: binaryMessager)
+        registeryMethodChannel()
+    }
+    
+    
+    private func registeryMethodChannel(){
+
+        _methodChannel.setMethodCallHandler({
+            (call: FlutterMethodCall, result: FlutterResult) -> Void in
+            print("ComPDFKit-Flutter: iOS-MethodChannel: CPDFDocumentPlugin [method:\(call.method)]")
+            if(self.document == nil && self.pdfViewController != nil){
+                guard let pdfListView = self.pdfViewController?.pdfListView else {
+                    print("pdfViewController error")
+                    return
+                }
+                self.document = pdfListView.document
+            }
+            switch call.method {
+            case "open_document":
+                // TODO: 这里要再打开文档
+                let initInfo = call.arguments as? [String: Any]
+                let path = initInfo?["filePath"] as? String ?? ""
+                let password = initInfo?["password"] ?? ""
+                
+                self.document = CPDFDocument(url: URL(fileURLWithPath: path))
+                if(self.document?.isLocked == true){
+                    self.document?.unlock(withPassword: password as? String ?? "")
+                }
+                result(2)
+            case "get_file_name":
+                
+                if(self.document == nil){
+                    print("self.document is nil")
+                    result("is nil")
+                    return
+                }
+                // TODO: 这里返回文档名称
+                result("文档名称")
+            case "is_encrypted":
+                // TODO: 返回文档是否加密了,true:加密, false:未加密
+                result(false)
+            case "is_image_doc":
+                // TODO: 是否为图片文档, true:是图片文档, false:非图片文档
+                result(false)
+            case "get_permissions":
+                // TODO: 返回文档当前的权限,返回int类型。none:0, user:1, owner:2
+                result(0)
+            case "check_owner_unlocked":
+                // TODO: 检查所有者权限是否已经解锁. 已解锁:true, 未解锁:false
+                result(false)
+            case "check_password":
+                // TODO: 检查密码是否正确
+                let info = call.arguments as? [String: Any]
+                // flutter 层传过来的密码
+                let password = initInfo?["password"] as? String ?? ""
+                // 是否是权限密码
+                let isOwnerPassword = initInfo?["isOwnerPassword"] as Bool ?? false
+                // 返回密码是否正确
+                result(true)
+            case "close":
+                // TODO: 关闭文档,释放资源
+                result(true)
+            case "has_change":
+                // TODO: 返回文档是否有修改:true:有修改, false:未修改
+                result(false)
+            case "import_annotations":
+                // TODO: 导入注释
+                // 返回值:导入成功:true, 导入失败:false
+                result(true)
+            case "export_annotations":
+                // TODO: 导出注释
+                // 返回值:导出成功:导出的xfdf文件路径, 导出失败:空字符串
+                result("")
+            case "remove_all_annotations":
+                // TODO: 删除所有注释
+                // 返回值:删除成功:true, 删除失败:false
+                result(true)
+            case "get_page_count":
+                // TODO: 返回当前文档总页数
+                result(1)
+            default:
+                result(FlutterMethodNotImplemented)
+            }
+        });
+        
+    }
+}

+ 1 - 5
ios/Classes/reader/CPDFViewCtrlFactory.swift

@@ -82,17 +82,13 @@ class CPDFViewCtrlFlutter: NSObject, FlutterPlatformView, CPDFViewBaseController
         navigationController.view.frame = frame
         
         var plugin = CPDFViewCtrlPlugin(viewId: viewId, binaryMessenger: messenger!, controller: pdfViewController)
-        
+
         super.init()
         
         // Proxy set, but not used
         pdfViewController.delegate = self
         
         navigationController.setViewControllers([pdfViewController], animated: true)
-
-        
-
-        
     }
 
     func view() -> UIView {

+ 30 - 8
ios/Classes/reader/CPDFViewCtrlPlugin.swift

@@ -22,11 +22,19 @@ class CPDFViewCtrlPlugin {
     init(viewId: Int64, binaryMessenger messenger: FlutterBinaryMessenger, controller : CPDFViewController) {
         self.pdfViewController = controller
         _methodChannel = FlutterMethodChannel.init(name: "com.compdfkit.flutter.ui.pdfviewer.\(viewId)", binaryMessenger: messenger)
-        registeryMethodChannel(viewId: viewId, binaryMessenger: messenger)
+        registeryMethodChannel()
+
+        var documentPlugin = CPDFDocumentPlugin(pdfViewController: pdfViewController, uid: String(describing: viewId), binaryMessager: messenger)
+
+        // TODO: 返回当前滑动到的页码
+        _methodChannel.invokeMethod("onPageChanged", arguments: 1)
+        
+        // TODO: 监听到执行了保存的回调
+        _methodChannel.invokeMethod("saveDocument", arguments: nil)
     }
     
     
-    private func registeryMethodChannel(viewId: Int64, binaryMessenger messenger: FlutterBinaryMessenger){
+    private func registeryMethodChannel(){
 
         _methodChannel.setMethodCallHandler({
             (call: FlutterMethodCall, result: FlutterResult) -> Void in
@@ -66,6 +74,26 @@ class CPDFViewCtrlPlugin {
                     return
                 }
                 result(pdfListView.scaleFactor)
+            case "set_read_background_color":
+                guard let pdfListView = self.pdfViewController.pdfListView else {
+                    return
+                }
+                // TODO: 需要设置阅读的背景颜色
+                // hex color, for example: '#FFFFFF'
+                // 需要设置给PDFListView
+                let bgColor = call.arguments as! String
+                let color = ColorHelper.colorWithHexString(hex: bgColor)
+                print("bgColor:\(bgColor), color:\(color.description)")
+//                pdfListView.displayModeCustomColor = CPDFDisplayModeCustom()
+//                pdfListView.layoutDocumentView()
+            case "get_read_background_color":
+                guard let pdfListView = self.pdfViewController.pdfListView else {
+                    result("#FFFFFF")
+                    return
+                }
+                // TODO: 返回当前阅读的背景颜色
+                // 需要返回Hex 颜色给Flutter, 例如:'#FFFFFF'
+//                result(pdfListView.displayModeCustomColor.toHexString())
             case "set_form_field_highlight":
                 guard let pdfListView = self.pdfViewController.pdfListView else {
                     return
@@ -178,12 +206,6 @@ class CPDFViewCtrlPlugin {
                     return
                 }
                 result(pdfListView.currentPageIndex)
-            case "has_change":
-                guard let pdfListView = self.pdfViewController.pdfListView else {
-                    result(false)
-                    return
-                }
-                result(pdfListView.document.isModified())
             default:
                 result(FlutterMethodNotImplemented)
             }

+ 4 - 0
lib/compdfkit.dart

@@ -88,4 +88,8 @@ class ComPDFKit {
     }
     return Directory(path);
   }
+
+  static Future<bool> removeSignFileList() async {
+    return await _methodChannel.invokeMethod('remove_sign_file_list');
+  }
 }

+ 14 - 4
lib/configuration/cpdf_configuration.dart

@@ -7,6 +7,7 @@
 
 
 import 'dart:convert';
+import 'dart:ffi';
 
 import 'package:compdfkit_flutter/configuration/attributes/cpdf_annot_attr.dart';
 
@@ -94,6 +95,7 @@ class CPDFModeConfig {
 
 /// Configuration for top toolbar functionality.
 class CPDFToolbarConfig {
+
   /// Top toolbar actions for Android platform
   ///
   /// Default: thumbnail, search, bota, menu.
@@ -114,6 +116,8 @@ class CPDFToolbarConfig {
   /// Configure the menu options opened in the top toolbar [CPDFToolbarAction.menu]
   final List<CPDFToolbarMenuAction> availableMenus;
 
+  final bool mainToolbarVisible;
+
   const CPDFToolbarConfig(
       {this.androidAvailableActions = const [
         CPDFToolbarAction.thumbnail,
@@ -141,7 +145,8 @@ class CPDFToolbarConfig {
         CPDFToolbarMenuAction.share,
         CPDFToolbarMenuAction.openDocument,
         CPDFToolbarMenuAction.snip
-      ]});
+      ],
+      this.mainToolbarVisible = true});
 
   Map<String, dynamic> toJson() => {
         'androidAvailableActions':
@@ -150,7 +155,8 @@ class CPDFToolbarConfig {
             iosLeftBarAvailableActions.map((e) => e.name).toList(),
         'iosRightBarAvailableActions':
             iosRightBarAvailableActions.map((e) => e.name).toList(),
-        'availableMenus': availableMenus.map((e) => e.name).toList()
+        'availableMenus': availableMenus.map((e) => e.name).toList(),
+        'mainToolbarVisible' : mainToolbarVisible
       };
 }
 
@@ -202,6 +208,8 @@ class CPDFReaderViewConfig {
   /// only android platform
   final bool pageSameWidth;
 
+  final List<int> margins;
+
   const CPDFReaderViewConfig(
       {this.linkHighlight = true,
       this.formFieldHighlight = true,
@@ -214,7 +222,8 @@ class CPDFReaderViewConfig {
       this.enablePageIndicator = true,
       this.pageSpacing = 10,
       this.pageScale = 1.0,
-      this.pageSameWidth = true});
+      this.pageSameWidth = true,
+      this.margins = const [0,0,0,0]});
 
   Map<String, dynamic> toJson() => {
         'linkHighlight': linkHighlight,
@@ -228,7 +237,8 @@ class CPDFReaderViewConfig {
         'enablePageIndicator': enablePageIndicator,
         'pageSpacing': pageSpacing,
         'pageScale': pageScale,
-        'pageSameWidth': pageSameWidth
+        'pageSameWidth': pageSameWidth,
+        'margins' : margins
       };
 }
 

+ 66 - 11
lib/configuration/cpdf_options.dart

@@ -6,6 +6,10 @@
 // This notice may not be removed from this file.
 
 
+import 'dart:ui';
+
+import 'package:compdfkit_flutter/util/extension/cpdf_color_extension.dart';
+
 enum CPDFViewMode { viewer, annotations, contentEditor, forms, signatures }
 
 /// The [CPDFToolbarAction.back] button will only be displayed on the leftmost side of the top toolbar on the Android platform
@@ -32,16 +36,26 @@ enum CPDFDisplayMode { singlePage, doublePage, coverPage }
 /// readerView background themes
 enum CPDFThemes {
   /// Bright mode, readerview background is white
-  light,
+  light('#FFFFFF'),
 
   /// dark mode, readerview background is black
-  dark,
+  dark('#000000'),
 
   /// brown paper color
-  sepia,
+  sepia('#FFEFBE'),
 
   /// Light green, eye protection mode
-  reseda
+  reseda('#CDE6D0');
+
+  final String color;
+
+  const CPDFThemes(this.color);
+
+  // 获取颜色值
+  String getColor() {
+    return color;
+  }
+
 }
 
 enum CPDFAnnotationType {
@@ -121,16 +135,15 @@ enum CPDFCheckStyle { check, circle, cross, diamond, square, star }
 
 enum CPDFThemeMode { light, dark, system }
 
-/// The [CPDFEdgeInsets] is used to set the padding of the PDF document.
+/// [CPDFEdgeInsets] defines the padding for a PDF document.
 ///
-/// [Android] can only set horizontal margins, [top] and [bottom] margins.
-/// Horizontal spacing cannot be set independently.
-/// The horizontal spacing value is set using the [left] attribute,
-/// the spacing between two pages is the same as the top spacing.
+/// - On **Android**, you can set individual margins for [top], [bottom], [left], and [right].
+///   To adjust the spacing between pages, use the `setPageSpacing()` method.
 ///
-/// The [iOS] platform can set the [top], [bottom], [left] and [right] margins,
-/// and the spacing between two pages is the same as the top spacing.
+/// - On **iOS**, you can also configure [top], [bottom], [left], and [right] margins.
+///   The spacing between pages is equal to the [top] margin.
 class CPDFEdgeInsets {
+
   final int left;
 
   final int top;
@@ -164,4 +177,46 @@ class CPDFEdgeInsets {
         'right': right,
         'bottom': bottom,
       };
+}
+
+
+enum CPDFDocumentPermissions {
+
+  none,
+
+  user,
+
+  owner
+
+}
+
+/// Error types of the opening document.
+enum CPDFDocumentError {
+  /// No read permission.
+  noReadPermission,
+
+  /// SDK No verified license
+  notVerifyLicense,
+
+  /// open document success.
+  success,
+
+  /// Unknown error
+  unknown,
+
+  /// File not found or could not be opened.
+  errorFile,
+
+  /// File not in PDF format or corrupted.
+  errorFormat,
+
+  /// Password required or incorrect password.
+  errorPassword,
+
+  /// Unsupported security scheme.
+  errorSecurity,
+
+  /// Error page.
+  errorPage
+
 }

+ 159 - 8
lib/document/cpdf_document.dart

@@ -5,7 +5,9 @@
 // UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS SUBJECT TO CIVIL AND CRIMINAL PENALTIES.
 // This notice may not be removed from this file.
 
-
+import 'package:compdfkit_flutter/configuration/cpdf_options.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
 
 /// A class to handle PDF documents without using [CPDFReaderWidget]
 ///
@@ -21,12 +23,161 @@
 /// var fileName = await document.getFileName();
 /// ```
 class CPDFDocument {
-  // late MethodChannel _channel;
-  //
-  // bool _isValid = false;
-  //
-  // CPDFDocument.withController(int viewId)
-  //     : _channel = MethodChannel('com.compdfkit.flutter.document_$viewId'),
-  //       _isValid = true;
+  late MethodChannel _channel;
+
+  bool _isValid = false;
+
+  get isValid => _isValid;
+
+  CPDFDocument.withController(int viewId)
+      : _channel = MethodChannel('com.compdfkit.flutter.document_$viewId'),
+        _isValid = true;
+
+  Future<CPDFDocumentError> open(String filePath, String password) async {
+    var errorCode = await _channel.invokeMethod(
+        'open_document', {'filePath': filePath, 'password': password});
+    var error = CPDFDocumentError.values[errorCode];
+    _isValid = error == CPDFDocumentError.success;
+    return error;
+  }
+
+  /// Gets the file name of the PDF document.
+  ///
+  /// example:
+  /// ```dart
+  /// var fileName = await document.getFileName();
+  /// ```
+  Future<String> getFileName() async {
+    return await _channel.invokeMethod('get_file_name');
+  }
+
+  /// Checks if the PDF document is encrypted.
+  ///
+  /// example:
+  /// ```dart
+  /// var isEncrypted = await document.isEncrypted();
+  /// ```
+  Future<bool> isEncrypted() async {
+    return await _channel.invokeMethod('is_encrypted');
+  }
+
+  /// Checks if the PDF document is an image document.
+  /// This is a time-consuming operation that depends on the document size.
+  ///
+  /// example:
+  /// ```dart
+  /// var isImageDoc = await document.isImageDoc();
+  /// ```
+  Future<bool> isImageDoc() async {
+    return await _channel.invokeMethod('is_image_doc');
+  }
+
+  /// Gets the current document's permissions. There are three types of permissions:
+  /// No restrictions: [CPDFDocumentPermissions.none]
+  /// If the document has an open password and an owner password,
+  /// using the open password will grant [CPDFDocumentPermissions.user] permissions,
+  /// and using the owner password will grant [CPDFDocumentPermissions.owner] permissions.
+  ///
+  /// example:
+  /// ```dart
+  /// var permissions = await document.getPermissions();
+  /// ```
+  Future<CPDFDocumentPermissions> getPermissions() async {
+    int permissionId = await _channel.invokeMethod('get_permissions');
+    return CPDFDocumentPermissions.values[permissionId];
+  }
+
+  /// Check if owner permissions are unlocked
+  ///
+  /// example:
+  /// ```dart
+  /// var isUnlocked = await document.checkOwnerUnlocked();
+  /// ```
+  Future<bool> checkOwnerUnlocked() async {
+    return await _channel.invokeMethod('check_owner_unlocked');
+  }
+
+  /// Whether the password is correct.
+  ///
+  /// example:
+  /// ```dart
+  /// var isCorrect = await document.checkPassword('password', isOwnerPassword: true);
+  /// ```
+  Future<bool> checkPassword(String password,
+      {bool isOwnerPassword = false}) async {
+    return await _channel.invokeMethod('check_password',
+        {'password': password, 'isOwnerPassword': isOwnerPassword});
+  }
+
+  /// Check the document for modifications
+  ///
+  /// example:
+  /// ```dart
+  /// bool hasChange = await document.hasChange();
+  /// ```
+  Future<bool> hasChange() async {
+    return await _channel.invokeMethod('has_change');
+  }
+
+  /// After completing the operation of the document,
+  /// please close the document at the appropriate location to release resources.
+  Future<void> close() async {
+    if (!_isValid) return;
+    await _channel.invokeMethod('close');
+    debugPrint('ComPDFKit:CPDFDocument.close');
+    _isValid = false;
+  }
+
+  /// Imports annotations from the specified XFDF file into the current PDF document.
+  ///
+  /// **Parameters:**<br/>
+  ///   xfdfFile - Path of the XFDF file to be imported.
+  ///
+  /// **example:**
+  /// ```dart
+  /// bool result = await document.importAnnotations(xxx.xfdf);
+  /// ```
+  ///
+  /// **Returns:**
+  ///   true if the import is successful; otherwise, false.
+  Future<bool> importAnnotations(String xfdfFile) async {
+    return await _channel.invokeMethod('import_annotations', xfdfFile);
+  }
+
+  /// Exports annotations from the current PDF document to an XFDF file.
+  ///
+  /// **example:**
+  /// ```dart
+  /// String xfdfPath = await document.exportAnnotations();
+  /// ```
+  ///
+  /// Returns:
+  ///   The path of the XFDF file if export is successful; an empty string if the export fails.
+  Future<String> exportAnnotations() async {
+    return await _channel.invokeMethod('export_annotations');
+  }
+
+
+  /// Delete all comments in the current document
+  ///
+  /// example:
+  /// ```dart
+  /// bool result = await document.removeAllAnnotations();
+  /// ```
+  Future<bool> removeAllAnnotations() async {
+    return await _channel.invokeMethod('remove_all_annotations');
+  }
+
+  /// Get the total number of pages in the current document
+  ///
+  /// example:
+  /// ```dart
+  /// int pageCount = await document.getPageCount();
+  /// ```
+  Future<int> getPageCount()  async {
+    return await _channel.invokeMethod('get_page_count');
+  }
+
+  // Future<void> getInfo() async {}
 
 }

+ 13 - 2
lib/widgets/cpdf_reader_widget.dart

@@ -19,6 +19,11 @@ import 'package:flutter/services.dart';
 typedef CPDFReaderWidgetCreatedCallback = void Function(
     CPDFReaderWidgetController controller);
 
+typedef CPDFPageChangedCallback = void Function(int pageIndex);
+
+typedef CPDFDocumentSaveCallback = void Function();
+
+
 class CPDFReaderWidget extends StatefulWidget {
   /// pdf file path
   final String document;
@@ -30,13 +35,19 @@ class CPDFReaderWidget extends StatefulWidget {
 
   final CPDFReaderWidgetCreatedCallback onCreated;
 
+  final CPDFPageChangedCallback? onPageChanged;
+
+  final CPDFDocumentSaveCallback? onSaveCallback;
+
   /// init callback
   const CPDFReaderWidget(
       {Key? key,
       required this.document,
       this.password = '',
       required this.configuration,
-      required this.onCreated})
+      required this.onCreated,
+      this.onPageChanged,
+      this.onSaveCallback})
       : super(key: key);
 
   @override
@@ -94,6 +105,6 @@ class _CPDFReaderWidgetState extends State<CPDFReaderWidget> {
 
   Future<void> _onPlatformViewCreated(int id) async {
     debugPrint('ComPDFKit-Flutter: CPDFReaderWidget created');
-    widget.onCreated(CPDFReaderWidgetController(id));
+    widget.onCreated(CPDFReaderWidgetController(id, onPageChanged: widget.onPageChanged, saveCallback : widget.onSaveCallback));
   }
 }

+ 50 - 13
lib/widgets/cpdf_reader_widget_controller.dart

@@ -9,6 +9,9 @@ import 'dart:io';
 import 'package:flutter/services.dart';
 
 import '../configuration/cpdf_options.dart';
+import '../document/cpdf_document.dart';
+import '../util/extension/cpdf_color_extension.dart';
+import 'cpdf_reader_widget.dart';
 
 /// PDF Reader Widget Controller
 ///
@@ -28,17 +31,30 @@ import '../configuration/cpdf_options.dart';
 ///         ));
 /// ```
 class CPDFReaderWidgetController {
+
   late MethodChannel _channel;
 
-  // late CPDFDocument _document;
+  late CPDFDocument _document;
 
-  CPDFReaderWidgetController(int id) {
+  CPDFReaderWidgetController(int id, {
+    CPDFPageChangedCallback? onPageChanged,
+    CPDFDocumentSaveCallback? saveCallback}) {
     _channel = MethodChannel('com.compdfkit.flutter.ui.pdfviewer.$id');
-    _channel.setMethodCallHandler((call) async {});
-    // _document = CPDFDocument.withController(id);
+    _channel.setMethodCallHandler((call) async {
+      switch (call.method) {
+        case 'onPageChanged':
+          var pageIndex = call.arguments['pageIndex'];
+          onPageChanged?.call(pageIndex);
+          break;
+        case 'saveDocument':
+          saveCallback?.call();
+          break;
+      }
+    });
+    _document = CPDFDocument.withController(id);
   }
 
-  // CPDFDocument get document => _document;
+  CPDFDocument get document => _document;
 
   /// Save document
   /// Return value: **true** if the save is successful,
@@ -87,9 +103,18 @@ class CPDFReaderWidgetController {
   /// ```dart
   /// await _controller.setReadBackgroundColor(Colors.white);
   /// ```
-  // Future<void> setReadBackgroundColor(Color color) async {
-  //   await _channel.invokeMethod('set_read_background_color', color.toHex());
-  // }
+  Future<void> setReadBackgroundColor({CPDFThemes? theme, Color? customColor}) async {
+    String colorToUse;
+    if (theme != null) {
+      colorToUse = theme.getColor();
+    } else if (customColor != null) {
+      colorToUse = customColor.toHex();
+    } else {
+      throw ArgumentError('Either theme or customColor must be provided.');
+    }
+    await _channel.invokeMethod('set_read_background_color', colorToUse);
+  }
+
 
   /// Get background color of reader.
   ///
@@ -97,10 +122,10 @@ class CPDFReaderWidgetController {
   /// ```dart
   /// Color color = await _controller.getReadBackgroundColor();
   /// ```
-  // Future<Color> getReadBackgroundColor() async {
-  //   String hexColor = await _channel.invokeMethod('get_read_background_color');
-  //   return HexColor.fromHex(hexColor);
-  // }
+  Future<Color> getReadBackgroundColor() async {
+    String hexColor = await _channel.invokeMethod('get_read_background_color');
+    return HexColor.fromHex(hexColor);
+  }
 
   /// Sets whether to display highlight Form Field.
   /// [isFormFieldHighlight] : true to display highlight Form Field.
@@ -180,6 +205,17 @@ class CPDFReaderWidgetController {
     await _channel.invokeMethod('set_margin' , edgeInsets.toJson());
   }
 
+  /// Sets the spacing between pages. This method is supported only on the [Android] platform.
+  ///
+  /// - For the [iOS] platform, use the [setMargins] method instead.
+  ///   The spacing between pages is equal to the value of [CPDFEdgeInsets.top].
+  ///
+  /// Parameters:
+  /// [spacing] The space between pages, in pixels.
+  Future<void> setPageSpacing(int spacing) async {
+    await _channel.invokeMethod('set_page_spacing', spacing);
+  }
+
   /// Sets whether it is continuous scroll mode.
   ///
   /// [isContinueMode] Whether it is continuous scroll mode.
@@ -330,7 +366,8 @@ class CPDFReaderWidgetController {
   /// ```dart
   /// bool hasChange = await document.hasChange();
   /// ```
+  @Deprecated("use CPDFDocument().hasChange()")
   Future<bool> hasChange() async {
-    return await _channel.invokeMethod('has_change');
+    return await _document.hasChange();
   }
 }

+ 1 - 1
pubspec.yaml

@@ -1,6 +1,6 @@
 name: compdfkit_flutter
 description: ComPDFKit for Flutter is a comprehensive SDK that allows you to quickly add PDF functionality to Android and iOS Flutter applications.
-version: 2.1.3
+version: 2.2.0
 homepage: https://www.compdf.com
 repository: https://github.com/ComPDFKit/compdfkit-pdf-sdk-flutter
 issue_tracker: https://www.compdf.com/support