Browse Source

ComPDFKit(flutter) - 2.2.0 iOS 端接入

yangliuhua 3 months ago
parent
commit
ff87719712

+ 2 - 2
example/ios/Podfile

@@ -31,8 +31,8 @@ target 'Runner' do
   use_frameworks!
   use_modular_headers!
 
-  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.1.3.podspec'
+  pod "ComPDFKit", podspec:'https://www.compdf.com/download/ios/cocoapods/xcframeworks/compdfkit/2.2.0.podspec'
+  pod "ComPDFKit_Tools", podspec:'https://www.compdf.com/download/ios/cocoapods/xcframeworks/compdfkit_tools/2.2.0.podspec'
   flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
   target 'RunnerTests' do
     inherit! :search_paths

+ 7 - 0
example/ios/Runner/Info.plist

@@ -59,6 +59,13 @@
 	<string>Your consent is required before you could access the function.</string>
 	<key>UIApplicationSupportsIndirectInputEvents</key>
 	<true/>
+	<key>UISupportsDocumentBrowser</key>
+	<true/>
+    <key>UIBackgroundModes</key>
+    <array>
+       <string>fetch</string>
+       <string>remote-notification</string>
+    </array>
 	<key>UILaunchStoryboardName</key>
 	<string>LaunchScreen</string>
 	<key>UIMainStoryboardFile</key>

+ 20 - 0
example/ios/Runner/en.lproj/Localizable.strings

@@ -36,6 +36,7 @@
 "Technical Support" = "Technical Support";
 "support@compdf.com" = "support@compdf.com";
 "Technical Supports" = "Technical Support";
+"Mail account is not set up!" = "Mail account is not set up!";
 "© 2014-2024 PDF Technologies, Inc. All Rights Reserved." = "© 2014-2024 PDF Technologies, Inc. All Rights Reserved.";
 "Privacy Policy" = "Privacy Policy";
 "Service Terms" = "Service Terms";
@@ -49,6 +50,7 @@
 "Save as Flattened PDF" = "Save as Flattened PDF";
 "_Flattened" = "_Flattened";
 "Sorry PDF Reader Can't open this pdf file!" = "Sorry PDF Reader Can't open this pdf file!";
+"The current page is scanned images that do not support adding highlights, underlines, strikeouts, and squiggly lines." = "The current page is scanned images that do not support adding highlights, underlines, strikeouts, and squiggly lines.";
 
 "Sorry PDF Reader Can't open this pdf file!" = "Sorry PDF Reader Can't open this pdf file!";
 "Your consent is required before you could access the function." = "Your consent is required before you could access the function.";
@@ -114,6 +116,7 @@
 "Ignore Case" = "Ignore Case";
 "Whole Words only" = "Whole Words only";
 "Effective immediately after setting" = "Effective immediately after setting";
+"Please enter the password" = "Please enter the password";
 
 "View Setting" = "View Setting";
 "Document Info" = "Document Info";
@@ -129,6 +132,7 @@
 "Split View" = "Split View";
 "Vertical Scrolling" = "Vertical";
 "Horizontal Scrolling" = "Horizontal";
+"Vertical Scrolling Paging" = "Page Break";
 "Themes" = "Themes";
 "Light" = "Light";
 "Dark" = "Dark";
@@ -231,6 +235,7 @@
 "Stroke Color" = "Stroke Color";
 "Fill Color" = "Fill Color";
 "Line and Border Style" = "Line and Border Style";
+"Dash Spacing" = "Dash Spacing";
 "Start" = "Start";
 "End" = "End";
 "Arrow Style" = "Arrow Style";
@@ -289,6 +294,8 @@
 "Paste and Match Style" = "Paste and Match Style";
 "Crop" = "Crop";
 "Export Successfully!" = "Export Successfully!";
+"Styles" = "Style";
+"Select All" = "Select All";
 
 "Text Field" = "Text Field";
 "Check Box" = "Check Box";
@@ -547,3 +554,16 @@
 "Marked" = "Marked";
 "Reply" = "Reply";
 "View Reply" = "View Reply";
+
+"Compress" = "Compress";
+"Selected File" = "Selected File";
+"Change" = "Change";
+"Compress Quality" = "Compress Quality";
+"Low Quality" = "Low Quality";
+"Standard Quality" = "Standard Quality";
+"High Quality" = "High Quality";
+"Custom" = "Custom";
+"Saving Path" = "Saving Path";
+"Compressing" = "Compressing";
+"Incorrect password, please try again." = "Incorrect password, please try again.";
+"Compressed successfully!" = "Compressed successfully!";

