David PHAM-VAN

Implement dynamic layout on iOS and macOS

@@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
5 - Add imageFromAssetBundle and networkImage 5 - Add imageFromAssetBundle and networkImage
6 - Add Page orientation on PdfPreview 6 - Add Page orientation on PdfPreview
7 - Improve PrintJob object 7 - Improve PrintJob object
  8 +- Implement dynamic layout on iOS and macOS
8 9
9 ## 5.0.0-nullsafety.1 10 ## 5.0.0-nullsafety.1
10 11
@@ -28,6 +28,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate @@ -28,6 +28,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate
28 private var urlObservation: NSKeyValueObservation? 28 private var urlObservation: NSKeyValueObservation?
29 private var jobName: String? 29 private var jobName: String?
30 private var orientation: UIPrintInfo.Orientation? 30 private var orientation: UIPrintInfo.Orientation?
  31 + private let semaphore = DispatchSemaphore(value: 0)
31 32
32 public init(printing: PrintingPlugin, index: Int) { 33 public init(printing: PrintingPlugin, index: Int) {
33 self.printing = printing 34 self.printing = printing
@@ -46,9 +47,9 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate @@ -46,9 +47,9 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate
46 } 47 }
47 } 48 }
48 49
49 - func cancelJob(_ error: String?) { 50 + func cancelJob(_: String?) {
50 pdfDocument = nil 51 pdfDocument = nil
51 - printing.onCompleted(printJob: self, completed: false, error: error as NSString?) 52 + semaphore.signal()
52 } 53 }
53 54
54 func setDocument(_ data: Data?) { 55 func setDocument(_ data: Data?) {
@@ -57,24 +58,25 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate @@ -57,24 +58,25 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate
57 let dataProvider = CGDataProvider(dataInfo: nil, data: bytesPointer, size: data?.count ?? 0, releaseData: dataProviderReleaseDataCallback) 58 let dataProvider = CGDataProvider(dataInfo: nil, data: bytesPointer, size: data?.count ?? 0, releaseData: dataProviderReleaseDataCallback)
58 pdfDocument = CGPDFDocument(dataProvider!) 59 pdfDocument = CGPDFDocument(dataProvider!)
59 60
60 - let controller = UIPrintInteractionController.shared  
61 - controller.delegate = self  
62 -  
63 - let printInfo = UIPrintInfo.printInfo()  
64 - printInfo.jobName = jobName!  
65 - printInfo.outputType = .general  
66 - if orientation != nil {  
67 - printInfo.orientation = orientation!  
68 - orientation = nil  
69 - }  
70 - controller.printInfo = printInfo  
71 - controller.printPageRenderer = self  
72 - controller.present(animated: true, completionHandler: completionHandler) 61 + // Unblock the main thread
  62 + semaphore.signal()
73 } 63 }
74 64
75 override public var numberOfPages: Int { 65 override public var numberOfPages: Int {
76 - let pages = pdfDocument?.numberOfPages ?? 0  
77 - return pages 66 + printing.onLayout(
  67 + printJob: self,
  68 + width: paperRect.size.width,
  69 + height: paperRect.size.height,
  70 + marginLeft: printableRect.origin.x,
  71 + marginTop: printableRect.origin.y,
  72 + marginRight: paperRect.size.width - (printableRect.origin.x + printableRect.size.width),
  73 + marginBottom: paperRect.size.height - (printableRect.origin.y + printableRect.size.height)
  74 + )
  75 +
  76 + // Block the main thread, waiting for a document
  77 + semaphore.wait()
  78 +
  79 + return pdfDocument?.numberOfPages ?? 0
78 } 80 }
79 81
80 func completionHandler(printController _: UIPrintInteractionController, completed: Bool, error: Error?) { 82 func completionHandler(printController _: UIPrintInteractionController, completed: Bool, error: Error?) {
@@ -110,7 +112,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate @@ -110,7 +112,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate
110 controller.print(to: printer, completionHandler: completionHandler) 112 controller.print(to: printer, completionHandler: completionHandler)
111 } 113 }
112 114
113 - func printPdf(name: String, withPageSize size: CGSize, andMargin margin: CGRect) { 115 + func printPdf(name: String, withPageSize size: CGSize, andMargin _: CGRect) {
114 let printing = UIPrintInteractionController.isPrintingAvailable 116 let printing = UIPrintInteractionController.isPrintingAvailable
115 if !printing { 117 if !printing {
116 self.printing.onCompleted(printJob: self, completed: false, error: "Printing not available") 118 self.printing.onCompleted(printJob: self, completed: false, error: "Printing not available")
@@ -123,15 +125,21 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate @@ -123,15 +125,21 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate
123 125
124 jobName = name 126 jobName = name
125 127
126 - self.printing.onLayout(  
127 - printJob: self,  
128 - width: size.width,  
129 - height: size.height,  
130 - marginLeft: margin.minX,  
131 - marginTop: margin.minY,  
132 - marginRight: size.width - margin.maxX,  
133 - marginBottom: size.height - margin.maxY  
134 - ) 128 + let controller = UIPrintInteractionController.shared
  129 + controller.delegate = self
  130 +
  131 + let printInfo = UIPrintInfo.printInfo()
  132 + printInfo.jobName = jobName!
  133 + printInfo.outputType = .general
  134 + if orientation != nil {
  135 + printInfo.orientation = orientation!
  136 + orientation = nil
  137 + }
  138 + controller.printInfo = printInfo
  139 + controller.showsPaperSelectionForLoadedPapers = true
  140 +
  141 + controller.printPageRenderer = self
  142 + controller.present(animated: true, completionHandler: completionHandler)
135 } 143 }
136 144
137 static func sharePdf(data: Data, withSourceRect rect: CGRect, andName name: String) { 145 static func sharePdf(data: Data, withSourceRect rect: CGRect, andName name: String) {
@@ -287,7 +295,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate @@ -287,7 +295,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate
287 public static func printingInfo() -> NSDictionary { 295 public static func printingInfo() -> NSDictionary {
288 let data: NSDictionary = [ 296 let data: NSDictionary = [
289 "directPrint": true, 297 "directPrint": true,
290 - "dynamicLayout": false, 298 + "dynamicLayout": true,
291 "canPrint": true, 299 "canPrint": true,
292 "canConvertHtml": true, 300 "canConvertHtml": true,
293 "canShare": true, 301 "canShare": true,
@@ -17,12 +17,29 @@ @@ -17,12 +17,29 @@
17 import Flutter 17 import Flutter
18 import Foundation 18 import Foundation
19 19
  20 +// Dart:ffi API
  21 +private var _printingPlugin: PrintingPlugin?
  22 +
  23 +@_cdecl("net_nfet_printing_set_document")
  24 +func setDocument(job: UInt32, doc: UnsafePointer<UInt8>, size: UInt64) {
  25 + _printingPlugin!.jobs[job]?.setDocument(Data(bytes: doc, count: Int(size)))
  26 +}
  27 +
  28 +@_cdecl("net_nfet_printing_set_error")
  29 +func setError(job: UInt32, message: UnsafePointer<CChar>) {
  30 + _printingPlugin!.jobs[job]?.cancelJob(String(cString: message))
  31 +}
  32 +
  33 +// End of Dart:ffi API
  34 +
20 public class PrintingPlugin: NSObject, FlutterPlugin { 35 public class PrintingPlugin: NSObject, FlutterPlugin {
21 private var channel: FlutterMethodChannel 36 private var channel: FlutterMethodChannel
  37 + public var jobs = [UInt32: PrintJob]()
22 38
23 init(_ channel: FlutterMethodChannel) { 39 init(_ channel: FlutterMethodChannel) {
24 self.channel = channel 40 self.channel = channel
25 super.init() 41 super.init()
  42 + _printingPlugin = self
26 } 43 }
27 44
28 /// Entry point 45 /// Entry point
@@ -44,6 +61,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { @@ -44,6 +61,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
44 let marginRight = CGFloat((args["marginRight"] as? NSNumber)?.floatValue ?? 0.0) 61 let marginRight = CGFloat((args["marginRight"] as? NSNumber)?.floatValue ?? 0.0)
45 let marginBottom = CGFloat((args["marginBottom"] as? NSNumber)?.floatValue ?? 0.0) 62 let marginBottom = CGFloat((args["marginBottom"] as? NSNumber)?.floatValue ?? 0.0)
46 let printJob = PrintJob(printing: self, index: args["job"] as! Int) 63 let printJob = PrintJob(printing: self, index: args["job"] as! Int)
  64 + jobs[args["job"] as! UInt32] = printJob
47 printJob.printPdf(name: name, 65 printJob.printPdf(name: name,
48 withPageSize: CGSize( 66 withPageSize: CGSize(
49 width: width, 67 width: width,
@@ -137,19 +155,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { @@ -137,19 +155,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
137 "job": printJob.index, 155 "job": printJob.index,
138 ] as [String: Any] 156 ] as [String: Any]
139 157
140 - channel.invokeMethod("onLayout", arguments: arg, result: { (result: Any?) -> Void in  
141 - if result as? Bool == false {  
142 - printJob.cancelJob(nil)  
143 - } else if result is FlutterError {  
144 - let error = result as! FlutterError  
145 - printJob.cancelJob(error.message)  
146 - } else if result is FlutterStandardTypedData {  
147 - let object = result as! FlutterStandardTypedData  
148 - printJob.setDocument(object.data)  
149 - } else {  
150 - printJob.cancelJob("Unknown data type")  
151 - }  
152 - }) 158 + channel.invokeMethod("onLayout", arguments: arg)
153 } 159 }
154 160
155 /// send completion status to flutter 161 /// send completion status to flutter
@@ -160,6 +166,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { @@ -160,6 +166,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
160 "job": printJob.index, 166 "job": printJob.index,
161 ] 167 ]
162 channel.invokeMethod("onCompleted", arguments: data) 168 channel.invokeMethod("onCompleted", arguments: data)
  169 + jobs.removeValue(forKey: UInt32(printJob.index))
163 } 170 }
164 171
165 /// send html to pdf data result to flutter 172 /// send html to pdf data result to flutter
@@ -15,11 +15,13 @@ @@ -15,11 +15,13 @@
15 */ 15 */
16 16
17 import 'dart:async'; 17 import 'dart:async';
  18 +import 'dart:io';
18 import 'dart:typed_data'; 19 import 'dart:typed_data';
19 20
20 import 'package:flutter/rendering.dart' show Rect; 21 import 'package:flutter/rendering.dart' show Rect;
21 import 'package:flutter/services.dart'; 22 import 'package:flutter/services.dart';
22 import 'package:pdf/pdf.dart'; 23 import 'package:pdf/pdf.dart';
  24 +import 'package:printing/src/method_channel_ffi.dart';
23 25
24 import 'callback.dart'; 26 import 'callback.dart';
25 import 'interface.dart'; 27 import 'interface.dart';
@@ -56,7 +58,20 @@ class MethodChannelPrinting extends PrintingPlatform { @@ -56,7 +58,20 @@ class MethodChannelPrinting extends PrintingPlatform {
56 marginBottom: call.arguments['marginBottom'], 58 marginBottom: call.arguments['marginBottom'],
57 ); 59 );
58 60
59 - final bytes = await job.onLayout!(format); 61 + Uint8List bytes;
  62 + try {
  63 + bytes = await job.onLayout!(format);
  64 + } catch (e) {
  65 + if (Platform.isMacOS || Platform.isIOS) {
  66 + return setErrorFfi(job, e.toString());
  67 + }
  68 +
  69 + rethrow;
  70 + }
  71 +
  72 + if (Platform.isMacOS || Platform.isIOS) {
  73 + return setDocumentFfi(job, bytes);
  74 + }
60 75
61 return Uint8List.fromList(bytes); 76 return Uint8List.fromList(bytes);
62 case 'onCompleted': 77 case 'onCompleted':
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +import 'dart:ffi' as ffi;
  18 +import 'dart:io' as io;
  19 +import 'dart:typed_data';
  20 +
  21 +import 'package:ffi/ffi.dart' as ffi;
  22 +
  23 +import 'print_job.dart';
  24 +
  25 +/// Load the dynamic library
  26 +final ffi.DynamicLibrary _dynamicLibrary = _open();
  27 +ffi.DynamicLibrary _open() {
  28 + if (io.Platform.isMacOS || io.Platform.isIOS) {
  29 + return ffi.DynamicLibrary.process();
  30 + }
  31 + throw UnsupportedError('This platform is not supported.');
  32 +}
  33 +
  34 +/// Set the Pdf document data
  35 +void setDocumentFfi(PrintJob job, Uint8List data) {
  36 + final nativeBytes = ffi.allocate<ffi.Uint8>(count: data.length);
  37 + nativeBytes.asTypedList(data.length).setAll(0, data);
  38 + _setDocument(job.index, nativeBytes, data.length);
  39 +}
  40 +
  41 +final _SetDocument_Dart _setDocument =
  42 + _dynamicLibrary.lookupFunction<_SetDocument_C, _SetDocument_Dart>(
  43 + 'net_nfet_printing_set_document',
  44 +);
  45 +
  46 +typedef _SetDocument_C = ffi.Void Function(
  47 + ffi.Uint32 job,
  48 + ffi.Pointer<ffi.Uint8> data,
  49 + ffi.Uint64 size,
  50 +);
  51 +
  52 +typedef _SetDocument_Dart = void Function(
  53 + int job,
  54 + ffi.Pointer<ffi.Uint8> data,
  55 + int size,
  56 +);
  57 +
  58 +/// Set the Pdf Error message
  59 +void setErrorFfi(PrintJob job, String message) {
  60 + _setError(job.index, ffi.Utf8.toUtf8(message));
  61 +}
  62 +
  63 +final _SetError_Dart _setError =
  64 + _dynamicLibrary.lookupFunction<_SetError_C, _SetError_Dart>(
  65 + 'net_nfet_printing_set_error',
  66 +);
  67 +
  68 +typedef _SetError_C = ffi.Void Function(
  69 + ffi.Uint32 job,
  70 + ffi.Pointer<ffi.Utf8> message,
  71 +);
  72 +
  73 +typedef _SetError_Dart = void Function(
  74 + int job,
  75 + ffi.Pointer<ffi.Utf8> message,
  76 +);
@@ -29,6 +29,7 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { @@ -29,6 +29,7 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate {
29 private var printOperation: NSPrintOperation? 29 private var printOperation: NSPrintOperation?
30 private var pdfDocument: CGPDFDocument? 30 private var pdfDocument: CGPDFDocument?
31 private var page: CGPDFPage? 31 private var page: CGPDFPage?
  32 + private let semaphore = DispatchSemaphore(value: 0)
32 33
33 public init(printing: PrintingPlugin, index: Int) { 34 public init(printing: PrintingPlugin, index: Int) {
34 self.printing = printing 35 self.printing = printing
@@ -47,7 +48,29 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { @@ -47,7 +48,29 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate {
47 48
48 setFrameSize(size) 49 setFrameSize(size)
49 setBoundsSize(size) 50 setBoundsSize(size)
50 - range.pointee.length = pdfDocument?.numberOfPages ?? 0 51 +
  52 + printing.onLayout(
  53 + printJob: self,
  54 + width: printOperation!.printInfo.paperSize.width,
  55 + height: printOperation!.printInfo.paperSize.height,
  56 + marginLeft: printOperation!.printInfo.leftMargin,
  57 + marginTop: printOperation!.printInfo.topMargin,
  58 + marginRight: printOperation!.printInfo.rightMargin,
  59 + marginBottom: printOperation!.printInfo.bottomMargin
  60 + )
  61 +
  62 + // Block the main thread, waiting for a document
  63 + semaphore.wait()
  64 +
  65 + if pdfDocument != nil {
  66 + range.pointee.length = pdfDocument!.numberOfPages
  67 + let page = pdfDocument!.page(at: 1)
  68 + let size = page?.getBoxRect(CGPDFBox.mediaBox) ?? NSZeroRect
  69 + setFrameSize(size.size)
  70 + setBoundsSize(size.size)
  71 + } else {
  72 + range.pointee.length = 0
  73 + }
51 return true 74 return true
52 } 75 }
53 76
@@ -67,8 +90,8 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { @@ -67,8 +90,8 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate {
67 let dataProvider = CGDataProvider(dataInfo: nil, data: bytesPointer, size: data?.count ?? 0, releaseData: dataProviderReleaseDataCallback) 90 let dataProvider = CGDataProvider(dataInfo: nil, data: bytesPointer, size: data?.count ?? 0, releaseData: dataProviderReleaseDataCallback)
68 pdfDocument = CGPDFDocument(dataProvider!) 91 pdfDocument = CGPDFDocument(dataProvider!)
69 92
70 - let window = NSApplication.shared.mainWindow!  
71 - printOperation!.runModal(for: window, delegate: self, didRun: #selector(printOperationDidRun(printOperation:success:contextInfo:)), contextInfo: nil) 93 + // Unblock the main thread
  94 + semaphore.signal()
72 } 95 }
73 96
74 override public func draw(_: NSRect) { 97 override public func draw(_: NSRect) {
@@ -136,21 +159,15 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate { @@ -136,21 +159,15 @@ public class PrintJob: NSView, NSSharingServicePickerDelegate {
136 // Print the custom view 159 // Print the custom view
137 printOperation = NSPrintOperation(view: self, printInfo: printInfo) 160 printOperation = NSPrintOperation(view: self, printInfo: printInfo)
138 printOperation!.jobTitle = name 161 printOperation!.jobTitle = name
139 - printOperation!.printPanel.options = [.showsPreview] 162 + printOperation!.printPanel.options = [.showsPreview, .showsPaperSize, .showsOrientation]
140 163
141 - printing.onLayout(  
142 - printJob: self,  
143 - width: printOperation!.printInfo.paperSize.width,  
144 - height: printOperation!.printInfo.paperSize.height,  
145 - marginLeft: printOperation!.printInfo.leftMargin,  
146 - marginTop: printOperation!.printInfo.topMargin,  
147 - marginRight: printOperation!.printInfo.rightMargin,  
148 - marginBottom: printOperation!.printInfo.bottomMargin  
149 - ) 164 + let window = NSApplication.shared.mainWindow!
  165 + printOperation!.runModal(for: window, delegate: self, didRun: #selector(printOperationDidRun(printOperation:success:contextInfo:)), contextInfo: nil)
150 } 166 }
151 167
152 - func cancelJob(_ error: String?) {  
153 - printing.onCompleted(printJob: self, completed: false, error: error as NSString?) 168 + func cancelJob(_: String?) {
  169 + pdfDocument = nil
  170 + semaphore.signal()
154 } 171 }
155 172
156 public static func sharePdf(data: Data, withSourceRect rect: CGRect, andName name: String) { 173 public static func sharePdf(data: Data, withSourceRect rect: CGRect, andName name: String) {
@@ -17,12 +17,29 @@ @@ -17,12 +17,29 @@
17 import FlutterMacOS 17 import FlutterMacOS
18 import Foundation 18 import Foundation
19 19
  20 +// Dart:ffi API
  21 +private var _printingPlugin: PrintingPlugin?
  22 +
  23 +@_cdecl("net_nfet_printing_set_document")
  24 +func setDocument(job: UInt32, doc: UnsafePointer<UInt8>, size: UInt64) {
  25 + _printingPlugin!.jobs[job]?.setDocument(Data(bytes: doc, count: Int(size)))
  26 +}
  27 +
  28 +@_cdecl("net_nfet_printing_set_error")
  29 +func setError(job: UInt32, message: UnsafePointer<CChar>) {
  30 + _printingPlugin!.jobs[job]?.cancelJob(String(cString: message))
  31 +}
  32 +
  33 +// End of Dart:ffi API
  34 +
20 public class PrintingPlugin: NSObject, FlutterPlugin { 35 public class PrintingPlugin: NSObject, FlutterPlugin {
21 private var channel: FlutterMethodChannel 36 private var channel: FlutterMethodChannel
  37 + public var jobs = [UInt32: PrintJob]()
22 38
23 init(_ channel: FlutterMethodChannel) { 39 init(_ channel: FlutterMethodChannel) {
24 self.channel = channel 40 self.channel = channel
25 super.init() 41 super.init()
  42 + _printingPlugin = self
26 } 43 }
27 44
28 /// Entry point 45 /// Entry point
@@ -44,6 +61,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { @@ -44,6 +61,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
44 let marginRight = CGFloat((args["marginRight"] as? NSNumber)?.floatValue ?? 0.0) 61 let marginRight = CGFloat((args["marginRight"] as? NSNumber)?.floatValue ?? 0.0)
45 let marginBottom = CGFloat((args["marginBottom"] as? NSNumber)?.floatValue ?? 0.0) 62 let marginBottom = CGFloat((args["marginBottom"] as? NSNumber)?.floatValue ?? 0.0)
46 let printJob = PrintJob(printing: self, index: args["job"] as! Int) 63 let printJob = PrintJob(printing: self, index: args["job"] as! Int)
  64 + jobs[args["job"] as! UInt32] = printJob
47 printJob.printPdf(name: name, 65 printJob.printPdf(name: name,
48 withPageSize: CGSize( 66 withPageSize: CGSize(
49 width: width, 67 width: width,
@@ -108,13 +126,6 @@ public class PrintingPlugin: NSObject, FlutterPlugin { @@ -108,13 +126,6 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
108 andBaseUrl: args["baseUrl"] as? String == nil ? nil : URL(string: args["baseUrl"] as! String) 126 andBaseUrl: args["baseUrl"] as? String == nil ? nil : URL(string: args["baseUrl"] as! String)
109 ) 127 )
110 result(NSNumber(value: 1)) 128 result(NSNumber(value: 1))
111 -// } else if call.method == "pickPrinter" {  
112 -// PrintJob.pickPrinter(result: result, withSourceRect: CGRect(  
113 -// x: CGFloat((args["x"] as? NSNumber)?.floatValue ?? 0.0),  
114 -// y: CGFloat((args["y"] as? NSNumber)?.floatValue ?? 0.0),  
115 -// width: CGFloat((args["w"] as? NSNumber)?.floatValue ?? 0.0),  
116 -// height: CGFloat((args["h"] as? NSNumber)?.floatValue ?? 0.0)  
117 -// ))  
118 } else if call.method == "printingInfo" { 129 } else if call.method == "printingInfo" {
119 result(PrintJob.printingInfo()) 130 result(PrintJob.printingInfo())
120 } else if call.method == "rasterPdf" { 131 } else if call.method == "rasterPdf" {
@@ -143,19 +154,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { @@ -143,19 +154,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
143 "job": printJob.index, 154 "job": printJob.index,
144 ] as [String: Any] 155 ] as [String: Any]
145 156
146 - channel.invokeMethod("onLayout", arguments: arg, result: { (result: Any?) -> Void in  
147 - if result as? Bool == false {  
148 - printJob.cancelJob(nil)  
149 - } else if result is FlutterError {  
150 - let error = result as! FlutterError  
151 - printJob.cancelJob(error.message)  
152 - } else if result is FlutterStandardTypedData {  
153 - let object = result as! FlutterStandardTypedData  
154 - printJob.setDocument(object.data)  
155 - } else {  
156 - printJob.cancelJob("Unknown data type")  
157 - }  
158 - }) 157 + channel.invokeMethod("onLayout", arguments: arg)
159 } 158 }
160 159
161 /// send completion status to flutter 160 /// send completion status to flutter
@@ -166,6 +165,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { @@ -166,6 +165,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin {
166 "job": printJob.index, 165 "job": printJob.index,
167 ] 166 ]
168 channel.invokeMethod("onCompleted", arguments: data) 167 channel.invokeMethod("onCompleted", arguments: data)
  168 + jobs.removeValue(forKey: UInt32(printJob.index))
169 } 169 }
170 170
171 /// send html to pdf data result to flutter 171 /// send html to pdf data result to flutter
@@ -11,6 +11,7 @@ environment: @@ -11,6 +11,7 @@ environment:
11 flutter: ">=1.16.0" 11 flutter: ">=1.16.0"
12 12
13 dependencies: 13 dependencies:
  14 + ffi: ">=0.2.0-nullsafety <2.0.0"
14 flutter: 15 flutter:
15 sdk: flutter 16 sdk: flutter
16 flutter_web_plugins: 17 flutter_web_plugins: