Committed by
David PHAM-VAN
Workaround for iOS bug + force paper size:
implemented fix when UIPrinter isn't contactable even if accessible due to an iOS bug. added a flag to force using custom paper size to use when the combination of airprint+printer driver choose a wrong paper format.
Showing
9 changed files
with
60 additions
and
2 deletions
printing/ios/Classes/CustomPrintPaper.swift
0 → 100644
@@ -25,6 +25,9 @@ func dataProviderReleaseDataCallback(info _: UnsafeMutableRawPointer?, data: Uns | @@ -25,6 +25,9 @@ func dataProviderReleaseDataCallback(info _: UnsafeMutableRawPointer?, data: Uns | ||
25 | // Each printer will be identified by its URL string | 25 | // Each printer will be identified by its URL string |
26 | var selectedPrinters = [String: UIPrinter]() | 26 | var selectedPrinters = [String: UIPrinter]() |
27 | 27 | ||
28 | +// Holds the printer after it was picked | ||
29 | +var pickedPrinter: UIPrinter? | ||
30 | + | ||
28 | public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate { | 31 | public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate { |
29 | private var printing: PrintingPlugin | 32 | private var printing: PrintingPlugin |
30 | public var index: Int | 33 | public var index: Int |
@@ -36,6 +39,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | @@ -36,6 +39,7 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | ||
36 | private let semaphore = DispatchSemaphore(value: 0) | 39 | private let semaphore = DispatchSemaphore(value: 0) |
37 | private var dynamic = false | 40 | private var dynamic = false |
38 | private var currentSize: CGSize? | 41 | private var currentSize: CGSize? |
42 | + private var forceCustomPrintPaper = false | ||
39 | 43 | ||
40 | public init(printing: PrintingPlugin, index: Int) { | 44 | public init(printing: PrintingPlugin, index: Int) { |
41 | self.printing = printing | 45 | self.printing = printing |
@@ -149,6 +153,10 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | @@ -149,6 +153,10 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | ||
149 | return paperList[0] | 153 | return paperList[0] |
150 | } | 154 | } |
151 | 155 | ||
156 | + if forceCustomPrintPaper { | ||
157 | + return CustomPrintPaper(size: currentSize!) | ||
158 | + } | ||
159 | + | ||
152 | for paper in paperList { | 160 | for paper in paperList { |
153 | if (paper.paperSize.width == currentSize!.width && paper.paperSize.height == currentSize!.height) || | 161 | if (paper.paperSize.width == currentSize!.width && paper.paperSize.height == currentSize!.height) || |
154 | (paper.paperSize.width == currentSize!.height && paper.paperSize.height == currentSize!.width) | 162 | (paper.paperSize.width == currentSize!.height && paper.paperSize.height == currentSize!.width) |
@@ -162,9 +170,11 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | @@ -162,9 +170,11 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | ||
162 | return bestPaper | 170 | return bestPaper |
163 | } | 171 | } |
164 | 172 | ||
165 | - func printPdf(name: String, withPageSize size: CGSize, andMargin margin: CGRect, withPrinter printerID: String?, dynamically dyn: Bool, outputType type: UIPrintInfo.OutputType) { | 173 | + func printPdf(name: String, withPageSize size: CGSize, andMargin margin: CGRect, withPrinter printerID: String?, dynamically dyn: Bool, outputType type: UIPrintInfo.OutputType, forceCustomPrintPaper: Bool = false) { |
166 | currentSize = size | 174 | currentSize = size |
167 | dynamic = dyn | 175 | dynamic = dyn |
176 | + self.forceCustomPrintPaper = forceCustomPrintPaper | ||
177 | + | ||
168 | let printing = UIPrintInteractionController.isPrintingAvailable | 178 | let printing = UIPrintInteractionController.isPrintingAvailable |
169 | if !printing { | 179 | if !printing { |
170 | self.printing.onCompleted(printJob: self, completed: false, error: "Printing not available") | 180 | self.printing.onCompleted(printJob: self, completed: false, error: "Printing not available") |
@@ -207,6 +217,14 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | @@ -207,6 +217,14 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | ||
207 | selectedPrinters[printerURLString] = UIPrinter(url: printerURL!) | 217 | selectedPrinters[printerURLString] = UIPrinter(url: printerURL!) |
208 | } | 218 | } |
209 | 219 | ||
220 | + // Sometimes using UIPrinter(url:) gives a non-contactable printer. | ||
221 | + // https://stackoverflow.com/questions/34602302/creating-a-working-uiprinter-object-from-url-for-dialogue-free-printing | ||
222 | + // This lets use a printer saved during picking and fall back using a printer created with UIPrinter(url:) | ||
223 | + if pickedPrinter != nil && selectedPrinters[printerURLString]!.url == pickedPrinter?.url { | ||
224 | + controller.print(to: pickedPrinter!, completionHandler: completionHandler) | ||
225 | + return | ||
226 | + } | ||
227 | + | ||
210 | selectedPrinters[printerURLString]!.contactPrinter { available in | 228 | selectedPrinters[printerURLString]!.contactPrinter { available in |
211 | if !available { | 229 | if !available { |
212 | self.printing.onCompleted(printJob: self, completed: false, error: "Printer not available") | 230 | self.printing.onCompleted(printJob: self, completed: false, error: "Printer not available") |
@@ -328,6 +346,9 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | @@ -328,6 +346,9 @@ public class PrintJob: UIPrintPageRenderer, UIPrintInteractionControllerDelegate | ||
328 | "model": printer.makeAndModel as Any, | 346 | "model": printer.makeAndModel as Any, |
329 | "location": printer.displayLocation as Any, | 347 | "location": printer.displayLocation as Any, |
330 | ] | 348 | ] |
349 | + | ||
350 | + pickedPrinter = printer | ||
351 | + | ||
331 | result(data) | 352 | result(data) |
332 | } | 353 | } |
333 | 354 |
@@ -60,6 +60,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | @@ -60,6 +60,7 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | ||
60 | let marginBottom = CGFloat((args["marginBottom"] as! NSNumber).floatValue) | 60 | let marginBottom = CGFloat((args["marginBottom"] as! NSNumber).floatValue) |
61 | let printJob = PrintJob(printing: self, index: args["job"] as! Int) | 61 | let printJob = PrintJob(printing: self, index: args["job"] as! Int) |
62 | let dynamic = args["dynamic"] as! Bool | 62 | let dynamic = args["dynamic"] as! Bool |
63 | + let forceCustomPrintPaper = args["forceCustomPrintPaper"] as! Bool | ||
63 | 64 | ||
64 | let outputType: UIPrintInfo.OutputType | 65 | let outputType: UIPrintInfo.OutputType |
65 | switch args["outputType"] as! Int { | 66 | switch args["outputType"] as! Int { |
@@ -89,7 +90,8 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | @@ -89,7 +90,8 @@ public class PrintingPlugin: NSObject, FlutterPlugin { | ||
89 | ), | 90 | ), |
90 | withPrinter: printer, | 91 | withPrinter: printer, |
91 | dynamically: dynamic, | 92 | dynamically: dynamic, |
92 | - outputType: outputType) | 93 | + outputType: outputType, |
94 | + forceCustomPrintPaper: forceCustomPrintPaper) | ||
93 | result(NSNumber(value: 1)) | 95 | result(NSNumber(value: 1)) |
94 | } else if call.method == "sharePdf" { | 96 | } else if call.method == "sharePdf" { |
95 | let object = args["doc"] as! FlutterStandardTypedData | 97 | let object = args["doc"] as! FlutterStandardTypedData |
@@ -158,6 +158,7 @@ class PrintingPlugin extends PrintingPlatform { | @@ -158,6 +158,7 @@ class PrintingPlugin extends PrintingPlatform { | ||
158 | bool dynamicLayout, | 158 | bool dynamicLayout, |
159 | bool usePrinterSettings, | 159 | bool usePrinterSettings, |
160 | OutputType outputType, | 160 | OutputType outputType, |
161 | + bool forceCustomPrintPaper, | ||
161 | ) async { | 162 | ) async { |
162 | late Uint8List result; | 163 | late Uint8List result; |
163 | try { | 164 | try { |
@@ -68,6 +68,7 @@ abstract class PrintingPlatform extends PlatformInterface { | @@ -68,6 +68,7 @@ abstract class PrintingPlatform extends PlatformInterface { | ||
68 | bool dynamicLayout, | 68 | bool dynamicLayout, |
69 | bool usePrinterSettings, | 69 | bool usePrinterSettings, |
70 | OutputType outputType, | 70 | OutputType outputType, |
71 | + bool forceCustomPrintPaper, | ||
71 | ); | 72 | ); |
72 | 73 | ||
73 | /// Enumerate the available printers on the system. | 74 | /// Enumerate the available printers on the system. |
@@ -182,6 +182,7 @@ class MethodChannelPrinting extends PrintingPlatform { | @@ -182,6 +182,7 @@ class MethodChannelPrinting extends PrintingPlatform { | ||
182 | bool dynamicLayout, | 182 | bool dynamicLayout, |
183 | bool usePrinterSettings, | 183 | bool usePrinterSettings, |
184 | OutputType outputType, | 184 | OutputType outputType, |
185 | + bool forceCustomPrintPaper, | ||
185 | ) async { | 186 | ) async { |
186 | final job = _printJobs.add( | 187 | final job = _printJobs.add( |
187 | onCompleted: Completer<bool>(), | 188 | onCompleted: Completer<bool>(), |
@@ -201,6 +202,7 @@ class MethodChannelPrinting extends PrintingPlatform { | @@ -201,6 +202,7 @@ class MethodChannelPrinting extends PrintingPlatform { | ||
201 | 'dynamic': dynamicLayout, | 202 | 'dynamic': dynamicLayout, |
202 | 'usePrinterSettings': usePrinterSettings, | 203 | 'usePrinterSettings': usePrinterSettings, |
203 | 'outputType': outputType.index, | 204 | 'outputType': outputType.index, |
205 | + 'forceCustomPrintPaper': forceCustomPrintPaper, | ||
204 | }; | 206 | }; |
205 | 207 | ||
206 | await _channel.invokeMethod<int>('printPdf', params); | 208 | await _channel.invokeMethod<int>('printPdf', params); |
@@ -40,9 +40,15 @@ mixin Printing { | @@ -40,9 +40,15 @@ mixin Printing { | ||
40 | /// Set [usePrinterSettings] to true to use the configuration defined by | 40 | /// Set [usePrinterSettings] to true to use the configuration defined by |
41 | /// the printer. May not work for all the printers and can depend on the | 41 | /// the printer. May not work for all the printers and can depend on the |
42 | /// drivers. (Supported platforms: Windows) | 42 | /// drivers. (Supported platforms: Windows) |
43 | + /// | ||
43 | /// Set [outputType] to [OutputType.generic] to use the default printing | 44 | /// Set [outputType] to [OutputType.generic] to use the default printing |
44 | /// system, or [OutputType.photos] to use the photo printing system. | 45 | /// system, or [OutputType.photos] to use the photo printing system. |
45 | /// (Supported platforms: iOS) | 46 | /// (Supported platforms: iOS) |
47 | + /// | ||
48 | + /// Use [customPrintPaper] to force the printer to use a custom paper size. | ||
49 | + /// Use value `true` to use [format] as custom paper size, when the printer | ||
50 | + /// driver will not allows the user to use papers which are actually supported by the printer. | ||
51 | + /// (Supported platforms: iOS) | ||
46 | static Future<bool> layoutPdf({ | 52 | static Future<bool> layoutPdf({ |
47 | required LayoutCallback onLayout, | 53 | required LayoutCallback onLayout, |
48 | String name = 'Document', | 54 | String name = 'Document', |
@@ -50,6 +56,7 @@ mixin Printing { | @@ -50,6 +56,7 @@ mixin Printing { | ||
50 | bool dynamicLayout = true, | 56 | bool dynamicLayout = true, |
51 | bool usePrinterSettings = false, | 57 | bool usePrinterSettings = false, |
52 | OutputType outputType = OutputType.generic, | 58 | OutputType outputType = OutputType.generic, |
59 | + bool forceCustomPrintPaper = false, | ||
53 | }) { | 60 | }) { |
54 | return PrintingPlatform.instance.layoutPdf( | 61 | return PrintingPlatform.instance.layoutPdf( |
55 | null, | 62 | null, |
@@ -59,6 +66,7 @@ mixin Printing { | @@ -59,6 +66,7 @@ mixin Printing { | ||
59 | dynamicLayout, | 66 | dynamicLayout, |
60 | usePrinterSettings, | 67 | usePrinterSettings, |
61 | outputType, | 68 | outputType, |
69 | + forceCustomPrintPaper, | ||
62 | ); | 70 | ); |
63 | } | 71 | } |
64 | 72 | ||
@@ -138,6 +146,15 @@ mixin Printing { | @@ -138,6 +146,15 @@ mixin Printing { | ||
138 | /// Set [usePrinterSettings] to true to use the configuration defined by | 146 | /// Set [usePrinterSettings] to true to use the configuration defined by |
139 | /// the printer. May not work for all the printers and can depend on the | 147 | /// the printer. May not work for all the printers and can depend on the |
140 | /// drivers. (Supported platforms: Windows) | 148 | /// drivers. (Supported platforms: Windows) |
149 | + /// | ||
150 | + /// Set [outputType] to [OutputType.generic] to use the default printing | ||
151 | + /// system, or [OutputType.photos] to use the photo printing system. | ||
152 | + /// (Supported platforms: iOS) | ||
153 | + /// | ||
154 | + /// Use [customPrintPaper] to force the printer to use a custom paper size. | ||
155 | + /// Use value `true` to use [format] as custom paper size, when the printer | ||
156 | + /// driver will not allows the user to use papers which are actually supported by the printer. | ||
157 | + /// (Supported platforms: iOS) | ||
141 | static FutureOr<bool> directPrintPdf({ | 158 | static FutureOr<bool> directPrintPdf({ |
142 | required Printer printer, | 159 | required Printer printer, |
143 | required LayoutCallback onLayout, | 160 | required LayoutCallback onLayout, |
@@ -146,6 +163,7 @@ mixin Printing { | @@ -146,6 +163,7 @@ mixin Printing { | ||
146 | bool dynamicLayout = true, | 163 | bool dynamicLayout = true, |
147 | bool usePrinterSettings = false, | 164 | bool usePrinterSettings = false, |
148 | OutputType outputType = OutputType.generic, | 165 | OutputType outputType = OutputType.generic, |
166 | + bool forceCustomPrintPaper = false, | ||
149 | }) { | 167 | }) { |
150 | return PrintingPlatform.instance.layoutPdf( | 168 | return PrintingPlatform.instance.layoutPdf( |
151 | printer, | 169 | printer, |
@@ -155,6 +173,7 @@ mixin Printing { | @@ -155,6 +173,7 @@ mixin Printing { | ||
155 | dynamicLayout, | 173 | dynamicLayout, |
156 | usePrinterSettings, | 174 | usePrinterSettings, |
157 | outputType, | 175 | outputType, |
176 | + forceCustomPrintPaper, | ||
158 | ); | 177 | ); |
159 | } | 178 | } |
160 | 179 |
@@ -109,6 +109,7 @@ class MockPrinting extends Mock | @@ -109,6 +109,7 @@ class MockPrinting extends Mock | ||
109 | bool dynamicLayout, | 109 | bool dynamicLayout, |
110 | bool usePrinterSettings, | 110 | bool usePrinterSettings, |
111 | OutputType outputType, | 111 | OutputType outputType, |
112 | + bool forceCustomPrintPaper, | ||
112 | ) async => | 113 | ) async => |
113 | true; | 114 | true; |
114 | 115 |
-
Please register or login to post a comment