+ 20 - 0
example/ios/Runner/zh-Hans.lproj/Localizable.strings

@@ -33,6 +33,7 @@
 "Technical Support" = "技术支持";
 "support@compdf.com" = "support@compdf.com";
 "Technical Supports" = "ComPDFKit技术支持请求";
+"Mail account is not set up!" = "尚未设置Email邮箱";
 "© 2014-2024 PDF Technologies, Inc. All Rights Reserved." = "© 2014-2024 PDF Technologies, Inc. All Rights Reserved.";
 "Privacy Policy" = "隐私协议";
 "Service Terms" = "服务条款";
@@ -46,6 +47,7 @@
 "Save as Flattened PDF" = "另存为扁平化副本";
 "_Flattened" = "_扁平化文档";
 "Sorry PDF Reader Can't open this pdf file!" = "对不起,PDF阅读器无法打开此PDF文件!";
+"The current page is scanned images that do not support adding highlights, underlines, strikeouts, and squiggly lines." = "当前页面为图像。不支持添加高光、下划线、删除线和波浪线等注释。";
 
 "Your consent is required before you could access the function." = "在您访问该功能之前需要您的同意。";
 
@@ -96,6 +98,7 @@
 "This PDF has password protect." = "这个PDF有密码保护。";
 "Please input the password below:" = "请在下方输入密码:";
 "The password is invalid !" = "密码无效!";
+"Please enter the password" = "请输入文档密码";
 
 "Viewer" = "查看器";
 "Annotations" = "注释";
@@ -127,6 +130,7 @@
 "Split View" = "分屏视图";
 "Vertical Scrolling" = "垂直";
 "Horizontal Scrolling" = "水平";
+"Vertical Scrolling Paging" = "分页";
 "Themes" = "主题";
 "Light" = "日间模式";
 "Dark" = "夜间模式";
@@ -228,6 +232,7 @@
 "Stroke Color" = "边框颜色";
 "Fill Color" = "填充颜色";
 "Line and Border Style" = "线型";
+"Dash Spacing" = "虚线";
 "Start" = "线头";
 "End" = "线尾";
 "Arrow Style" = "箭头样式";
@@ -288,6 +293,8 @@
 "Paste and Match Style" = "带样式粘贴";
 "Export Successfully!" = "图片导出成功!";
 "Exit" = "退出";
+"Styles" = "效果";
+"Select All" = "选择全部";
 
 "Text Field" = "文本域";
 "Check Box" = "复选框";
@@ -545,3 +552,16 @@
 "Marked" = "已标记";
 "Reply" = "回复";
 "View Reply" = "查看回复";
+
+"Compress" = "压缩";
+"Selected File" = "选中文档";
+"Change" = "更换";
+"Compress Quality" = "压缩质量";
+"Low Quality" = "低";
+"Standard Quality" = "标准";
+"High Quality" = "高";
+"Custom" = "自定义";
+"Saving Path" = "文件存储路径";
+"Compressing" = "正在压缩···";
+"Incorrect password, please try again." = "密码错误,请重试。";
+"Compressed successfully!" = "压缩成功";

+ 15 - 7
example/lib/examples.dart

