mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Refactor initial route code take 2 (flutter/engine#20468)
This commit is contained in:
parent
89d75f7420
commit
5ac78f5be6
@ -925,6 +925,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine.
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEnginePlatformViewTest.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngineTest.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Internal.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterObservatoryPublisher.h
|
||||
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterObservatoryPublisher.mm
|
||||
|
||||
@ -1056,23 +1056,19 @@ class Window {
|
||||
///
|
||||
/// ## Android
|
||||
///
|
||||
/// On Android, calling
|
||||
/// [`FlutterView.setInitialRoute`](/javadoc/io/flutter/view/FlutterView.html#setInitialRoute-java.lang.String-)
|
||||
/// will set this value. The value must be set sufficiently early, i.e. before
|
||||
/// the [runApp] call is executed in Dart, for this to have any effect on the
|
||||
/// framework. The `createFlutterView` method in your `FlutterActivity`
|
||||
/// subclass is a suitable time to set the value. The application's
|
||||
/// `AndroidManifest.xml` file must also be updated to have a suitable
|
||||
/// [`<intent-filter>`](https://developer.android.com/guide/topics/manifest/intent-filter-element.html).
|
||||
/// On Android, the initial route can be set on the [initialRoute](/javadoc/io/flutter/embedding/android/FlutterActivity.NewEngineIntentBuilder.html#initialRoute-java.lang.String-)
|
||||
/// method of the [FlutterActivity](/javadoc/io/flutter/embedding/android/FlutterActivity.html)'s
|
||||
/// intent builder.
|
||||
///
|
||||
/// On a standalone engine, see https://flutter.dev/docs/development/add-to-app/android/add-flutter-screen#initial-route-with-a-cached-engine.
|
||||
///
|
||||
/// ## iOS
|
||||
///
|
||||
/// On iOS, calling
|
||||
/// [`FlutterViewController.setInitialRoute`](/objcdoc/Classes/FlutterViewController.html#/c:objc%28cs%29FlutterViewController%28im%29setInitialRoute:)
|
||||
/// will set this value. The value must be set sufficiently early, i.e. before
|
||||
/// the [runApp] call is executed in Dart, for this to have any effect on the
|
||||
/// framework. The `application:didFinishLaunchingWithOptions:` method is a
|
||||
/// suitable time to set this value.
|
||||
/// On iOS, the initial route can be set on the `initialRoute`
|
||||
/// parameter of the [FlutterViewController](/objcdoc/Classes/FlutterViewController.html)'s
|
||||
/// initializer.
|
||||
///
|
||||
/// On a standalone engine, see https://flutter.dev/docs/development/add-to-app/ios/add-flutter-screen#route.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
|
||||
@ -710,26 +710,6 @@ abstract class Window {
|
||||
///
|
||||
/// This will be the string "`/`" if no particular route was requested.
|
||||
///
|
||||
/// ## Android
|
||||
///
|
||||
/// On Android, calling
|
||||
/// [`FlutterView.setInitialRoute`](/javadoc/io/flutter/view/FlutterView.html#setInitialRoute-java.lang.String-)
|
||||
/// will set this value. The value must be set sufficiently early, i.e. before
|
||||
/// the [runApp] call is executed in Dart, for this to have any effect on the
|
||||
/// framework. The `createFlutterView` method in your `FlutterActivity`
|
||||
/// subclass is a suitable time to set the value. The application's
|
||||
/// `AndroidManifest.xml` file must also be updated to have a suitable
|
||||
/// [`<intent-filter>`](https://developer.android.com/guide/topics/manifest/intent-filter-element.html).
|
||||
///
|
||||
/// ## iOS
|
||||
///
|
||||
/// On iOS, calling
|
||||
/// [`FlutterViewController.setInitialRoute`](/objcdoc/Classes/FlutterViewController.html#/c:objc%28cs%29FlutterViewController%28im%29setInitialRoute:)
|
||||
/// will set this value. The value must be set sufficiently early, i.e. before
|
||||
/// the [runApp] call is executed in Dart, for this to have any effect on the
|
||||
/// framework. The `application:didFinishLaunchingWithOptions:` method is a
|
||||
/// suitable time to set this value.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Navigator], a widget that handles routing.
|
||||
|
||||
@ -5,52 +5,6 @@
|
||||
#ifndef FLUTTER_FLUTTER_H_
|
||||
#define FLUTTER_FLUTTER_H_
|
||||
|
||||
/**
|
||||
BREAKING CHANGES:
|
||||
|
||||
December 17, 2018:
|
||||
- Changed designated initializer on FlutterEngine
|
||||
|
||||
October 5, 2018:
|
||||
- Removed FlutterNavigationController.h/.mm
|
||||
- Changed return signature of `FlutterDartHeadlessCodeRunner.run*` from void
|
||||
to bool
|
||||
- Removed HeadlessPlatformViewIOS
|
||||
- Marked FlutterDartHeadlessCodeRunner deprecated
|
||||
|
||||
August 31, 2018: Marked -[FlutterDartProject
|
||||
initFromDefaultSourceForConfiguration] and FlutterStandardBigInteger as
|
||||
unavailable.
|
||||
|
||||
July 26, 2018: Marked -[FlutterDartProject
|
||||
initFromDefaultSourceForConfiguration] deprecated.
|
||||
|
||||
February 28, 2018: Removed "initWithFLXArchive" and
|
||||
"initWithFLXArchiveWithScriptSnapshot".
|
||||
|
||||
January 15, 2018: Marked "initWithFLXArchive" and
|
||||
"initWithFLXArchiveWithScriptSnapshot" as unavailable following the
|
||||
deprecation from December 11, 2017. Scheduled to be removed on February
|
||||
19, 2018.
|
||||
|
||||
January 09, 2018: Deprecated "FlutterStandardBigInteger" and its use in
|
||||
"FlutterStandardMessageCodec" and "FlutterStandardMethodCodec". Scheduled to
|
||||
be marked as unavailable once the deprecation has been available on the
|
||||
flutter/flutter alpha branch for four weeks. "FlutterStandardBigInteger" was
|
||||
needed because the Dart 1.0 int type had no size limit. With Dart 2.0, the
|
||||
int type is a fixed-size, 64-bit signed integer. If you need to communicate
|
||||
larger integers, use NSString encoding instead.
|
||||
|
||||
December 11, 2017: Deprecated "initWithFLXArchive" and
|
||||
"initWithFLXArchiveWithScriptSnapshot" and scheculed the same to be marked as
|
||||
unavailable on January 15, 2018. Instead, "initWithFlutterAssets" and
|
||||
"initWithFlutterAssetsWithScriptSnapshot" should be used. The reason for this
|
||||
change is that the FLX archive will be deprecated and replaced with a flutter
|
||||
assets directory containing the same files as the FLX did.
|
||||
|
||||
November 29, 2017: Added a BREAKING CHANGES section.
|
||||
*/
|
||||
|
||||
#include "FlutterAppDelegate.h"
|
||||
#include "FlutterBinaryMessenger.h"
|
||||
#include "FlutterCallbackCache.h"
|
||||
|
||||
@ -24,6 +24,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
extern NSString* const FlutterDefaultDartEntrypoint;
|
||||
|
||||
/**
|
||||
* The default Flutter initial route ("/").
|
||||
*/
|
||||
extern NSString* const FlutterDefaultInitialRoute;
|
||||
|
||||
/**
|
||||
* The FlutterEngine class coordinates a single instance of execution for a
|
||||
* `FlutterDartProject`. It may have zero or one `FlutterViewController` at a
|
||||
@ -53,6 +58,24 @@ extern NSString* const FlutterDefaultDartEntrypoint;
|
||||
FLUTTER_EXPORT
|
||||
@interface FlutterEngine : NSObject <FlutterTextureRegistry, FlutterPluginRegistry>
|
||||
|
||||
/**
|
||||
* Default initializer for a FlutterEngine.
|
||||
*
|
||||
* Threads created by this FlutterEngine will appear as "FlutterEngine #" in
|
||||
* Instruments. The prefix can be customized using `initWithName`.
|
||||
*
|
||||
* The engine will execute the project located in the bundle with the identifier
|
||||
* "io.flutter.flutter.app" (the default for Flutter projects).
|
||||
*
|
||||
* A newly initialized engine will not run until either `-runWithEntrypoint:` or
|
||||
* `-runWithEntrypoint:libraryURI:` is called.
|
||||
*
|
||||
* FlutterEngine created with this method will have allowHeadlessExecution set to `YES`.
|
||||
* This means that the engine will continue to run regardless of whether a `FlutterViewController`
|
||||
* is attached to it or not, until `-destroyContext:` is called or the process finishes.
|
||||
*/
|
||||
- (instancetype)init;
|
||||
|
||||
/**
|
||||
* Initialize this FlutterEngine.
|
||||
*
|
||||
@ -114,17 +137,12 @@ FLUTTER_EXPORT
|
||||
project:(nullable FlutterDartProject*)project
|
||||
allowHeadlessExecution:(BOOL)allowHeadlessExecution NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* The default initializer is not available for this object.
|
||||
* Callers must use `-[FlutterEngine initWithName:project:]`.
|
||||
*/
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
+ (instancetype)new NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Runs a Dart program on an Isolate from the main Dart library (i.e. the library that
|
||||
* contains `main()`), using `main()` as the entrypoint (the default for Flutter projects).
|
||||
* contains `main()`), using `main()` as the entrypoint (the default for Flutter projects),
|
||||
* and using "/" (the default route) as the initial route.
|
||||
*
|
||||
* The first call to this method will create a new Isolate. Subsequent calls will return
|
||||
* immediately and have no effect.
|
||||
@ -135,7 +153,7 @@ FLUTTER_EXPORT
|
||||
|
||||
/**
|
||||
* Runs a Dart program on an Isolate from the main Dart library (i.e. the library that
|
||||
* contains `main()`).
|
||||
* contains `main()`), using "/" (the default route) as the initial route.
|
||||
*
|
||||
* The first call to this method will create a new Isolate. Subsequent calls will return
|
||||
* immediately and have no effect.
|
||||
@ -149,6 +167,25 @@ FLUTTER_EXPORT
|
||||
*/
|
||||
- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint;
|
||||
|
||||
/**
|
||||
* Runs a Dart program on an Isolate from the main Dart library (i.e. the library that
|
||||
* contains `main()`).
|
||||
*
|
||||
* The first call to this method will create a new Isolate. Subsequent calls will return
|
||||
* immediately and have no effect.
|
||||
*
|
||||
* @param entrypoint The name of a top-level function from the same Dart
|
||||
* library that contains the app's main() function. If this is FlutterDefaultDartEntrypoint (or
|
||||
* nil), it will default to `main()`. If it is not the app's main() function, that function must
|
||||
* be decorated with `@pragma(vm:entry-point)` to ensure the method is not tree-shaken by the Dart
|
||||
* compiler.
|
||||
* @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is
|
||||
* FlutterDefaultInitialRoute (or nil), it will default to the "/" route.
|
||||
* @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise.
|
||||
*/
|
||||
- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint
|
||||
initialRoute:(nullable NSString*)initialRoute;
|
||||
|
||||
/**
|
||||
* Runs a Dart program on an Isolate using the specified entrypoint and Dart library,
|
||||
* which may not be the same as the library containing the Dart program's `main()` function.
|
||||
|
||||
@ -55,7 +55,7 @@ FLUTTER_EXPORT
|
||||
*
|
||||
* The initialized viewcontroller will attach itself to the engine as part of this process.
|
||||
*
|
||||
* @param engine The `FlutterEngine` instance to attach to.
|
||||
* @param engine The `FlutterEngine` instance to attach to. Cannot be nil.
|
||||
* @param nibName The NIB name to initialize this UIViewController with.
|
||||
* @param nibBundle The NIB bundle.
|
||||
*/
|
||||
@ -78,6 +78,23 @@ FLUTTER_EXPORT
|
||||
nibName:(nullable NSString*)nibName
|
||||
bundle:(nullable NSBundle*)nibBundle NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Initializes a new FlutterViewController and `FlutterEngine` with the specified
|
||||
* `FlutterDartProject` and `initialRoute`.
|
||||
*
|
||||
* This will implicitly create a new `FlutterEngine` which is retrievable via the `engine` property
|
||||
* after initialization.
|
||||
*
|
||||
* @param project The `FlutterDartProject` to initialize the `FlutterEngine` with.
|
||||
* @param initialRoute The initial `Navigator` route to load.
|
||||
* @param nibName The NIB name to initialize this UIViewController with.
|
||||
* @param nibBundle The NIB bundle.
|
||||
*/
|
||||
- (instancetype)initWithProject:(nullable FlutterDartProject*)project
|
||||
initialRoute:(nullable NSString*)initialRoute
|
||||
nibName:(nullable NSString*)nibName
|
||||
bundle:(nullable NSBundle*)nibBundle NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Initializer that is called from loading a FlutterViewController from a XIB.
|
||||
*
|
||||
@ -117,6 +134,8 @@ FLUTTER_EXPORT
|
||||
- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package;
|
||||
|
||||
/**
|
||||
* Deprecated API to set initial route.
|
||||
*
|
||||
* Attempts to set the first route that the Flutter app shows if the Flutter
|
||||
* runtime hasn't yet started. The default is "/".
|
||||
*
|
||||
@ -127,9 +146,15 @@ FLUTTER_EXPORT
|
||||
* Setting this after the Flutter started running has no effect. See `pushRoute`
|
||||
* and `popRoute` to change the route after Flutter started running.
|
||||
*
|
||||
* This is deprecated because it needs to be called at the time of initialization
|
||||
* and thus should just be in the `initWithProject` initializer. If using
|
||||
* `initWithEngine`, the initial route should be set on the engine's
|
||||
* initializer.
|
||||
*
|
||||
* @param route The name of the first route to show.
|
||||
*/
|
||||
- (void)setInitialRoute:(NSString*)route;
|
||||
- (void)setInitialRoute:(NSString*)route
|
||||
FLUTTER_DEPRECATED("Use FlutterViewController initializer to specify initial route");
|
||||
|
||||
/**
|
||||
* Instructs the Flutter Navigator (if any) to go back.
|
||||
@ -138,8 +163,7 @@ FLUTTER_EXPORT
|
||||
|
||||
/**
|
||||
* Instructs the Flutter Navigator (if any) to push a route on to the navigation
|
||||
* stack. The setInitialRoute method should be preferred if this is called before the
|
||||
* FlutterViewController has come into view.
|
||||
* stack.
|
||||
*
|
||||
* @param route The name of the route to push to the navigation stack.
|
||||
*/
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
#import "flutter/shell/platform/darwin/ios/platform_view_ios.h"
|
||||
|
||||
NSString* const FlutterDefaultDartEntrypoint = nil;
|
||||
NSString* const FlutterDefaultInitialRoute = nil;
|
||||
static constexpr int kNumProfilerSamplesPerSec = 5;
|
||||
|
||||
@interface FlutterEngineRegistrar : NSObject <FlutterPluginRegistrar>
|
||||
@ -47,6 +48,7 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
|
||||
@property(nonatomic, readonly) NSMutableDictionary<NSString*, FlutterEngineRegistrar*>* registrars;
|
||||
|
||||
@property(nonatomic, readwrite, copy) NSString* isolateId;
|
||||
@property(nonatomic, copy) NSString* initialRoute;
|
||||
@property(nonatomic, retain) id<NSObject> flutterViewControllerWillDeallocObserver;
|
||||
@end
|
||||
|
||||
@ -83,6 +85,10 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
|
||||
std::unique_ptr<flutter::ConnectionCollection> _connections;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
return [self initWithName:@"FlutterEngine" project:nil allowHeadlessExecution:YES];
|
||||
}
|
||||
|
||||
- (instancetype)initWithName:(NSString*)labelPrefix {
|
||||
return [self initWithName:labelPrefix project:nil allowHeadlessExecution:YES];
|
||||
}
|
||||
@ -161,6 +167,7 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
|
||||
}];
|
||||
|
||||
[_labelPrefix release];
|
||||
[_initialRoute release];
|
||||
[_pluginPublications release];
|
||||
[_registrars release];
|
||||
_binaryMessenger.parent = nil;
|
||||
@ -368,6 +375,13 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
|
||||
binaryMessenger:self.binaryMessenger
|
||||
codec:[FlutterJSONMethodCodec sharedInstance]]);
|
||||
|
||||
if ([_initialRoute length] > 0) {
|
||||
// Flutter isn't ready to receive this method call yet but the channel buffer will cache this.
|
||||
[_navigationChannel invokeMethod:@"setInitialRoute" arguments:_initialRoute];
|
||||
[_initialRoute release];
|
||||
_initialRoute = nil;
|
||||
}
|
||||
|
||||
_platformChannel.reset([[FlutterMethodChannel alloc]
|
||||
initWithName:@"flutter/platform"
|
||||
binaryMessenger:self.binaryMessenger
|
||||
@ -437,13 +451,16 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
|
||||
libraryOrNil:libraryOrNil]);
|
||||
}
|
||||
|
||||
- (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
|
||||
- (BOOL)createShell:(NSString*)entrypoint
|
||||
libraryURI:(NSString*)libraryURI
|
||||
initialRoute:(NSString*)initialRoute {
|
||||
if (_shell != nullptr) {
|
||||
FML_LOG(WARNING) << "This FlutterEngine was already invoked.";
|
||||
return NO;
|
||||
}
|
||||
|
||||
static size_t shellCount = 1;
|
||||
self.initialRoute = initialRoute;
|
||||
|
||||
auto settings = [_dartProject.get() settings];
|
||||
auto platformData = [_dartProject.get() defaultPlatformData];
|
||||
@ -553,21 +570,35 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
|
||||
}
|
||||
|
||||
- (BOOL)run {
|
||||
return [self runWithEntrypoint:FlutterDefaultDartEntrypoint libraryURI:nil];
|
||||
return [self runWithEntrypoint:FlutterDefaultDartEntrypoint
|
||||
libraryURI:nil
|
||||
initialRoute:FlutterDefaultInitialRoute];
|
||||
}
|
||||
|
||||
- (BOOL)runWithEntrypoint:(NSString*)entrypoint libraryURI:(NSString*)libraryURI {
|
||||
if ([self createShell:entrypoint libraryURI:libraryURI]) {
|
||||
return [self runWithEntrypoint:entrypoint
|
||||
libraryURI:libraryURI
|
||||
initialRoute:FlutterDefaultInitialRoute];
|
||||
}
|
||||
|
||||
- (BOOL)runWithEntrypoint:(NSString*)entrypoint {
|
||||
return [self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:FlutterDefaultInitialRoute];
|
||||
}
|
||||
|
||||
- (BOOL)runWithEntrypoint:(NSString*)entrypoint initialRoute:(NSString*)initialRoute {
|
||||
return [self runWithEntrypoint:entrypoint libraryURI:nil initialRoute:initialRoute];
|
||||
}
|
||||
|
||||
- (BOOL)runWithEntrypoint:(NSString*)entrypoint
|
||||
libraryURI:(NSString*)libraryURI
|
||||
initialRoute:(NSString*)initialRoute {
|
||||
if ([self createShell:entrypoint libraryURI:libraryURI initialRoute:initialRoute]) {
|
||||
[self launchEngine:entrypoint libraryURI:libraryURI];
|
||||
}
|
||||
|
||||
return _shell != nullptr;
|
||||
}
|
||||
|
||||
- (BOOL)runWithEntrypoint:(NSString*)entrypoint {
|
||||
return [self runWithEntrypoint:entrypoint libraryURI:nil];
|
||||
}
|
||||
|
||||
- (void)notifyLowMemory {
|
||||
if (_shell) {
|
||||
_shell->NotifyLowMemoryWarning();
|
||||
@ -670,6 +701,15 @@ static constexpr int kNumProfilerSamplesPerSec = 5;
|
||||
return _binaryMessenger;
|
||||
}
|
||||
|
||||
// For test only. Ideally we should create a dependency injector for all dependencies and
|
||||
// remove this.
|
||||
- (void)setBinaryMessenger:(FlutterBinaryMessengerRelay*)binaryMessenger {
|
||||
// Discard the previous messenger and keep the new one.
|
||||
_binaryMessenger.parent = nil;
|
||||
[_binaryMessenger release];
|
||||
_binaryMessenger = [binaryMessenger retain];
|
||||
}
|
||||
|
||||
#pragma mark - FlutterBinaryMessenger
|
||||
|
||||
- (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
|
||||
|
||||
@ -5,7 +5,8 @@
|
||||
#import <OCMock/OCMock.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
#include "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterBinaryMessengerRelay.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterEngine_Test.h"
|
||||
|
||||
FLUTTER_ASSERT_ARC
|
||||
|
||||
@ -79,4 +80,23 @@ FLUTTER_ASSERT_ARC
|
||||
OCMVerify([plugin detachFromEngineForRegistrar:[OCMArg any]]);
|
||||
}
|
||||
|
||||
- (void)testRunningInitialRouteSendsNavigationMessage {
|
||||
id mockBinaryMessenger = OCMClassMock([FlutterBinaryMessengerRelay class]);
|
||||
|
||||
FlutterEngine* engine = [[FlutterEngine alloc] init];
|
||||
[engine setBinaryMessenger:mockBinaryMessenger];
|
||||
|
||||
// Run with an initial route.
|
||||
[engine runWithEntrypoint:FlutterDefaultDartEntrypoint initialRoute:@"test"];
|
||||
|
||||
// Now check that an encoded method call has been made on the binary messenger to set the
|
||||
// initial route to "test".
|
||||
FlutterMethodCall* setInitialRouteMethodCall =
|
||||
[FlutterMethodCall methodCallWithMethodName:@"setInitialRoute" arguments:@"test"];
|
||||
NSData* encodedSetInitialRouteMethod =
|
||||
[[FlutterJSONMethodCodec sharedInstance] encodeMethodCall:setInitialRouteMethodCall];
|
||||
OCMVerify([mockBinaryMessenger sendOnChannel:@"flutter/navigation"
|
||||
message:encodedSetInitialRouteMethod]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -43,7 +43,9 @@
|
||||
- (flutter::FlutterPlatformViewsController*)platformViewsController;
|
||||
- (FlutterTextInputPlugin*)textInputPlugin;
|
||||
- (void)launchEngine:(NSString*)entrypoint libraryURI:(NSString*)libraryOrNil;
|
||||
- (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryOrNil;
|
||||
- (BOOL)createShell:(NSString*)entrypoint
|
||||
libraryURI:(NSString*)libraryOrNil
|
||||
initialRoute:(NSString*)initialRoute;
|
||||
- (void)attachView;
|
||||
- (void)notifyLowMemory;
|
||||
- (flutter::PlatformViewIOS*)iosPlatformView;
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
// 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 "flutter/shell/platform/darwin/ios/framework/Headers/FlutterEngine.h"
|
||||
|
||||
// Category to add test-only visibility.
|
||||
@interface FlutterEngine (Test) <FlutterBinaryMessenger>
|
||||
- (void)setBinaryMessenger:(FlutterBinaryMessengerRelay*)binaryMessenger;
|
||||
@end
|
||||
@ -111,26 +111,24 @@ typedef enum UIAccessibilityContrast : NSInteger {
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)sharedSetupWithProject:(nullable FlutterDartProject*)project {
|
||||
_viewOpaque = YES;
|
||||
_weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterViewController>>(self);
|
||||
_engine.reset([[FlutterEngine alloc] initWithName:@"io.flutter"
|
||||
project:project
|
||||
allowHeadlessExecution:self.engineAllowHeadlessExecution]);
|
||||
_flutterView.reset([[FlutterView alloc] initWithDelegate:_engine opaque:self.isViewOpaque]);
|
||||
[_engine.get() createShell:nil libraryURI:nil];
|
||||
_engineNeedsLaunch = YES;
|
||||
_ongoingTouches = [[NSMutableSet alloc] init];
|
||||
[self loadDefaultSplashScreenView];
|
||||
[self performCommonViewControllerInitialization];
|
||||
}
|
||||
|
||||
- (instancetype)initWithProject:(nullable FlutterDartProject*)project
|
||||
nibName:(nullable NSString*)nibName
|
||||
bundle:(nullable NSBundle*)nibBundle {
|
||||
- (instancetype)initWithProject:(FlutterDartProject*)project
|
||||
nibName:(NSString*)nibName
|
||||
bundle:(NSBundle*)nibBundle {
|
||||
self = [super initWithNibName:nibName bundle:nibBundle];
|
||||
if (self) {
|
||||
[self sharedSetupWithProject:project];
|
||||
[self sharedSetupWithProject:project initialRoute:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithProject:(FlutterDartProject*)project
|
||||
initialRoute:(NSString*)initialRoute
|
||||
nibName:(NSString*)nibName
|
||||
bundle:(NSBundle*)nibBundle {
|
||||
self = [super initWithNibName:nibName bundle:nibBundle];
|
||||
if (self) {
|
||||
[self sharedSetupWithProject:project initialRoute:initialRoute];
|
||||
}
|
||||
|
||||
return self;
|
||||
@ -148,7 +146,7 @@ typedef enum UIAccessibilityContrast : NSInteger {
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
if (!_engine.get()) {
|
||||
[self sharedSetupWithProject:nil];
|
||||
[self sharedSetupWithProject:nil initialRoute:nil];
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,6 +154,21 @@ typedef enum UIAccessibilityContrast : NSInteger {
|
||||
return [self initWithProject:nil nibName:nil bundle:nil];
|
||||
}
|
||||
|
||||
- (void)sharedSetupWithProject:(nullable FlutterDartProject*)project
|
||||
initialRoute:(nullable NSString*)initialRoute {
|
||||
_viewOpaque = YES;
|
||||
_weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterViewController>>(self);
|
||||
_engine.reset([[FlutterEngine alloc] initWithName:@"io.flutter"
|
||||
project:project
|
||||
allowHeadlessExecution:self.engineAllowHeadlessExecution]);
|
||||
_flutterView.reset([[FlutterView alloc] initWithDelegate:_engine opaque:self.isViewOpaque]);
|
||||
[_engine.get() createShell:nil libraryURI:nil initialRoute:initialRoute];
|
||||
_engineNeedsLaunch = YES;
|
||||
_ongoingTouches = [[NSMutableSet alloc] init];
|
||||
[self loadDefaultSplashScreenView];
|
||||
[self performCommonViewControllerInitialization];
|
||||
}
|
||||
|
||||
- (BOOL)isViewOpaque {
|
||||
return _viewOpaque;
|
||||
}
|
||||
@ -469,7 +482,12 @@ static void sendFakeTouchEvent(FlutterEngine* engine,
|
||||
}
|
||||
|
||||
- (UIView*)splashScreenFromXib:(NSString*)name {
|
||||
NSArray* objects = [[NSBundle mainBundle] loadNibNamed:name owner:self options:nil];
|
||||
NSArray* objects = nil;
|
||||
@try {
|
||||
objects = [[NSBundle mainBundle] loadNibNamed:name owner:self options:nil];
|
||||
} @catch (NSException* exception) {
|
||||
return nil;
|
||||
}
|
||||
if ([objects count] != 0) {
|
||||
UIView* view = [objects objectAtIndex:0];
|
||||
return view;
|
||||
|
||||
@ -13,7 +13,9 @@
|
||||
FLUTTER_ASSERT_ARC
|
||||
|
||||
@interface FlutterEngine ()
|
||||
- (BOOL)createShell:(NSString*)entrypoint libraryURI:(NSString*)libraryURI;
|
||||
- (BOOL)createShell:(NSString*)entrypoint
|
||||
libraryURI:(NSString*)libraryURI
|
||||
initialRoute:(NSString*)initialRoute;
|
||||
@end
|
||||
|
||||
@interface FlutterEngine (TestLowMemory)
|
||||
@ -513,7 +515,7 @@ typedef enum UIAccessibilityContrast : NSInteger {
|
||||
- (void)testDoesntLoadViewInInit {
|
||||
FlutterDartProject* project = [[FlutterDartProject alloc] init];
|
||||
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
|
||||
[engine createShell:@"" libraryURI:@""];
|
||||
[engine createShell:@"" libraryURI:@"" initialRoute:nil];
|
||||
FlutterViewController* realVC = [[FlutterViewController alloc] initWithEngine:engine
|
||||
nibName:nil
|
||||
bundle:nil];
|
||||
@ -523,7 +525,7 @@ typedef enum UIAccessibilityContrast : NSInteger {
|
||||
- (void)testHideOverlay {
|
||||
FlutterDartProject* project = [[FlutterDartProject alloc] init];
|
||||
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
|
||||
[engine createShell:@"" libraryURI:@""];
|
||||
[engine createShell:@"" libraryURI:@"" initialRoute:nil];
|
||||
FlutterViewController* realVC = [[FlutterViewController alloc] initWithEngine:engine
|
||||
nibName:nil
|
||||
bundle:nil];
|
||||
|
||||
@ -28,6 +28,15 @@
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0AC232F424BA71D300A85907 /* SemanticsObjectTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SemanticsObjectTest.mm; sourceTree = "<group>"; };
|
||||
0AC232F724BA71D300A85907 /* FlutterEngineTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterEngineTest.mm; sourceTree = "<group>"; };
|
||||
0AC2330324BA71D300A85907 /* accessibility_bridge_test.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = accessibility_bridge_test.mm; sourceTree = "<group>"; };
|
||||
0AC2330B24BA71D300A85907 /* FlutterTextInputPluginTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlutterTextInputPluginTest.m; sourceTree = "<group>"; };
|
||||
0AC2330F24BA71D300A85907 /* FlutterBinaryMessengerRelayTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterBinaryMessengerRelayTest.mm; sourceTree = "<group>"; };
|
||||
0AC2331024BA71D300A85907 /* connection_collection_test.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = connection_collection_test.mm; sourceTree = "<group>"; };
|
||||
0AC2331224BA71D300A85907 /* FlutterEnginePlatformViewTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterEnginePlatformViewTest.mm; sourceTree = "<group>"; };
|
||||
0AC2331924BA71D300A85907 /* FlutterPluginAppLifeCycleDelegateTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlutterPluginAppLifeCycleDelegateTest.m; sourceTree = "<group>"; };
|
||||
0AC2332124BA71D300A85907 /* FlutterViewControllerTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterViewControllerTest.mm; sourceTree = "<group>"; };
|
||||
0D1CE5D7233430F400E5D880 /* FlutterChannelsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlutterChannelsTest.m; sourceTree = "<group>"; };
|
||||
0D6AB6B122BB05E100EEE540 /* IosUnitTests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IosUnitTests.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0D6AB6B422BB05E100EEE540 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
@ -62,6 +71,23 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
0AC232E924BA71D300A85907 /* Source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0AC232F424BA71D300A85907 /* SemanticsObjectTest.mm */,
|
||||
0AC232F724BA71D300A85907 /* FlutterEngineTest.mm */,
|
||||
0AC2330324BA71D300A85907 /* accessibility_bridge_test.mm */,
|
||||
0AC2330B24BA71D300A85907 /* FlutterTextInputPluginTest.m */,
|
||||
0AC2330F24BA71D300A85907 /* FlutterBinaryMessengerRelayTest.mm */,
|
||||
0AC2331024BA71D300A85907 /* connection_collection_test.mm */,
|
||||
0AC2331224BA71D300A85907 /* FlutterEnginePlatformViewTest.mm */,
|
||||
0AC2331924BA71D300A85907 /* FlutterPluginAppLifeCycleDelegateTest.m */,
|
||||
0AC2332124BA71D300A85907 /* FlutterViewControllerTest.mm */,
|
||||
);
|
||||
name = Source;
|
||||
path = ../../../shell/platform/darwin/ios/framework/Source;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0D1CE5D62334309900E5D880 /* Source-Common */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -74,6 +100,7 @@
|
||||
0D6AB6A822BB05E100EEE540 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0AC232E924BA71D300A85907 /* Source */,
|
||||
0D6AB6B322BB05E100EEE540 /* App */,
|
||||
0D6AB6CC22BB05E200EEE540 /* Tests */,
|
||||
0D6AB6B222BB05E100EEE540 /* Products */,
|
||||
|
||||
@ -331,10 +331,11 @@ def AssertExpectedJavaVersion():
|
||||
|
||||
def AssertExpectedXcodeVersion():
|
||||
"""Checks that the user has a recent version of Xcode installed"""
|
||||
EXPECTED_MAJOR_VERSION = '11'
|
||||
EXPECTED_MAJOR_VERSION = ['11', '12']
|
||||
version_output = subprocess.check_output(['xcodebuild', '-version'])
|
||||
match = re.match("Xcode (\d+)", version_output)
|
||||
message = "Xcode must be installed to run the iOS embedding unit tests"
|
||||
assert "Xcode %s." % EXPECTED_MAJOR_VERSION in version_output, message
|
||||
assert match.group(1) in EXPECTED_MAJOR_VERSION, message
|
||||
|
||||
def RunJavaTests(filter, android_variant='android_debug_unopt'):
|
||||
"""Runs the Java JUnit unit tests for the Android embedding"""
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
0A57B3BD2323C4BD00DD9521 /* ScreenBeforeFlutter.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A57B3BC2323C4BD00DD9521 /* ScreenBeforeFlutter.m */; };
|
||||
0A57B3BF2323C74200DD9521 /* FlutterEngine+ScenariosTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A57B3BE2323C74200DD9521 /* FlutterEngine+ScenariosTest.m */; };
|
||||
0A57B3C22323D2D700DD9521 /* AppLifecycleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A57B3C12323D2D700DD9521 /* AppLifecycleTests.m */; };
|
||||
0A97D7C024BA937000050525 /* FlutterViewControllerInitialRouteTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A97D7BF24BA937000050525 /* FlutterViewControllerInitialRouteTest.m */; };
|
||||
0D14A3FE239743190013D873 /* golden_platform_view_rotate_iPhone SE_simulator.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D14A3FD239743190013D873 /* golden_platform_view_rotate_iPhone SE_simulator.png */; };
|
||||
0D8470A4240F0B1F0030B565 /* StatusBarTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D8470A3240F0B1F0030B565 /* StatusBarTest.m */; };
|
||||
0DB781EF22E931BE00E9B371 /* Flutter.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 246B4E4522E3B61000073EBF /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
@ -119,6 +120,7 @@
|
||||
0A57B3BE2323C74200DD9521 /* FlutterEngine+ScenariosTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "FlutterEngine+ScenariosTest.m"; sourceTree = "<group>"; };
|
||||
0A57B3C02323C74D00DD9521 /* FlutterEngine+ScenariosTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FlutterEngine+ScenariosTest.h"; sourceTree = "<group>"; };
|
||||
0A57B3C12323D2D700DD9521 /* AppLifecycleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppLifecycleTests.m; sourceTree = "<group>"; };
|
||||
0A97D7BF24BA937000050525 /* FlutterViewControllerInitialRouteTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FlutterViewControllerInitialRouteTest.m; sourceTree = "<group>"; };
|
||||
0D14A3FD239743190013D873 /* golden_platform_view_rotate_iPhone SE_simulator.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "golden_platform_view_rotate_iPhone SE_simulator.png"; sourceTree = "<group>"; };
|
||||
0D8470A2240F0B1F0030B565 /* StatusBarTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StatusBarTest.h; sourceTree = "<group>"; };
|
||||
0D8470A3240F0B1F0030B565 /* StatusBarTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StatusBarTest.m; sourceTree = "<group>"; };
|
||||
@ -243,6 +245,7 @@
|
||||
children = (
|
||||
248FDFC322FE7CD0009CC7CD /* FlutterEngineTest.m */,
|
||||
0DB781FC22EA2C0300E9B371 /* FlutterViewControllerTest.m */,
|
||||
0A97D7BF24BA937000050525 /* FlutterViewControllerInitialRouteTest.m */,
|
||||
248D76E522E388380012F0C1 /* Info.plist */,
|
||||
0A57B3C12323D2D700DD9521 /* AppLifecycleTests.m */,
|
||||
);
|
||||
@ -469,6 +472,7 @@
|
||||
files = (
|
||||
0DB7820222EA493B00E9B371 /* FlutterViewControllerTest.m in Sources */,
|
||||
0A57B3C22323D2D700DD9521 /* AppLifecycleTests.m in Sources */,
|
||||
0A97D7C024BA937000050525 /* FlutterViewControllerInitialRouteTest.m in Sources */,
|
||||
248FDFC422FE7CD0009CC7CD /* FlutterEngineTest.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
NSAssert([scenario length] != 0, @"You need to provide a scenario");
|
||||
self = [self initWithName:[NSString stringWithFormat:@"Test engine for %@", scenario]
|
||||
project:nil];
|
||||
[self runWithEntrypoint:nil];
|
||||
[self run];
|
||||
|
||||
[self.binaryMessenger setMessageHandlerOnChannel:@"waiting_for_status"
|
||||
binaryMessageHandler:^(NSData* message, FlutterBinaryReply reply) {
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
XCTAssertNil(engine.platformChannel);
|
||||
XCTAssertNil(engine.lifecycleChannel);
|
||||
|
||||
XCTAssertTrue([engine runWithEntrypoint:nil]);
|
||||
XCTAssertTrue([engine run]);
|
||||
|
||||
XCTAssertNotNil(engine.navigationChannel);
|
||||
XCTAssertNotNil(engine.platformChannel);
|
||||
|
||||
@ -0,0 +1,84 @@
|
||||
// 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 <Flutter/Flutter.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "AppDelegate.h"
|
||||
|
||||
FLUTTER_ASSERT_ARC
|
||||
|
||||
@interface FlutterViewControllerInitialRouteTest : XCTestCase
|
||||
@property(nonatomic, strong) FlutterViewController* flutterViewController;
|
||||
@end
|
||||
|
||||
// This test needs to be in its own file with only one test method because dart:ui
|
||||
// window's defaultRouteName can only be set once per VM.
|
||||
@implementation FlutterViewControllerInitialRouteTest
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
self.continueAfterFailure = NO;
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
if (self.flutterViewController) {
|
||||
XCTestExpectation* vcDismissed = [self expectationWithDescription:@"dismiss"];
|
||||
[self.flutterViewController dismissViewControllerAnimated:NO
|
||||
completion:^{
|
||||
[vcDismissed fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:10.0 handler:nil];
|
||||
}
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testSettingInitialRoute {
|
||||
self.flutterViewController =
|
||||
[[FlutterViewController alloc] initWithProject:nil
|
||||
initialRoute:@"myCustomInitialRoute"
|
||||
nibName:nil
|
||||
bundle:nil];
|
||||
|
||||
NSObject<FlutterBinaryMessenger>* binaryMessenger = self.flutterViewController.binaryMessenger;
|
||||
__weak typeof(binaryMessenger) weakBinaryMessenger = binaryMessenger;
|
||||
|
||||
FlutterBinaryMessengerConnection waitingForStatusConnection = [binaryMessenger
|
||||
setMessageHandlerOnChannel:@"waiting_for_status"
|
||||
binaryMessageHandler:^(NSData* message, FlutterBinaryReply reply) {
|
||||
FlutterMethodChannel* channel = [FlutterMethodChannel
|
||||
methodChannelWithName:@"driver"
|
||||
binaryMessenger:weakBinaryMessenger
|
||||
codec:[FlutterJSONMethodCodec sharedInstance]];
|
||||
[channel invokeMethod:@"set_scenario" arguments:@{@"name" : @"initial_route_reply"}];
|
||||
}];
|
||||
|
||||
XCTestExpectation* customInitialRouteSet =
|
||||
[self expectationWithDescription:@"Custom initial route was set on the Dart side"];
|
||||
FlutterBinaryMessengerConnection initialRoutTestChannelConnection =
|
||||
[binaryMessenger setMessageHandlerOnChannel:@"initial_route_test_channel"
|
||||
binaryMessageHandler:^(NSData* message, FlutterBinaryReply reply) {
|
||||
NSDictionary* dict = [NSJSONSerialization JSONObjectWithData:message
|
||||
options:0
|
||||
error:nil];
|
||||
NSString* initialRoute = dict[@"method"];
|
||||
if ([initialRoute isEqualToString:@"myCustomInitialRoute"]) {
|
||||
[customInitialRouteSet fulfill];
|
||||
} else {
|
||||
XCTFail(@"Expected initial route to be set to "
|
||||
@"myCustomInitialRoute. Was set to %@ instead",
|
||||
initialRoute);
|
||||
}
|
||||
}];
|
||||
|
||||
AppDelegate* appDelegate = (AppDelegate*)UIApplication.sharedApplication.delegate;
|
||||
UIViewController* rootVC = appDelegate.window.rootViewController;
|
||||
[rootVC presentViewController:self.flutterViewController animated:NO completion:nil];
|
||||
|
||||
[self waitForExpectationsWithTimeout:30.0 handler:nil];
|
||||
|
||||
[binaryMessenger cleanupConnection:waitingForStatusConnection];
|
||||
[binaryMessenger cleanupConnection:initialRoutTestChannelConnection];
|
||||
}
|
||||
|
||||
@end
|
||||
@ -6,6 +6,8 @@
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "AppDelegate.h"
|
||||
|
||||
FLUTTER_ASSERT_ARC
|
||||
|
||||
@interface FlutterViewControllerTest : XCTestCase
|
||||
@property(nonatomic, strong) FlutterViewController* flutterViewController;
|
||||
@end
|
||||
@ -19,7 +21,12 @@
|
||||
|
||||
- (void)tearDown {
|
||||
if (self.flutterViewController) {
|
||||
[self.flutterViewController removeFromParentViewController];
|
||||
XCTestExpectation* vcDismissed = [self expectationWithDescription:@"dismiss"];
|
||||
[self.flutterViewController dismissViewControllerAnimated:NO
|
||||
completion:^{
|
||||
[vcDismissed fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:10.0 handler:nil];
|
||||
}
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
//
|
||||
// ScenariosTests.m
|
||||
// ScenariosTests
|
||||
//
|
||||
// Created by Dan Field on 7/20/19.
|
||||
// Copyright © 2019 flutter. All rights reserved.
|
||||
//
|
||||
// Copyright 2019 The Chromium 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 <XCTest/XCTest.h>
|
||||
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
// @dart = 2.6
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:scenario_app/src/channel_util.dart';
|
||||
|
||||
import 'scenario.dart';
|
||||
|
||||
/// A blank page that just sends back to the platform what the set initial
|
||||
/// route is.
|
||||
class InitialRouteReply extends Scenario {
|
||||
/// Creates the InitialRouteReply.
|
||||
///
|
||||
/// The [window] parameter must not be null.
|
||||
InitialRouteReply(Window window)
|
||||
: assert(window != null),
|
||||
super(window);
|
||||
|
||||
@override
|
||||
void onBeginFrame(Duration duration) {
|
||||
sendJsonMethodCall(
|
||||
window: window,
|
||||
channel: 'initial_route_test_channel',
|
||||
method: window.defaultRouteName,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'animated_color_square.dart';
|
||||
import 'initial_route_reply.dart';
|
||||
import 'locale_initialization.dart';
|
||||
import 'platform_view.dart';
|
||||
import 'poppable_screen.dart';
|
||||
@ -41,6 +42,7 @@ Map<String, ScenarioFactory> _scenarios = <String, ScenarioFactory>{
|
||||
'platform_view_gesture_reject_after_touches_ended': () => PlatformViewForTouchIOSScenario(window, 'platform view touch', id: _viewId++, accept: false, rejectUntilTouchesEnded: true),
|
||||
'tap_status_bar': () => TouchesScenario(window),
|
||||
'text_semantics_focus': () => SendTextFocusScemantics(window),
|
||||
'initial_route_reply': () => InitialRouteReply(window),
|
||||
};
|
||||
|
||||
Map<String, dynamic> _currentScenarioParams = <String, dynamic>{};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user