David PHAM-VAN

Convert objective-c code to swift

... ... @@ -14,6 +14,7 @@
DART_SRC=$(shell find . -name '*.dart')
CLNG_SRC=$(shell find printing/ios -name '*.java' -o -name '*.m' -o -name '*.h') $(shell find printing/android -name '*.java' -o -name '*.m' -o -name '*.h')
SWFT_SRC=$(shell find . -name '*.swift')
FONTS=pdf/open-sans.ttf pdf/roboto.ttf
all: $(FONTS) format
... ... @@ -24,7 +25,7 @@ pdf/open-sans.ttf:
pdf/roboto.ttf:
curl -L "https://github.com/google/fonts/raw/master/apache/robotomono/RobotoMono-Regular.ttf" > $@
format: format-dart format-clang
format: format-dart format-clang format-swift
format-dart: $(DART_SRC)
dartfmt -w --fix $^
... ... @@ -32,6 +33,9 @@ format-dart: $(DART_SRC)
format-clang: $(CLNG_SRC)
clang-format -style=Chromium -i $^
format-swift: $(SWFT_SRC)
swiftformat --swiftversion 4.2 $^
pdf/.dart_tool:
cd pdf ; pub get
... ...
... ... @@ -2,6 +2,7 @@
* Fix dart lint warnings
* Add documentation
* Add a filename parameter for sharing
* Convert Objective-C code to Swift
# 1.3.3
* Update Readme
... ...
... ... @@ -8,7 +8,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
... ... @@ -22,7 +22,7 @@ rootProject.allprojects {
apply plugin: 'com.android.library'
android {
compileSdkVersion 26
compileSdkVersion 28
defaultConfig {
minSdkVersion 19
... ...
... ... @@ -11,14 +11,13 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
669503AD9820A2FB8EB7D135 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 438EF44EBD2180BA9FEB6DD7 /* libPods-Runner.a */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
E8DE9257AFBCBC1504A2E8B5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E9F8451991F067F1B35AD2E /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
... ... @@ -39,17 +38,19 @@
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
1E8FFA8481E6F7C0861A5633 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
36CCD35B2CCD6DA63F3BB856 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
438EF44EBD2180BA9FEB6DD7 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
3E9F8451991F067F1B35AD2E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
64E6F026FD235CE443A8B399 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
... ... @@ -63,18 +64,21 @@
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
669503AD9820A2FB8EB7D135 /* libPods-Runner.a in Frameworks */,
E8DE9257AFBCBC1504A2E8B5 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
2BF041FD892A0BC85D754ACF /* Pods */ = {
55188E0E9477620B487B3E3D /* Pods */ = {
isa = PBXGroup;
children = (
36CCD35B2CCD6DA63F3BB856 /* Pods-Runner.debug.xcconfig */,
64E6F026FD235CE443A8B399 /* Pods-Runner.release.xcconfig */,
1E8FFA8481E6F7C0861A5633 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
... ... @@ -96,8 +100,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
2BF041FD892A0BC85D754ACF /* Pods */,
A68417D4692CD8722C677E29 /* Frameworks */,
55188E0E9477620B487B3E3D /* Pods */,
A068841E0B33BBCDB05C8960 /* Frameworks */,
);
sourceTree = "<group>";
};
... ... @@ -112,8 +116,6 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
... ... @@ -121,6 +123,8 @@
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
... ... @@ -128,15 +132,14 @@
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
97C146F21CF9000F007C117D /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
A68417D4692CD8722C677E29 /* Frameworks */ = {
A068841E0B33BBCDB05C8960 /* Frameworks */ = {
isa = PBXGroup;
children = (
438EF44EBD2180BA9FEB6DD7 /* libPods-Runner.a */,
3E9F8451991F067F1B35AD2E /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
... ... @@ -148,14 +151,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
4DD8C990B54E5CD60DA09BAD /* [CP] Check Pods Manifest.lock */,
1823E53487662DB3F45BAC31 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
770C3FAAF999833574938C52 /* [CP] Embed Pods Frameworks */,
27917B59DB58561F8D7C1998 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
... ... @@ -177,6 +180,7 @@
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1010;
};
};
};
... ... @@ -213,21 +217,7 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
4DD8C990B54E5CD60DA09BAD /* [CP] Check Pods Manifest.lock */ = {
1823E53487662DB3F45BAC31 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
... ... @@ -249,7 +239,7 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
770C3FAAF999833574938C52 /* [CP] Embed Pods Frameworks */ = {
27917B59DB58561F8D7C1998 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
... ... @@ -257,20 +247,36 @@
inputFileListPaths = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/printing/printing.framework",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
);
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/printing.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
... ... @@ -292,8 +298,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
... ... @@ -388,8 +393,9 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_BUNDLE_IDENTIFIER = net.nfet.flutter.printingExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.2;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
... ... @@ -495,6 +501,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
... ... @@ -505,6 +512,7 @@
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
... ... @@ -517,8 +525,11 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_BUNDLE_IDENTIFIER = net.nfet.flutter.printingExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.2;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
... ... @@ -528,6 +539,7 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
... ... @@ -540,8 +552,10 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_BUNDLE_IDENTIFIER = net.nfet.flutter.printingExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 4.2;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
... ...
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
import Flutter
import UIKit
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
... ...
#import "GeneratedPluginRegistrant.h"
\ No newline at end of file
... ...
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Flutter/Flutter.h>
@interface PdfPrintPageRenderer : UIPrintPageRenderer
- (instancetype)init:(FlutterMethodChannel*)channel;
- (void)drawPageAtIndex:(NSInteger)pageIndex inRect:(CGRect)printableRect;
- (void)setDocument:(NSData*)data;
@property(nonatomic, readonly) NSInteger numberOfPages;
@end
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "PageRenderer.h"
@implementation PdfPrintPageRenderer {
FlutterMethodChannel* channel;
CGPDFDocumentRef pdfDocument;
NSLock* lock;
}
- (instancetype)init:(FlutterMethodChannel*)channel {
self = [super init];
self->channel = channel;
self->lock = [[NSLock alloc] init];
self->pdfDocument = nil;
return self;
}
- (void)dealloc {
if (self->pdfDocument != nil) {
CGPDFDocumentRelease(self->pdfDocument);
}
}
- (NSInteger)numberOfPages {
NSNumber* width = [[NSNumber alloc] initWithDouble:self.paperRect.size.width];
NSNumber* height =
[[NSNumber alloc] initWithDouble:self.paperRect.size.height];
NSNumber* marginLeft =
[[NSNumber alloc] initWithDouble:self.printableRect.origin.x];
NSNumber* marginTop =
[[NSNumber alloc] initWithDouble:self.printableRect.origin.y];
NSNumber* marginRight =
[[NSNumber alloc] initWithDouble:self.paperRect.size.width -
(self.printableRect.origin.x +
self.printableRect.size.width)];
NSNumber* marginBottom =
[[NSNumber alloc] initWithDouble:self.paperRect.size.height -
(self.printableRect.origin.y +
self.printableRect.size.height)];
NSDictionary* arg = @{
@"width" : width,
@"height" : height,
@"marginLeft" : marginLeft,
@"marginTop" : marginTop,
@"marginRight" : marginRight,
@"marginBottom" : marginBottom,
};
[lock lock];
[channel invokeMethod:@"onLayout" arguments:arg];
[lock lock];
[lock unlock];
size_t pages = CGPDFDocumentGetNumberOfPages(pdfDocument);
return pages;
}
- (void)drawPageAtIndex:(NSInteger)pageIndex inRect:(CGRect)printableRect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGPDFPageRef page = CGPDFDocumentGetPage(pdfDocument, pageIndex + 1);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextTranslateCTM(ctx, 0.0, -self.paperRect.size.height);
CGContextDrawPDFPage(ctx, page);
}
void dataProviderReleaseDataCallback(void* info,
const void* data,
size_t size) {
free((void*)data);
}
- (void)setDocument:(NSData*)data {
void* buffer = malloc(data.length);
memcpy(buffer, data.bytes, data.length);
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(
NULL, buffer, data.length, dataProviderReleaseDataCallback);
if (pdfDocument != nil) {
CGPDFDocumentRelease(pdfDocument);
pdfDocument = nil;
}
pdfDocument = CGPDFDocumentCreateWithProvider(dataProvider);
CGDataProviderRelease(dataProvider);
[lock unlock];
}
@end
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Flutter
func dataProviderReleaseDataCallback(info _: UnsafeMutableRawPointer?, data: UnsafeRawPointer, size _: Int) {
data.deallocate()
}
class PdfPrintPageRenderer: UIPrintPageRenderer {
private var channel: FlutterMethodChannel?
private var pdfDocument: CGPDFDocument?
private var lock: NSLock?
init(_ channel: FlutterMethodChannel?) {
super.init()
self.channel = channel
lock = NSLock()
pdfDocument = nil
}
override func drawPage(at pageIndex: Int, in _: CGRect) {
let ctx = UIGraphicsGetCurrentContext()
let page = pdfDocument?.page(at: pageIndex + 1)
ctx?.scaleBy(x: 1.0, y: -1.0)
ctx?.translateBy(x: 0.0, y: -paperRect.size.height)
ctx?.drawPDFPage(page!)
}
func setDocument(_ data: Data?) {
let bytesPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: data?.count ?? 0)
data?.copyBytes(to: bytesPointer, count: data?.count ?? 0)
let dataProvider = CGDataProvider(dataInfo: nil, data: bytesPointer, size: data?.count ?? 0, releaseData: dataProviderReleaseDataCallback)
pdfDocument = CGPDFDocument(dataProvider!)
lock?.unlock()
}
override var numberOfPages: Int {
let width = NSNumber(value: Double(paperRect.size.width))
let height = NSNumber(value: Double(paperRect.size.height))
let marginLeft = NSNumber(value: Double(printableRect.origin.x))
let marginTop = NSNumber(value: Double(printableRect.origin.y))
let marginRight = NSNumber(value: Double(paperRect.size.width - (printableRect.origin.x + printableRect.size.width)))
let marginBottom = NSNumber(value: Double(paperRect.size.height - (printableRect.origin.y + printableRect.size.height)))
let arg = [
"width": width,
"height": height,
"marginLeft": marginLeft,
"marginTop": marginTop,
"marginRight": marginRight,
"marginBottom": marginBottom,
]
lock?.lock()
channel?.invokeMethod("onLayout", arguments: arg)
lock?.lock()
lock?.unlock()
let pages = pdfDocument?.numberOfPages ?? 0
return pages
}
}
... ...
... ... @@ -16,8 +16,5 @@
#import <Flutter/Flutter.h>
@interface PrintingPlugin
: NSObject <FlutterPlugin, UIPrintInteractionControllerDelegate>
- (instancetype)init:(FlutterMethodChannel*)channel;
@interface PrintingPlugin : NSObject <FlutterPlugin>
@end
... ...
... ... @@ -15,133 +15,10 @@
*/
#import "PrintingPlugin.h"
#import "PageRenderer.h"
@implementation PrintingPlugin {
FlutterMethodChannel* channel;
PdfPrintPageRenderer* renderer;
}
#import <printing/printing-Swift.h>
@implementation PrintingPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel =
[FlutterMethodChannel methodChannelWithName:@"printing"
binaryMessenger:[registrar messenger]];
PrintingPlugin* instance = [[PrintingPlugin alloc] init:channel];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (instancetype)init:(FlutterMethodChannel*)channel {
self = [super init];
self->channel = channel;
self->renderer = nil;
return self;
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"printPdf" isEqualToString:call.method]) {
[self printPdf:[call.arguments objectForKey:@"name"]];
result(@1);
} else if ([@"writePdf" isEqualToString:call.method]) {
[self writePdf:[call.arguments objectForKey:@"doc"]];
result(@1);
} else if ([@"sharePdf" isEqualToString:call.method]) {
[self sharePdf:[call.arguments objectForKey:@"doc"]
withSourceRect:CGRectMake(
[[call.arguments objectForKey:@"x"] floatValue],
[[call.arguments objectForKey:@"y"] floatValue],
[[call.arguments objectForKey:@"w"] floatValue],
[[call.arguments objectForKey:@"h"] floatValue])
andName:[call.arguments objectForKey:@"name"]];
result(@1);
} else {
result(FlutterMethodNotImplemented);
}
[SwiftPrintingPlugin registerWithRegistrar:registrar];
}
- (void)printPdf:(nonnull NSString*)name {
BOOL printing = [UIPrintInteractionController isPrintingAvailable];
if (!printing) {
NSLog(@"printing not available");
return;
}
UIPrintInteractionController* controller =
[UIPrintInteractionController sharedPrintController];
[controller setDelegate:self];
UIPrintInfo* printInfo = [UIPrintInfo printInfo];
printInfo.jobName = name;
printInfo.outputType = UIPrintInfoOutputGeneral;
controller.printInfo = printInfo;
renderer = [[PdfPrintPageRenderer alloc] init:channel];
[controller setPrintPageRenderer:renderer];
UIPrintInteractionCompletionHandler completionHandler =
^(UIPrintInteractionController* printController, BOOL completed,
NSError* error) {
if (!completed && error) {
NSLog(@"FAILED! due to error in domain %@ with error code %u",
error.domain, (unsigned int)error.code);
}
self->renderer = nil;
};
[controller presentAnimated:YES completionHandler:completionHandler];
}
- (void)writePdf:(nonnull FlutterStandardTypedData*)data {
[renderer setDocument:data.data];
}
- (void)sharePdf:(nonnull FlutterStandardTypedData*)data
withSourceRect:(CGRect)rect
andName:(NSString*)name {
NSURL* tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory()
isDirectory:YES];
CFUUIDRef uuid = CFUUIDCreate(NULL);
assert(uuid != nil);
CFStringRef uuidStr = CFUUIDCreateString(NULL, uuid);
assert(uuidStr != nil);
NSURL* fileURL;
if ([name isEqual:[NSNull null]]) {
fileURL = [[tmpDirURL
URLByAppendingPathComponent:[NSString stringWithFormat:@"document-%@",
uuidStr]]
URLByAppendingPathExtension:@"pdf"];
} else {
fileURL = [tmpDirURL URLByAppendingPathComponent:name];
}
assert(fileURL != nil);
CFRelease(uuidStr);
CFRelease(uuid);
NSString* path = [fileURL path];
NSError* error;
if (![[data data] writeToFile:path
options:NSDataWritingAtomic
error:&error]) {
NSLog(@"sharePdf error: %@", [error localizedDescription]);
return;
}
UIActivityViewController* activityViewController =
[[UIActivityViewController alloc] initWithActivityItems:@[ fileURL ]
applicationActivities:nil];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
UIViewController* controller =
[UIApplication sharedApplication].keyWindow.rootViewController;
activityViewController.popoverPresentationController.sourceView =
controller.view;
activityViewController.popoverPresentationController.sourceRect = rect;
}
[[UIApplication sharedApplication].keyWindow.rootViewController
presentViewController:activityViewController
animated:YES
completion:nil];
}
@end
... ...
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Flutter
import UIKit
public class SwiftPrintingPlugin: NSObject, FlutterPlugin, UIPrintInteractionControllerDelegate {
private var channel: FlutterMethodChannel?
private var renderer: PdfPrintPageRenderer?
init(_ channel: FlutterMethodChannel?) {
super.init()
self.channel = channel
renderer = nil
}
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "printing", binaryMessenger: registrar.messenger())
let instance = SwiftPrintingPlugin(channel)
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: FlutterResult) {
let args = call.arguments! as! [String: Any]
if "printPdf" == call.method {
printPdf(args["name"] as? String ?? "")
result(NSNumber(value: 1))
} else if "writePdf" == call.method {
if let object = args["doc"] as? FlutterStandardTypedData {
writePdf(object)
}
result(NSNumber(value: 1))
} else if "sharePdf" == call.method {
if let object = args["doc"] as? FlutterStandardTypedData {
sharePdf(
object,
withSourceRect: CGRect(x: CGFloat((args["x"] as? NSNumber)?.floatValue ?? 0.0), y: CGFloat((args["y"] as? NSNumber)?.floatValue ?? 0.0), width: CGFloat((args["w"] as? NSNumber)?.floatValue ?? 0.0), height: CGFloat((args["h"] as? NSNumber)?.floatValue ?? 0.0)),
andName: args["name"] as? String
)
}
result(NSNumber(value: 1))
} else {
result(FlutterMethodNotImplemented)
}
}
func completionHandler(printController _: UIPrintInteractionController, completed: Bool, error: Error?) {
if !completed, error != nil {
print("Unable to print: \(error?.localizedDescription ?? "unknown error")")
}
renderer = nil
}
func printPdf(_ name: String) {
let printing = UIPrintInteractionController.isPrintingAvailable
if !printing {
print("printing not available")
return
}
let controller = UIPrintInteractionController.shared
controller.delegate = self
let printInfo = UIPrintInfo.printInfo()
printInfo.jobName = name
printInfo.outputType = .general
controller.printInfo = printInfo
renderer = PdfPrintPageRenderer(channel)
controller.printPageRenderer = renderer
controller.present(animated: true, completionHandler: completionHandler)
}
func writePdf(_ data: FlutterStandardTypedData) {
renderer?.setDocument(data.data)
}
func sharePdf(_ data: FlutterStandardTypedData, withSourceRect rect: CGRect, andName name: String?) {
let tmpDirURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let uuid = CFUUIDCreate(nil)
assert(uuid != nil)
let uuidStr = CFUUIDCreateString(nil, uuid)
assert(uuidStr != nil)
var fileURL: URL
if name == nil {
fileURL = tmpDirURL.appendingPathComponent("document-\(uuidStr ?? "1" as CFString)").appendingPathExtension("pdf")
} else {
fileURL = tmpDirURL.appendingPathComponent(name!)
}
do {
try data.data.write(to: fileURL, options: .atomic)
} catch {
print("sharePdf error: \(error.localizedDescription)")
return
}
let activityViewController = UIActivityViewController(activityItems: [fileURL], applicationActivities: nil)
if UI_USER_INTERFACE_IDIOM() == .pad {
let controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController
activityViewController.popoverPresentationController?.sourceView = controller?.view
activityViewController.popoverPresentationController?.sourceRect = rect
}
UIApplication.shared.keyWindow?.rootViewController?.present(activityViewController, animated: true)
}
}
... ...
... ... @@ -12,6 +12,10 @@ dependencies:
sdk: flutter
pdf: "^1.3.0"
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
plugin:
androidPackage: net.nfet.flutter.printing
... ...