Merge pull request #2522 from chinmaygarde/master

Make the iOS shell use the public Flutter framework API.
This commit is contained in:
Chinmay Garde 2016-03-17 17:03:04 -07:00
commit 99f1529ebd
9 changed files with 388 additions and 96 deletions

View File

@ -244,6 +244,10 @@ if (is_android) {
sources = [
"platform/ios/FlutterAppDelegate.h",
"platform/ios/FlutterAppDelegate.mm",
"platform/ios/FlutterDartProject.mm",
"platform/ios/FlutterDartProject_Internal.h",
"platform/ios/FlutterDartSource.h",
"platform/ios/FlutterDartSource.mm",
"platform/ios/FlutterDynamicServiceLoader.h",
"platform/ios/FlutterDynamicServiceLoader.mm",
"platform/ios/FlutterView.h",
@ -251,10 +255,9 @@ if (is_android) {
"platform/ios/FlutterViewController.mm",
"platform/ios/flutter_touch_mapper.h",
"platform/ios/flutter_touch_mapper.mm",
"platform/ios/framework/Info.plist",
"platform/ios/framework/module.modulemap",
"platform/ios/main_ios.mm",
"platform/ios/public/Flutter.h",
"platform/ios/public/FlutterDartProject.h",
"platform/ios/public/FlutterMacros.h",
"platform/ios/public/FlutterViewController.h",
]

View File

@ -2,9 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/command_line.h"
#include "base/trace_event/trace_event.h"
#include "sky/shell/platform/ios/FlutterAppDelegate.h"
#include "sky/shell/platform/ios/public/FlutterViewController.h"
#include "base/trace_event/trace_event.h"
#include "sky/shell/switches.h"
NSURL* URLForSwitch(const char* name) {
auto cmd = *base::CommandLine::ForCurrentProcess();
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
if (cmd.HasSwitch(name)) {
auto url = [NSURL fileURLWithPath:@(cmd.GetSwitchValueASCII(name).c_str())];
[defaults setURL:url forKey:@(name)];
[defaults synchronize];
return url;
}
return [defaults URLForKey:@(name)];
}
@implementation FlutterAppDelegate
@ -12,13 +28,24 @@
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
TRACE_EVENT0("flutter", "applicationDidFinishLaunchingWithOptions");
NSBundle* dartBundle = [NSBundle
bundleWithIdentifier:@"io.flutter.application.FlutterApplication"];
#if TARGET_IPHONE_SIMULATOR
FlutterDartProject* project = [[FlutterDartProject alloc]
initWithFLXArchive:URLForSwitch(sky::shell::switches::kFLX)
dartMain:URLForSwitch(sky::shell::switches::kMainDartFile)
packageRoot:URLForSwitch(sky::shell::switches::kPackageRoot)];
#else
FlutterDartProject* project = [[FlutterDartProject alloc]
initWithPrecompiledDartBundle:
[NSBundle bundleWithIdentifier:
@"io.flutter.application.FlutterApplication"]];
#endif
CGRect frame = [UIScreen mainScreen].bounds;
UIWindow* window = [[UIWindow alloc] initWithFrame:frame];
FlutterViewController* viewController =
[[FlutterViewController alloc] initWithDartBundle:dartBundle];
[[FlutterViewController alloc] initWithProject:project
nibName:nil
bundle:nil];
window.rootViewController = viewController;
[viewController release];
self.window = window;

View File

@ -0,0 +1,169 @@
// Copyright 2016 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.
#include "sky/shell/platform/ios/FlutterDartProject_Internal.h"
#include "sky/shell/platform/ios/FlutterDartSource.h"
@implementation FlutterDartProject {
NSBundle* _precompiledDartBundle;
FlutterDartSource* _dartSource;
VMType _vmTypeRequirement;
}
#pragma mark - Override base class designated initializers
- (instancetype)init {
return [self initWithFLXArchive:nil dartMain:nil packageRoot:nil];
}
#pragma mark - Designated initializers
- (instancetype)initWithPrecompiledDartBundle:(NSBundle*)bundle {
self = [super init];
if (self) {
_precompiledDartBundle = [bundle copy];
[self checkReadiness];
}
return self;
}
- (instancetype)initWithFLXArchive:(NSURL*)archiveURL
dartMain:(NSURL*)dartMainURL
packageRoot:(NSURL*)dartPackageURL {
self = [super init];
if (self) {
_dartSource = [[FlutterDartSource alloc] initWithDartMain:dartMainURL
packageRoot:dartPackageURL
flxArchive:archiveURL];
[self checkReadiness];
}
return self;
}
#pragma mark - Common initialization tasks
- (void)checkReadiness {
if (_precompiledDartBundle != nil) {
_vmTypeRequirement = VMTypePrecompilation;
return;
}
if (_dartSource != nil) {
_vmTypeRequirement = VMTypeInterpreter;
return;
}
}
#pragma mark - Launching the project in a preconfigured engine.
static NSString* NSStringFromVMType(VMType type) {
switch (type) {
case VMTypeInvalid:
return @"Invalid";
case VMTypeInterpreter:
return @"Interpreter";
case VMTypePrecompilation:
return @"Precompilation";
}
return @"Unknown";
}
- (void)launchInEngine:(sky::SkyEnginePtr&)engine
embedderVMType:(VMType)embedderVMType
result:(LaunchResult)result {
if (_vmTypeRequirement == VMTypeInvalid) {
result(NO, @"The Dart project is invalid and cannot be loaded by any VM.");
return;
}
if (embedderVMType == VMTypeInvalid) {
result(NO, @"The embedder is invalid.");
return;
}
if (_vmTypeRequirement != embedderVMType) {
NSString* message = [NSString
stringWithFormat:
@"Could not load the project because of differing project type. "
@"The project can run in '%@' but the embedder is configured as "
@"'%@'",
NSStringFromVMType(_vmTypeRequirement),
NSStringFromVMType(embedderVMType)];
result(NO, message);
return;
}
switch (_vmTypeRequirement) {
case VMTypeInterpreter:
[self runFromSourceInEngine:engine result:result];
return;
case VMTypePrecompilation:
[self runFromPrecompiledSourceInEngine:engine result:result];
break;
case VMTypeInvalid:
break;
}
return result(NO, @"Internal error");
}
#pragma mark - Running from precompiled application bundles
- (void)runFromPrecompiledSourceInEngine:(sky::SkyEnginePtr&)engine
result:(LaunchResult)result {
NSString* path =
[_precompiledDartBundle pathForResource:@"app" ofType:@"flx"];
if (path.length == 0) {
NSString* message =
[NSString stringWithFormat:@"Could not find the 'app.flx' archive in "
@"the precompiled Dart bundle with ID '%@'",
_precompiledDartBundle.bundleIdentifier];
result(NO, message);
return;
}
engine->RunFromPrecompiledSnapshot(path.UTF8String);
result(YES, @"Success");
}
#pragma mark - Running from source
- (void)runFromSourceInEngine:(sky::SkyEnginePtr&)engine
result:(LaunchResult)result {
if (_dartSource == nil) {
result(NO, @"Dart source not specified.");
return;
}
[_dartSource validate:^(BOOL success, NSString* message) {
if (!success) {
return result(NO, message);
}
engine->RunFromFile(_dartSource.dartMain.absoluteURL.path.UTF8String,
_dartSource.packageRoot.absoluteURL.path.UTF8String,
_dartSource.flxArchive.absoluteURL.path.UTF8String);
result(YES, @"Success");
}];
}
#pragma mark - Misc.
- (void)dealloc {
[_precompiledDartBundle release];
[_dartSource release];
[super dealloc];
}
@end

View File

@ -0,0 +1,26 @@
// Copyright 2016 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.
#include "sky/shell/platform/ios/public/FlutterDartProject.h"
#include "sky/services/engine/sky_engine.mojom.h"
enum VMType {
// An invalid VM configuration.
VMTypeInvalid = 0,
// VM can execute Dart code as an interpreter.
VMTypeInterpreter,
// VM can execute precompiled Dart code.
VMTypePrecompilation,
};
typedef void (^LaunchResult)(BOOL success, NSString* message);
@interface FlutterDartProject ()
- (void)launchInEngine:(sky::SkyEnginePtr&)engine
embedderVMType:(VMType)type
result:(LaunchResult)result;
@end

View File

@ -0,0 +1,26 @@
// Copyright 2016 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.
#ifndef SKY_SHELL_PLATFORM_IOS_FLUTTERDARTSOURCE_H_
#define SKY_SHELL_PLATFORM_IOS_FLUTTERDARTSOURCE_H_
#import <Foundation/Foundation.h>
typedef void (^ValidationResult)(BOOL result, NSString* message);
@interface FlutterDartSource : NSObject
@property(nonatomic, readonly) NSURL* dartMain;
@property(nonatomic, readonly) NSURL* packageRoot;
@property(nonatomic, readonly) NSURL* flxArchive;
- (instancetype)initWithDartMain:(NSURL*)dartMain
packageRoot:(NSURL*)packageRoot
flxArchive:(NSURL*)flxArchive NS_DESIGNATED_INITIALIZER;
- (void)validate:(ValidationResult)result;
@end
#endif // SKY_SHELL_PLATFORM_IOS_FLUTTERDARTSOURCE_H_

View File

@ -0,0 +1,73 @@
// Copyright 2016 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.
#include "sky/shell/platform/ios/FlutterDartSource.h"
@implementation FlutterDartSource {
NSURL* _dartMain;
NSURL* _packageRoot;
NSURL* _flxArchive;
}
- (instancetype)init {
return [self initWithDartMain:nil packageRoot:nil flxArchive:nil];
}
- (instancetype)initWithDartMain:(NSURL*)dartMain
packageRoot:(NSURL*)packageRoot
flxArchive:(NSURL*)flxArchive {
self = [super init];
if (self) {
_dartMain = [dartMain copy];
_packageRoot = [packageRoot copy];
_flxArchive = [flxArchive copy];
}
return self;
}
static BOOL CheckDartProjectURL(NSMutableString* log,
NSURL* url,
NSString* logLabel) {
if (url == nil) {
[log appendFormat:@"The %@ was not specified.\n", logLabel];
return false;
}
if (!url.isFileURL) {
[log appendFormat:@"The %@ must be a file URL.\n", logLabel];
return false;
}
if (![[NSFileManager defaultManager] fileExistsAtPath:url.absoluteURL.path]) {
[log appendFormat:@"No file found at '%@' when looking for the %@.\n", url,
logLabel];
return false;
}
return true;
}
- (void)validate:(ValidationResult)result {
NSMutableString* log = [[[NSMutableString alloc] init] autorelease];
BOOL isValid = YES;
isValid &= CheckDartProjectURL(log, _flxArchive, @"FLX archive");
isValid &= CheckDartProjectURL(log, _dartMain, @"Dart main");
isValid &= CheckDartProjectURL(log, _packageRoot, @"Dart package root");
result(isValid, log);
}
- (void)dealloc {
[_dartMain release];
[_packageRoot release];
[_flxArchive release];
[super dealloc];
}
@end

View File

@ -11,6 +11,7 @@
#include "sky/services/engine/sky_engine.mojom.h"
#include "sky/services/platform/ios/system_chrome_impl.h"
#include "sky/shell/platform/ios/flutter_touch_mapper.h"
#include "sky/shell/platform/ios/FlutterDartProject_Internal.h"
#include "sky/shell/platform/ios/FlutterDynamicServiceLoader.h"
#include "sky/shell/platform/ios/FlutterView.h"
#include "sky/shell/platform/mac/platform_mac.h"
@ -20,7 +21,7 @@
#include "sky/shell/shell_view.h"
@implementation FlutterViewController {
NSBundle* _dartBundle;
FlutterDartProject* _dartProject;
UIInterfaceOrientationMask _orientationPreferences;
FlutterDynamicServiceLoader* _dynamicServiceLoader;
sky::ViewportMetricsPtr _viewportMetrics;
@ -32,13 +33,13 @@
#pragma mark - Manage and override all designated initializers
- (instancetype)initWithDartBundle:(NSBundle*)dartBundleOrNil
nibName:(NSString*)nibNameOrNil
bundle:(NSBundle*)bundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:bundleOrNil];
- (instancetype)initWithProject:(FlutterDartProject*)project
nibName:(NSString*)nibNameOrNil
bundle:(NSBundle*)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_dartBundle = [dartBundleOrNil retain];
_dartProject = [project retain];
[self performCommonViewControllerInitialization];
}
@ -48,17 +49,11 @@
- (instancetype)initWithNibName:(NSString*)nibNameOrNil
bundle:(NSBundle*)nibBundleOrNil {
return [self initWithDartBundle:nil nibName:nil bundle:nil];
return [self initWithProject:nil nibName:nil bundle:nil];
}
- (instancetype)initWithCoder:(NSCoder*)aDecoder {
return [self initWithDartBundle:nil nibName:nil bundle:nil];
}
#pragma mark - Implement convenience initializers
- (instancetype)initWithDartBundle:(NSBundle*)dartBundle {
return [self initWithDartBundle:dartBundle nibName:nil bundle:nil];
return [self initWithProject:nil nibName:nil bundle:nil];
}
#pragma mark - Common view controller initialization tasks
@ -140,11 +135,28 @@
[self setupPlatformServiceProvider];
enum VMType type = VMTypeInvalid;
#if TARGET_IPHONE_SIMULATOR
[self runFromDartSource];
type = VMTypeInterpreter;
#else
[self runFromPrecompiledSource];
type = VMTypePrecompilation;
#endif
[_dartProject launchInEngine:_engine
embedderVMType:type
result:^(BOOL success, NSString* message) {
if (!success) {
UIAlertView* alert = [[UIAlertView alloc]
initWithTitle:@"Launch Error"
message:message
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}];
}
static void DynamicServiceResolve(void* baton,
@ -171,52 +183,6 @@ static void DynamicServiceResolve(void* baton,
_engine->SetServices(services.Pass());
}
#if TARGET_IPHONE_SIMULATOR
- (void)runFromDartSource {
if (sky::shell::AttemptLaunchFromCommandLineSwitches(_engine)) {
return;
}
UIAlertView* alert = [[UIAlertView alloc]
initWithTitle:@"Error"
message:@"Could not resolve one or all of either the main dart "
@"file path, the FLX bundle path or the package root "
@"on the host. Use the tooling to relaunch the "
@"application."
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
#else
- (void)runFromPrecompiledSource {
mojo::String bundle_path([self flxBundlePath]);
CHECK(bundle_path.size() != 0)
<< "There must be a valid FLX bundle to run the application";
_engine->RunFromPrecompiledSnapshot(bundle_path);
}
- (const char*)flxBundlePath {
// In case this runner is part of the precompilation SDK, the FLX bundle is
// present in the application bundle instead of the runner bundle. Attempt
// to resolve the path there first.
NSString* path = [_dartBundle pathForResource:@"app" ofType:@"flx"];
if (path.length != 0) {
return path.UTF8String;
}
return
[[NSBundle mainBundle] pathForResource:@"app" ofType:@"flx"].UTF8String;
}
#endif // TARGET_IPHONE_SIMULATOR
#pragma mark - Loading the view
- (void)loadView {
@ -459,7 +425,7 @@ static inline PointerTypeMapperPhase PointerTypePhaseFromUITouchPhase(
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_dynamicServiceLoader release];
[_dartBundle release];
[_dartProject release];
[super dealloc];
}

View File

@ -0,0 +1,25 @@
// Copyright 2016 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.
#ifndef FLUTTER_FLUTTERDARTPROJECT_H_
#define FLUTTER_FLUTTERDARTPROJECT_H_
#import <Foundation/Foundation.h>
#include "FlutterMacros.h"
FLUTTER_EXPORT
@interface FlutterDartProject : NSObject
- (instancetype)initWithPrecompiledDartBundle:(NSBundle*)bundle
NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithFLXArchive:(NSURL*)archiveURL
dartMain:(NSURL*)dartMainURL
packageRoot:(NSURL*)dartPackageURL
NS_DESIGNATED_INITIALIZER;
@end
#endif // FLUTTER_FLUTTERDARTPROJECT_H_

View File

@ -6,39 +6,16 @@
#define FLUTTER_FLUTTERVIEWCONTROLLER_H_
#include "FlutterMacros.h"
#include "FlutterDartProject.h"
#import <UIKit/UIKit.h>
FLUTTER_EXPORT
@interface FlutterViewController : UIViewController
/**
* Initialize the view controller using the specified framework bundle
* containing the precompiled Dart code.
*
* @param dartBundle the framework bundle containing the precompiled Dart code.
*
* @return the initialized view controller.
*/
- (instancetype)initWithDartBundle:(NSBundle*)dartBundle;
/**
* Initialze the view controller using the specified framework bundle
* containing the precompiled dart code.
*
* @param dartBundleOrNil the framework bundle containing the precompiled Dart
* code.
* @param nibNameOrNil the nib name.
* @param nibBundleOrNil the bundle containing the nib.
*
* @return the initialized view controller.
*
* @discussion this is the designated initializer for this class. Subclasses
* must call this method during initialzation.
*/
- (instancetype)initWithDartBundle:(NSBundle*)dartBundleOrNil
nibName:(NSString*)nibNameOrNil
bundle:(NSBundle*)nibBundleOrNil
- (instancetype)initWithProject:(FlutterDartProject*)project
nibName:(NSString*)nibNameOrNil
bundle:(NSBundle*)nibBundleOrNil
NS_DESIGNATED_INITIALIZER;
@end