@@ -64,13 +64,21 @@ void showDocument(context) async {
 }
 
 void pickDocument() async {
-  FilePickerResult? result = await FilePicker.platform.pickFiles(
-    type: FileType.custom,
-    allowedExtensions: ['pdf'],
-  );
-  if (result != null) {
-    ComPDFKit.openDocument(result.files.first.path!,
-        password: '', configuration: CPDFConfiguration());
+  if (Platform.isIOS) {
+    await ComPDFKit.getPdfFilePath().then((value) {
+      ComPDFKit.openDocument(value!,
+          password: '', configuration: CPDFConfiguration());
+    });
+  } else {
+    FilePickerResult? result = await FilePicker.platform.pickFiles(
+      type: FileType.custom,
+      allowedExtensions: ['pdf'],
+    );
+
+    if (result != null) {
+      ComPDFKit.openDocument(result.files.first.path!,
+          password: '', configuration: CPDFConfiguration());
+    }
   }
 }
 

+ 49 - 12
ios/Classes/CompdfkitFlutterPlugin.swift

@@ -3,13 +3,16 @@ import UIKit
 import ComPDFKit
 import ComPDFKit_Tools
 
-public class CompdfkitFlutterPlugin: NSObject, FlutterPlugin, CPDFViewBaseControllerDelete {
+public class CompdfkitFlutterPlugin: NSObject, FlutterPlugin, CPDFViewBaseControllerDelete, UIDocumentPickerDelegate {
 
     public var messager : FlutterBinaryMessenger?
-
+    
+    private var startAccessing: Bool = false
+    
+    private var _reuslt: FlutterResult?
 
     public static func register(with registrar: FlutterPluginRegistrar) {
-        let channel = FlutterMethodChannel(name: "com.compdfkit.flutter.plugin", binaryMessenger: registrar.messenger())
+        let channel = FlutterMethodChannel.init(name: "com.compdfkit.flutter.plugin", binaryMessenger: registrar.messenger())
 
         let instance = CompdfkitFlutterPlugin()
         instance.messager = registrar.messenger()
@@ -43,17 +46,29 @@ public class CompdfkitFlutterPlugin: NSObject, FlutterPlugin, CPDFViewBaseContro
             let path = initInfo?["document"] as? String ?? ""
             let document = NSURL(fileURLWithPath: path)
             
-            let fileManager = FileManager.default
-            let samplesFilePath = NSHomeDirectory().appending("/Documents/Files")
-            let fileName = document.lastPathComponent ?? ""
-            let docsFilePath = samplesFilePath + "/" + fileName
+            var success = false
+            var documentPath = path
             
-            if !fileManager.fileExists(atPath: samplesFilePath) {
-                try? FileManager.default.createDirectory(atPath: samplesFilePath, withIntermediateDirectories: true, attributes: nil)
+            if startAccessing {
+                success = document.startAccessingSecurityScopedResource()
+                
+                startAccessing = false
+            } else {
+                let fileManager = FileManager.default
+                let samplesFilePath = NSHomeDirectory().appending("/Documents/Files")
+                let fileName = document.lastPathComponent ?? ""
+                let docsFilePath = samplesFilePath + "/" + fileName
+                
+                if !fileManager.fileExists(atPath: samplesFilePath) {
+                    try? FileManager.default.createDirectory(atPath: samplesFilePath, withIntermediateDirectories: true, attributes: nil)
+                }
+                
+                try? FileManager.default.copyItem(atPath: document.path ?? "", toPath: docsFilePath)
+                
+                documentPath = docsFilePath
             }
             
-            try? FileManager.default.copyItem(atPath: document.path ?? "", toPath: docsFilePath)
-            
+        
             let jsonDataParse = CPDFJSONDataParse(String: jsonString as! String)
             guard let configuration = jsonDataParse.configuration else { return }
             if let rootViewControl = UIApplication.shared.keyWindow?.rootViewController {
@@ -63,15 +78,26 @@ public class CompdfkitFlutterPlugin: NSObject, FlutterPlugin, CPDFViewBaseContro
                     tRootViewControl = presentedViewController
                 }
                 
-                let pdfViewController = CPDFViewController(filePath: docsFilePath, password: nil, configuration: configuration)
+                let pdfViewController = CPDFViewController(filePath: documentPath, password: nil, configuration: configuration)
                 let navController = CNavigationController(rootViewController: pdfViewController)
                 pdfViewController.delegate = self
                 navController.modalPresentationStyle = .fullScreen
                 tRootViewControl.present(navController, animated: true)
             }
+            
+            if success {
+                document.stopAccessingSecurityScopedResource()
+            }
         case "get_temporary_directory":
             result(self.getTemporaryDirectory())
             
+        case "get_pdf_file_path":
+            let documentTypes = ["com.adobe.pdf"]
+            let documentPickerViewController = UIDocumentPickerViewController(documentTypes: documentTypes, in: .open)
+            documentPickerViewController.delegate = self
+            UIApplication.presentedViewController()?.present(documentPickerViewController, animated: true, completion: nil)
+            _reuslt = result
+           
         default:
             result(FlutterMethodNotImplemented)
         }
@@ -88,4 +114,15 @@ public class CompdfkitFlutterPlugin: NSObject, FlutterPlugin, CPDFViewBaseContro
         baseControllerDelete.dismiss(animated: true)
     }
     
+    // MARK: - UIDocumentPickerDelegate
+    
+    public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
+        let fileUrlAuthozied = urls.first?.startAccessingSecurityScopedResource() ?? false
+        if fileUrlAuthozied {
+            let filePath = urls.first?.path ?? ""
+            _reuslt?(filePath)
+            startAccessing = true
+        }
+    }
+    
 }

+ 64 - 19
ios/Classes/reader/CPDFDocumentPlugin.swift

@@ -1,9 +1,12 @@
 //
 //  CPDFDocumentPlugin.swift
 //  compdfkit_flutter
+//  Copyright © 2014-2023 PDF Technologies, Inc. All Rights Reserved.
 //
-//  Created by Xiaolong Liu on 2024/7/19.
-//
+//  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.
 
 import Foundation
 import ComPDFKit
@@ -14,7 +17,7 @@ public class CPDFDocumentPlugin {
     
     private var document : CPDFDocument?
     
-    private var _methodChannel : FlutterMethodChannel
+    public var _methodChannel : FlutterMethodChannel
     
     private var pdfViewController : CPDFViewController?
     
@@ -54,6 +57,8 @@ public class CPDFDocumentPlugin {
                 if(self.document?.isLocked == true){
                     self.document?.unlock(withPassword: password as? String ?? "")
                 }
+                self.pdfViewController?.pdfListView?.document = self.document
+                self.pdfViewController?.pdfListView?.setNeedsDisplay()
                 result(2)
             case "get_file_name":
                 
@@ -66,46 +71,86 @@ public class CPDFDocumentPlugin {
                 result("文档名称")
             case "is_encrypted":
                 // TODO: 返回文档是否加密了,true:加密, false:未加密
-                result(false)
+                let isEncrypted = self.document?.isEncrypted ?? false
+               
+                result(isEncrypted)
             case "is_image_doc":
                 // TODO: 是否为图片文档, true:是图片文档, false:非图片文档
-                result(false)
+                let isImageDoc = self.document?.isImageDocument() ?? false
+                
+                result(isImageDoc)
             case "get_permissions":
                 // TODO: 返回文档当前的权限,返回int类型。none:0, user:1, owner:2
-                result(0)
+                let permissions = self.document?.permissionsStatus ?? .none
+                switch permissions {
+                case .none:
+                    result(0)
+                case .user:
+                    result(1)
+                case .owner:
+                    result(2)
+              
+                default:
+                    result(0)
+                }
+                
             case "check_owner_unlocked":
                 // TODO: 检查所有者权限是否已经解锁. 已解锁:true, 未解锁:false
-                result(false)
+                let owner = self.document?.isCheckOwnerUnlocked() ?? false
+                
+                result(owner)
             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)
+                let password = info?["password"] as? String ?? ""
+                
+                let isOwnerPassword = self.document?.checkOwnerPassword(password) ?? false
+
+                result(isOwnerPassword)
             case "has_change":
                 // TODO: 返回文档是否有修改:true:有修改, false:未修改
-                result(false)
+                let isModified = self.document?.isModified() ?? false
+                
+                result(isModified)
             case "import_annotations":
                 // TODO: 导入注释
                 // 返回值:导入成功:true, 导入失败:false
-                result(true)
+                let importPath = call.arguments as? String ?? ""
+                let success = self.document?.importAnnotation(fromXFDFPath: importPath) ?? false
+                if success {
+                    self.pdfViewController?.pdfListView?.setNeedsDisplayForVisiblePages()
+                }
+                result(success)
             case "export_annotations":
                 // TODO: 导出注释
                 // 返回值:导出成功:导出的xfdf文件路径, 导出失败:空字符串
-                result("")
+
+                let fileNameWithExtension = self.document?.documentURL.lastPathComponent ?? ""
+                let fileName = (fileNameWithExtension as NSString).deletingPathExtension
+                let documentFolder = NSHomeDirectory().appending("/Documents/\(fileName)_xfdf.xfdf")
+                let succes = self.document?.exportAnnotation(toXFDFPath: documentFolder) ?? false
+                if succes {
+                    result(documentFolder)
+                } else {
+                    result("")
+                }
+                
             case "remove_all_annotations":
                 // TODO: 删除所有注释
                 // 返回值:删除成功:true, 删除失败:false
+                let pageCount = self.document?.pageCount ?? 0
+                for i in 0..<pageCount {
+                    let page = self.document?.page(at: i)
+                    page?.removeAllAnnotations()
+                }
+                self.pdfViewController?.pdfListView?.setNeedsDisplayForVisiblePages()
+                self.pdfViewController?.pdfListView?.updateActiveAnnotations([])
                 result(true)
             case "get_page_count":
                 // TODO: 返回当前文档总页数
-                result(1)
+                let count = self.document?.pageCount ?? 1
+                result(count)
             default:
                 result(FlutterMethodNotImplemented)
             }

+ 18 - 2
ios/Classes/reader/CPDFViewCtrlFactory.swift

@@ -45,7 +45,7 @@ class CPDFViewCtrlFlutter: NSObject, FlutterPlatformView, CPDFViewBaseController
     
     private var navigationController : CNavigationController
 
-
+    private var plugin : CPDFViewCtrlPlugin
     init(
         frame: CGRect,
         viewIdentifier viewId: Int64,
@@ -81,7 +81,7 @@ class CPDFViewCtrlFlutter: NSObject, FlutterPlatformView, CPDFViewBaseController
         navigationController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
         navigationController.view.frame = frame
         
-        var plugin = CPDFViewCtrlPlugin(viewId: viewId, binaryMessenger: messenger!, controller: pdfViewController)
+        plugin = CPDFViewCtrlPlugin(viewId: viewId, binaryMessenger: messenger!, controller: pdfViewController)
 
         super.init()
         
@@ -94,10 +94,26 @@ class CPDFViewCtrlFlutter: NSObject, FlutterPlatformView, CPDFViewBaseController
     func view() -> UIView {
         return navigationController.view
     }
+    
+    // MARK: - CPDFViewBaseControllerDelete
         
     public func PDFViewBaseControllerDissmiss(_ baseControllerDelete: CPDFViewBaseController) {
 
     }
+   
+    func PDFViewBaseController(_ baseController: CPDFViewBaseController, SaveState success: Bool) {
+        // TODO: 监听到执行了保存的回调
+        if success {
+            plugin._methodChannel.invokeMethod("saveDocument", arguments: nil)
+        }
+    }
+    
+//    func PDFViewBaseController(_ baseController: CPDFViewBaseController, currentPageIndex index: Int) {
+//        // TODO: 返回当前滑动到的页码
+//        plugin._methodChannel.invokeMethod("onPageChanged", arguments: index)
+//        
+//        print("\(index)")
+//    }
 
 }
 

+ 4 - 11
ios/Classes/reader/CPDFViewCtrlPlugin.swift

@@ -15,7 +15,7 @@ import ComPDFKit_Tools
 
 class CPDFViewCtrlPlugin {
     
-    private var _methodChannel : FlutterMethodChannel
+    public var _methodChannel : FlutterMethodChannel
     
     private var pdfViewController : CPDFViewController
     
@@ -25,12 +25,6 @@ class CPDFViewCtrlPlugin {
         registeryMethodChannel()
 
         var documentPlugin = CPDFDocumentPlugin(pdfViewController: pdfViewController, uid: String(describing: viewId), binaryMessager: messenger)
-
-        // TODO: 返回当前滑动到的页码
-        _methodChannel.invokeMethod("onPageChanged", arguments: 1)
-        
-        // TODO: 监听到执行了保存的回调
-        _methodChannel.invokeMethod("saveDocument", arguments: nil)
     }
     
     
@@ -83,9 +77,8 @@ class CPDFViewCtrlPlugin {
                 // 需要设置给PDFListView
                 let bgColor = call.arguments as! String
                 let color = ColorHelper.colorWithHexString(hex: bgColor)
-                print("bgColor:\(bgColor), color:\(color.description)")
-//                pdfListView.displayModeCustomColor = CPDFDisplayModeCustom()
-//                pdfListView.layoutDocumentView()
+                pdfListView.displayModeCustomColor = color
+                pdfListView.layoutDocumentView()
             case "get_read_background_color":
                 guard let pdfListView = self.pdfViewController.pdfListView else {
                     result("#FFFFFF")
@@ -93,7 +86,7 @@ class CPDFViewCtrlPlugin {
                 }
                 // TODO: 返回当前阅读的背景颜色
                 // 需要返回Hex 颜色给Flutter, 例如:'#FFFFFF'
-//                result(pdfListView.displayModeCustomColor.toHexString())
+                result(pdfListView.displayModeCustomColor.toHexString())
             case "set_form_field_highlight":
                 guard let pdfListView = self.pdfViewController.pdfListView else {
                     return

+ 6 - 2
lib/compdfkit.dart

@@ -13,8 +13,7 @@ import 'package:flutter/services.dart';
 
 /// ComPDFKit plugin to load PDF and image documents on both platform iOS and Android.
 class ComPDFKit {
-  static const MethodChannel _methodChannel =
-      MethodChannel('com.compdfkit.flutter.plugin');
+  static const MethodChannel _methodChannel = MethodChannel('com.compdfkit.flutter.plugin');
 
   /// Please enter your ComPDFKit license to initialize the ComPDFKit SDK.<br/>
   /// This method is used for offline license authentication.
@@ -97,4 +96,9 @@ class ComPDFKit {
   static Future<bool> removeSignFileList() async {
     return await _methodChannel.invokeMethod('remove_sign_file_list');
   }
+
+  static Future<String?> getPdfFilePath() async {
+    final String? filePath = await _methodChannel.invokeMethod('get_pdf_file_path');
+    return filePath;
+  }
 }