Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,47 @@
# PDFTron Flutter Sample
Flutter sample project that integrates a document viewer using [PDFTron Flutter](https://github.com/PDFTron/pdftron-flutter). Check out the [integration guides](https://www.pdftron.com/documentation/android/flutter) to learn how to add PDFTron to your Flutter App.
A Flutter sample project that integrates a document viewer using PDFTron Flutter.

PDFTron's Flutter PDF library now supports sound null safety and is available on [GitHub](https://github.com/PDFTron/pdftron-flutter) and [pub.dev](https://pub.dev/packages/pdftron_flutter). To learn how to add PDFTron to your Flutter App, check out the [integration guides](https://www.pdftron.com/documentation/guides/flutter).

## Preview

**Android** | **iOS**
:--:|:--:
<img alt='demo-android' src='assets/gifs/android.gif' height="600" /> | <img alt='demo-android' src='assets/gifs/ios.gif' height="600" />

## Step
## Installation

### Android
1. Create a `local.properties` file inside the android folder with your Android SDK location, for example:

```
sdk.dir=/Users/<user-name>/Library/Android/sdk
```

2. For iOS, run:
### iOS
1. For iOS, run:
```
cd ios
pod install
```

## Run

### Sample App

```
flutter run
```

### Test

```
flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart
```

## Upgrade

For updating flutter projects, please check out [here](https://flutter.dev/docs/development/tools/sdk/upgrading).
For updating flutter projects, please check out [Upgrading Flutter](https://flutter.dev/docs/development/tools/sdk/upgrading).

## License
See [License](./LICENSE)
Expand Down
103 changes: 79 additions & 24 deletions integration_test/app_test.dart
Original file line number Diff line number Diff line change
@@ -1,36 +1,91 @@
// This is a basic Flutter integration test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_sample/thumbnail.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

import 'package:flutter_sample/main.dart' as app;
import 'package:pdftron_flutter/pdftron_flutter.dart';

// Test for the sample app.
void main() async {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
List<String> calls = <String>[];

setUpAll(() async {
// Used to track method calls.
MethodChannel('pdftron_flutter').setMockMethodCallHandler( (MethodCall call) async {
calls.add(call.method);
});
});

tearDown(() {
// Clears list after each test.
calls.clear();
});

// Destroys the method call tracker after all tests have ran.
tearDownAll(() async {
MethodChannel('pdftron_flutter').setMockMethodCallHandler(null);
});

testWidgets('Check widget hierarchy of app', (WidgetTester tester) async {
Widget myApp = app.MyApp();
await tester.pumpWidget(myApp);

void main() => run(_testMain);
expect(find.text("PDFTron Flutter Sample"), findsOneWidget);

final bodyFinder = find.byKey(Key('body'));
expect(bodyFinder, findsOneWidget);

// Body widget is SafeArea type if app is initialized and storage is permitted.
final body = tester.firstWidget(bodyFinder);
if (body is SafeArea) {
final inkWellFinder = find.descendant(of: bodyFinder, matching: find.byType(InkWell));
expect(inkWellFinder, findsWidgets);

void _testMain() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
app.main();
final imageFinder = find.descendant(of: inkWellFinder.first, matching: find.byType(Image));
expect(imageFinder, findsOneWidget);

// Trigger a frame.
await tester.pumpAndSettle();
} else {
// Body widget is Container type if app is not initialized or storage is not permitted.
expect(body.runtimeType, Container);

final alignFinder = find.descendant(of: bodyFinder, matching: find.byType(Align));
expect(alignFinder, findsOneWidget);

// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
final textFinder = find.descendant(of: alignFinder, matching: find.byType(Text));
expect(textFinder, findsOneWidget);

// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
Text text = tester.firstWidget<Text>(textFinder);
assert(text.data == 'Storage permission required.' || text.data == 'PDFTron SDK not initialized.');

// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
expect(find.byType(Text), findsNWidgets(2));
}
});

testWidgets("Opening Thumbnail", (WidgetTester tester) async {
await tester.runAsync(() async {
await tester.pumpWidget(app.MyApp());
await tester.pump();
expect(find.byType(InkWell), findsWidgets);

// Chooses a random thumbnail to select.
Random rng = Random();

// 6 is used instead of thumbnailList.length as that is the number of thumbnails visible upon loading.
int index = rng.nextInt(6);
Finder thumbnail = find.byKey(ValueKey(thumbnailList[index].documentUrl));

// Opens the selected thumbnail.
await tester.tap(thumbnail);
await tester.pump();

// Tests to ensure that the PdftronFlutter method were called.
await Future.delayed(Duration(seconds: 2), () async {
expect(calls.contains(Functions.openDocument), true);
});
});
}, variant: TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
}

8 changes: 0 additions & 8 deletions integration_test/driver.dart

This file was deleted.

12 changes: 6 additions & 6 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ PODS:
- Flutter (1.0.0)
- integration_test (0.0.1):
- Flutter
- PDFNet (8.1.0.76833)
- PDFNet (9.0.1.77780)
- pdftron_flutter (0.0.1):
- Flutter
- PDFNet
- permission_handler (3.0.1):
- "permission_handler (5.1.0+2)":
- Flutter

DEPENDENCIES:
Expand All @@ -31,10 +31,10 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
integration_test: 6eb66a19f7104200dcfdd62bc0077e1b09686e4f
PDFNet: 248e57518524fdbb47970216c2db3522e4f51028
PDFNet: b9e7a7831af4020a4835e19ecf6abf9b81ce29a4
pdftron_flutter: 32bd96e9bc9254c1861f17725e40dd611a7056cd
permission_handler: 6e56ded745f5a0b9dcc0327c65c4acd6a33b776b
permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0

PODFILE CHECKSUM: c3dd2ce4973c59b1eed0b8fefd9e24700fcd3376
PODFILE CHECKSUM: 1256ed743e0e6641e71d5339a76d03b9e411be9b

COCOAPODS: 1.9.3
COCOAPODS: 1.10.1
78 changes: 35 additions & 43 deletions ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
7D9D4596AFE603889D0C4AF9 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 156D97EE3B349FF3B0506A4B /* Pods_Runner.framework */; };
943B166731AF29A54E1E56A7 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 204000B1A7320C6A866AAD69 /* Pods_Runner.framework */; };
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 */; };
Expand All @@ -33,44 +33,55 @@
/* 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>"; };
156D97EE3B349FF3B0506A4B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
26A290795C8B345E7B54F3D8 /* 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>"; };
204000B1A7320C6A866AAD69 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
2BE6492F675995FD34402DF3 /* 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>"; };
3BDFDD4EE7D4A48E6F1023CD /* 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>"; };
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>"; };
8C7015EC7AC266049F570AC8 /* 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>"; };
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>"; };
978AC9E7D689FE7A1CC725C4 /* 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>"; };
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>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A318E888EA367D38A42C1330 /* 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>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7D9D4596AFE603889D0C4AF9 /* Pods_Runner.framework in Frameworks */,
943B166731AF29A54E1E56A7 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
526543B57B076E700259821D /* Frameworks */ = {
144481D43B8FD6BABC279BD2 /* Frameworks */ = {
isa = PBXGroup;
children = (
156D97EE3B349FF3B0506A4B /* Pods_Runner.framework */,
204000B1A7320C6A866AAD69 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
68FFF092814E7FD8BDE5D113 /* Pods */ = {
isa = PBXGroup;
children = (
2BE6492F675995FD34402DF3 /* Pods-Runner.debug.xcconfig */,
8C7015EC7AC266049F570AC8 /* Pods-Runner.release.xcconfig */,
A318E888EA367D38A42C1330 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
Expand All @@ -88,8 +99,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
B73FC6430D1564515ACDA0A8 /* Pods */,
526543B57B076E700259821D /* Frameworks */,
68FFF092814E7FD8BDE5D113 /* Pods */,
144481D43B8FD6BABC279BD2 /* Frameworks */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -125,33 +136,22 @@
name = "Supporting Files";
sourceTree = "<group>";
};
B73FC6430D1564515ACDA0A8 /* Pods */ = {
isa = PBXGroup;
children = (
978AC9E7D689FE7A1CC725C4 /* Pods-Runner.debug.xcconfig */,
3BDFDD4EE7D4A48E6F1023CD /* Pods-Runner.release.xcconfig */,
26A290795C8B345E7B54F3D8 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
828B385D0F4ED6C1571E5C5F /* [CP] Check Pods Manifest.lock */,
428ABE4C58A2A019489A3B39 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
9F87D447099B0ED1C64C936E /* [CP] Embed Pods Frameworks */,
69F2FFE7873B2C24CBEDA23A /* [CP] Copy Pods Resources */,
FB76715B0EFF3C89AFE1FCBA /* [CP] Embed Pods Frameworks */,
4243294FAA000FD34AB76E5C /* [CP] Copy Pods Resources */,
);
buildRules = (
);
Expand Down Expand Up @@ -223,25 +223,24 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
69F2FFE7873B2C24CBEDA23A /* [CP] Copy Pods Resources */ = {
4243294FAA000FD34AB76E5C /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
"${PODS_ROOT}/PDFNet/Tools-Localization",
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Tools-Localization",
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
828B385D0F4ED6C1571E5C5F /* [CP] Check Pods Manifest.lock */ = {
428ABE4C58A2A019489A3B39 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
Expand Down Expand Up @@ -277,24 +276,17 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
9F87D447099B0ED1C64C936E /* [CP] Embed Pods Frameworks */ = {
FB76715B0EFF3C89AFE1FCBA /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/PDFNet/PDFNet.framework",
"${PODS_ROOT}/PDFNet/Tools.framework",
"${BUILT_PRODUCTS_DIR}/integration_test/integration_test.framework",
"${BUILT_PRODUCTS_DIR}/pdftron_flutter/pdftron_flutter.framework",
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PDFNet.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Tools.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/integration_test.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/pdftron_flutter.framework",
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading