Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6e7f572
Basic iOS implementation
spesholized Apr 27, 2022
b4e8697
Merge branch 'flutter:main' into main
spesholized Apr 28, 2022
75a1bdc
[file_selector] Basic iOS implementation
spesholized Apr 27, 2022
15f2741
Merge branch 'main' of https://github.com/spesholized/plugins
spesholized Apr 28, 2022
62c60cb
Fix formatting and update environment sdk version
spesholized Apr 28, 2022
696cb78
Basic native unit test for plugin
spesholized Apr 29, 2022
11504f4
Update packages/file_selector/file_selector_ios/example/ios/Runner.xc…
spesholized May 2, 2022
252e110
Add placeholder integration test
spesholized May 3, 2022
cb76a80
Remove unused overrides in file_selector_ios.dart, update pubspec
spesholized May 25, 2022
ecfad9a
Use pigeon, fix Obj-C prefix typo
spesholized May 26, 2022
4ecda0e
Add native unit tests
spesholized May 27, 2022
2a69911
Update tests to use pigeon, change prefix to FFS, update wildcard typ…
spesholized Aug 2, 2022
38742a3
Use non-null properties in messages.dart, use objc associated for the…
spesholized Aug 2, 2022
ec291b6
Merge branch 'main' into file_selector_ios
stuartmorgan-g Aug 19, 2022
f0bbcf1
Remove local analysis options
stuartmorgan-g Aug 19, 2022
edc2881
Resync examples and tweak UTIs
stuartmorgan-g Aug 19, 2022
e521edc
Analysis fixes
stuartmorgan-g Aug 19, 2022
eabcce5
Autoformat
stuartmorgan-g Aug 19, 2022
d39d953
Missing copyright header
stuartmorgan-g Aug 19, 2022
170c260
Supress deprecation warning on legacy codepath
stuartmorgan-g Aug 19, 2022
129a097
Review comments
stuartmorgan-g Aug 21, 2022
0cfa61c
Format
stuartmorgan-g Aug 22, 2022
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
Prev Previous commit
Next Next commit
Add native unit tests
  • Loading branch information
spesholized committed May 27, 2022
commit 4ecda0e474e81239ff541246a56edc11c4ffe7bb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '11.0'
platform :ios, '11.0'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this 11 rather than 9 (and commented out)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly don't remember. It's reverted back to default (and commented out) now and I'm not seeing any issues.


# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
Expand Down Expand Up @@ -34,6 +34,8 @@ target 'Runner' do
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
# Pods for testing
pod 'OCMock', '~> 3.8.1'
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@
C71AE4B2281C6A090086307A /* Sources */,
C71AE4B3281C6A090086307A /* Frameworks */,
C71AE4B4281C6A090086307A /* Resources */,
5BE5886DAAA885227DE0796D /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
Expand Down Expand Up @@ -282,6 +283,23 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
5BE5886DAAA885227DE0796D /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,115 @@
// found in the LICENSE file.

@import file_selector_ios;
@import file_selector_ios.Test;
@import XCTest;

#import <OCMock/OCMock.h>

@interface FileSelectorTests : XCTestCase

@end

@implementation FileSelectorTests

- (void)testPlugin {
FTLFileSelectorPlugin *plugin = [[FTLFileSelectorPlugin alloc] init];
XCTAssertNotNil(plugin);
- (void)testPickerPresents {
FLTFileSelectorPlugin *plugin = [[FLTFileSelectorPlugin alloc] init];
UIDocumentPickerViewController *picker =
[[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[]
inMode:UIDocumentPickerModeImport];
id mockPresentingVC = OCMClassMock([UIViewController class]);
plugin.documentPickerViewControllerOverride = picker;
plugin.presentingViewControllerOverride = mockPresentingVC;

[plugin openFileSelectorWithConfig:[FLTFileSelectorConfig makeWithUtis:nil
allowMultiSelection:@NO]
completion:^(NSArray<NSString *> *paths, FlutterError *error){
}];

XCTAssertEqualObjects(picker.delegate, plugin);
OCMVerify(times(1), [mockPresentingVC presentViewController:picker
animated:[OCMArg any]
completion:[OCMArg any]]);
}

- (void)testReturnsPickedFiles {
FLTFileSelectorPlugin *plugin = [[FLTFileSelectorPlugin alloc] init];
XCTestExpectation *completionWasCalled = [[XCTestExpectation alloc] init];
UIDocumentPickerViewController *picker =
[[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[]
inMode:UIDocumentPickerModeImport];
[plugin openFileSelectorWithConfig:[FLTFileSelectorConfig makeWithUtis:nil
allowMultiSelection:@YES]
completion:^(NSArray<NSString *> *paths, FlutterError *error) {
NSArray *expectedPaths = @[ @"/file1.txt", @"/file2.txt" ];
XCTAssertEqualObjects(paths, expectedPaths);
[completionWasCalled fulfill];
}];
[plugin documentPicker:picker
didPickDocumentsAtURLs:@[
[NSURL URLWithString:@"file:///file1.txt"], [NSURL URLWithString:@"file:///file2.txt"]
]];
[self waitForExpectations:@[ completionWasCalled ] timeout:1.0];
XCTAssertNil(plugin.pendingCompletion);
}

- (void)testReturnsPickedFileLegacy {
// Tests that it handles the pre iOS 11 UIDocumentPickerDelegate method.
FLTFileSelectorPlugin *plugin = [[FLTFileSelectorPlugin alloc] init];
XCTestExpectation *completionWasCalled = [[XCTestExpectation alloc] init];
UIDocumentPickerViewController *picker =
[[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[]
inMode:UIDocumentPickerModeImport];
plugin.documentPickerViewControllerOverride = picker;
[plugin openFileSelectorWithConfig:[FLTFileSelectorConfig makeWithUtis:nil
allowMultiSelection:@NO]
completion:^(NSArray<NSString *> *paths, FlutterError *error) {
NSArray *expectedPaths = @[ @"/file1.txt" ];
XCTAssertEqualObjects(paths, expectedPaths);
[completionWasCalled fulfill];
}];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
[plugin documentPicker:picker didPickDocumentAtURL:[NSURL URLWithString:@"file:///file1.txt"]];
#pragma GCC diagnostic pop
[self waitForExpectations:@[ completionWasCalled ] timeout:1.0];
XCTAssertNil(plugin.pendingCompletion);
}

- (void)testCancellingPickerReturnsNil {
FLTFileSelectorPlugin *plugin = [[FLTFileSelectorPlugin alloc] init];
UIDocumentPickerViewController *picker =
[[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[]
inMode:UIDocumentPickerModeImport];
plugin.documentPickerViewControllerOverride = picker;

XCTestExpectation *completionWasCalled = [[XCTestExpectation alloc] init];
[plugin openFileSelectorWithConfig:[FLTFileSelectorConfig makeWithUtis:nil
allowMultiSelection:@NO]
completion:^(NSArray<NSString *> *paths, FlutterError *error) {
XCTAssertEqual(paths.count, 0);
[completionWasCalled fulfill];
}];
[plugin documentPickerWasCancelled:picker];
[self waitForExpectations:@[ completionWasCalled ] timeout:1.0];
XCTAssertNil(plugin.pendingCompletion);
}

- (void)testOpenFileSelectorWithPendingCompletionReturnsError {
FLTFileSelectorPlugin *plugin = [[FLTFileSelectorPlugin alloc] init];
plugin.pendingCompletion = ^(NSArray<NSString *> *paths, FlutterError *error) {
};

XCTestExpectation *completionWasCalled =
[[XCTestExpectation alloc] initWithDescription:@"Completion was called"];
[plugin openFileSelectorWithConfig:[FLTFileSelectorConfig makeWithUtis:nil
allowMultiSelection:@NO]
completion:^(NSArray<NSString *> *paths, FlutterError *error) {
XCTAssertNotNil(error);
[completionWasCalled fulfill];
}];

[self waitForExpectations:@[ completionWasCalled ] timeout:1.0];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,9 @@
// found in the LICENSE file.

#import "FLTFileSelectorPlugin.h"
#import "FLTFileSelectorPlugin_Test.h"
#import "messages.g.h"

@interface FLTFileSelectorPlugin () <UIDocumentPickerDelegate, FLTFileSelectorApi>

/**
* The completion block of a FLTFileSelectorApi request.
* It is saved and invoked later in a UIDocumentPickerDelegate method.
*/
@property(nonatomic) void (^pendingCompletion)(NSArray<NSString *> * _Nullable,
FlutterError * _Nullable);

@end

@implementation FLTFileSelectorPlugin

#pragma mark - FLTFileSelectorApi
Expand All @@ -30,17 +20,18 @@ - (void)openFileSelectorWithConfig:(FLTFileSelectorConfig *)config
return;
}

UIDocumentPickerViewController *documentPicker =
UIDocumentPickerViewController *documentPicker = self.documentPickerViewControllerOverride ?:
[[UIDocumentPickerViewController alloc] initWithDocumentTypes:config.utis
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to clang-format all of the ObjC files (or just run the repo tooling format command on the whole package).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

inMode:UIDocumentPickerModeImport];
documentPicker.delegate = self;
if (@available(iOS 11.0, *)) {
documentPicker.allowsMultipleSelection = config.allowMultiSelection.boolValue;
}

UIViewController *rootVC = UIApplication.sharedApplication.delegate.window.rootViewController;
if (rootVC) {
[rootVC presentViewController:documentPicker animated:YES completion:nil];
UIViewController *presentingVC = self.presentingViewControllerOverride ?:
UIApplication.sharedApplication.delegate.window.rootViewController;
if (presentingVC) {
[presentingVC presentViewController:documentPicker animated:YES completion:nil];
self.pendingCompletion = completion;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are creating the document picker in this method, and you get it in all of the callbacks, I believe you could avoid the need for the singleton state by using associated objects. (I looked at doing this in image_picker, but the callbacks don't work the same way unfortunately).

(That would eliminate the cleanup duplication/fragility issue raised below.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

} else {
completion(nil, [FlutterError errorWithCode:@"error"
Expand All @@ -60,6 +51,7 @@ + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {

- (void)documentPicker:(UIDocumentPickerViewController *)controller
didPickDocumentAtURL:(NSURL *)url {
// This method is only called in iOS < 11.0.
if (self.pendingCompletion) {
self.pendingCompletion(@[ url.path ], nil);
self.pendingCompletion = nil;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than have three copies of this logic, please make a small helper (to reduce the chance of any future changes only doing the first step but not the second) that sends and then clears.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Using associated objects now.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#import "FLTFileSelectorPlugin.h"

#import "messages.g.h"

// This header is available in the Test module. Import via "@import file_selector_ios.Test;".
@interface FLTFileSelectorPlugin() <FLTFileSelectorApi, UIDocumentPickerDelegate>

/**
* The completion block of a FLTFileSelectorApi request.
* It is saved and invoked later in a UIDocumentPickerDelegate method.
*/
@property(nonatomic) void (^_Nullable pendingCompletion)
(NSArray<NSString *> *_Nullable, FlutterError *_Nullable);
/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: blank line above this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is removed.

* Overrides the view controller used for presenting the document picker.
*/
@property(nonatomic) UIViewController * _Nullable presentingViewControllerOverride;

/**
* Overrides the UIDocumentPickerViewController used for file picking.
*/
@property(nonatomic) UIDocumentPickerViewController *_Nullable documentPickerViewControllerOverride;

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
framework module file_selector_ios {
umbrella header "file_selector_ios-umbrella.h"

export *
module * { export * }

explicit module Test {
header "FLTFileSelectorPlugin_Test.h"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: please fix missing final newlines in the files that are missing them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import <Foundation/Foundation.h>
#import <file_selector_ios/FLTFileSelectorPlugin.h>
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Displays the native iOS document picker.
s.author = { 'Flutter Dev Team' => '[email protected]' }
s.source = { :http => 'https://github.com/flutter/plugins/tree/main/packages/file_selector/file_selector_ios' }
s.source_files = 'Classes/**/*'
s.module_map = 'Classes/FileSelectorPlugin.modulemap'
s.dependency 'Flutter'
s.platform = :ios, '9.0'

Expand Down