未验证 提交 672e587e 编写于 作者: B Ben Konyi 提交者: GitHub

Background Execution Implementation for iOS (#5539)

上级 500f91bc
......@@ -42,7 +42,7 @@ linter:
# - avoid_bool_literals_in_conditional_expressions # not yet tested
# - avoid_catches_without_on_clauses # we do this commonly
# - avoid_catching_errors # we do this commonly
- avoid_classes_with_only_static_members
- avoid_classes_with_only_static_members # We want to avoid classes that can be instantiated but only have statics
- avoid_empty_else
- avoid_function_literals_in_foreach_calls
- avoid_init_to_null
......
......@@ -52,6 +52,8 @@ source_set("ui") {
"painting/shader.h",
"painting/vertices.cc",
"painting/vertices.h",
"plugins/callback_cache.cc",
"plugins/callback_cache.h",
"semantics/semantics_node.cc",
"semantics/semantics_node.h",
"semantics/semantics_update.cc",
......
......@@ -12,6 +12,7 @@
#include <sstream>
#include "flutter/common/settings.h"
#include "flutter/lib/ui/plugins/callback_cache.h"
#include "flutter/lib/ui/ui_dart_state.h"
#include "lib/fxl/build_config.h"
#include "lib/fxl/logging.h"
......@@ -36,6 +37,7 @@ extern void syslog(int, const char*, ...);
}
#endif
using tonic::DartConverter;
using tonic::LogIfError;
using tonic::ToDart;
......@@ -48,7 +50,9 @@ namespace blink {
#define BUILTIN_NATIVE_LIST(V) \
V(Logger_PrintString, 1) \
V(SaveCompilationTrace, 0) \
V(ScheduleMicrotask, 1)
V(ScheduleMicrotask, 1) \
V(GetCallbackHandle, 1) \
V(GetCallbackFromHandle, 1)
BUILTIN_NATIVE_LIST(DECLARE_FUNCTION);
......@@ -56,7 +60,7 @@ void DartRuntimeHooks::RegisterNatives(tonic::DartLibraryNatives* natives) {
natives->Register({BUILTIN_NATIVE_LIST(REGISTER_FUNCTION)});
}
static Dart_Handle GetClosure(Dart_Handle builtin_library, const char* name) {
static Dart_Handle GetFunction(Dart_Handle builtin_library, const char* name) {
Dart_Handle getter_name = ToDart(name);
Dart_Handle closure = Dart_Invoke(builtin_library, getter_name, 0, nullptr);
DART_CHECK_VALID(closure);
......@@ -64,7 +68,7 @@ static Dart_Handle GetClosure(Dart_Handle builtin_library, const char* name) {
}
static void InitDartInternal(Dart_Handle builtin_library, bool is_ui_isolate) {
Dart_Handle print = GetClosure(builtin_library, "_getPrintClosure");
Dart_Handle print = GetFunction(builtin_library, "_getPrintClosure");
Dart_Handle internal_library = Dart_LookupLibrary(ToDart("dart:_internal"));
......@@ -101,7 +105,7 @@ static void InitDartAsync(Dart_Handle builtin_library, bool is_ui_isolate) {
Dart_Handle schedule_microtask;
if (is_ui_isolate) {
schedule_microtask =
GetClosure(builtin_library, "_getScheduleMicrotaskClosure");
GetFunction(builtin_library, "_getScheduleMicrotaskClosure");
} else {
Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate"));
Dart_Handle method_name =
......@@ -125,7 +129,8 @@ static void InitDartIO(Dart_Handle builtin_library,
DART_CHECK_VALID(Dart_SetField(platform_type, ToDart("_nativeScript"),
ToDart(script_uri)));
}
Dart_Handle locale_closure = GetClosure(builtin_library, "_getLocaleClosure");
Dart_Handle locale_closure =
GetFunction(builtin_library, "_getLocaleClosure");
DART_CHECK_VALID(
Dart_SetField(platform_type, ToDart("_localeClosure"), locale_closure));
}
......@@ -223,4 +228,103 @@ void ScheduleMicrotask(Dart_NativeArguments args) {
UIDartState::Current()->ScheduleMicrotask(closure);
}
static std::string GetFunctionLibraryUrl(Dart_Handle closure) {
if (Dart_IsClosure(closure)) {
closure = Dart_ClosureFunction(closure);
DART_CHECK_VALID(closure);
}
if (!Dart_IsFunction(closure)) {
return "";
}
Dart_Handle url = Dart_Null();
Dart_Handle owner = Dart_FunctionOwner(closure);
if (Dart_IsInstance(owner)) {
owner = Dart_ClassLibrary(owner);
}
if (Dart_IsLibrary(owner)) {
url = Dart_LibraryUrl(owner);
DART_CHECK_VALID(url);
}
return DartConverter<std::string>::FromDart(url);
}
static std::string GetFunctionClassName(Dart_Handle closure) {
Dart_Handle result;
if (Dart_IsClosure(closure)) {
closure = Dart_ClosureFunction(closure);
DART_CHECK_VALID(closure);
}
if (!Dart_IsFunction(closure)) {
return "";
}
bool is_static = false;
result = Dart_FunctionIsStatic(closure, &is_static);
DART_CHECK_VALID(result);
if (!is_static) {
return "";
}
result = Dart_FunctionOwner(closure);
DART_CHECK_VALID(result);
if (Dart_IsLibrary(result) || !Dart_IsInstance(result)) {
return "";
}
return DartConverter<std::string>::FromDart(Dart_ClassName(result));
}
static std::string GetFunctionName(Dart_Handle func) {
DART_CHECK_VALID(func);
if (Dart_IsClosure(func)) {
func = Dart_ClosureFunction(func);
DART_CHECK_VALID(func);
}
if (!Dart_IsFunction(func)) {
return "";
}
bool is_static = false;
Dart_Handle result = Dart_FunctionIsStatic(func, &is_static);
DART_CHECK_VALID(result);
if (!is_static) {
return "";
}
result = Dart_FunctionName(func);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
return "";
}
return DartConverter<std::string>::FromDart(result);
}
void GetCallbackHandle(Dart_NativeArguments args) {
Dart_Handle func = Dart_GetNativeArgument(args, 0);
std::string name = GetFunctionName(func);
std::string class_name = GetFunctionClassName(func);
std::string library_path = GetFunctionLibraryUrl(func);
if (name.empty()) {
Dart_SetReturnValue(args, Dart_Null());
return;
}
Dart_SetReturnValue(
args, DartConverter<int64_t>::ToDart(DartCallbackCache::GetCallbackHandle(
name, class_name, library_path)));
}
void GetCallbackFromHandle(Dart_NativeArguments args) {
Dart_Handle h = Dart_GetNativeArgument(args, 0);
int64_t handle = DartConverter<int64_t>::FromDart(h);
Dart_SetReturnValue(args, DartCallbackCache::GetCallback(handle));
}
} // namespace blink
......@@ -11,6 +11,7 @@ dart_ui_files = [
"$flutter_root/lib/ui/lerp.dart",
"$flutter_root/lib/ui/natives.dart",
"$flutter_root/lib/ui/painting.dart",
"$flutter_root/lib/ui/plugins.dart",
"$flutter_root/lib/ui/pointer.dart",
"$flutter_root/lib/ui/semantics.dart",
"$flutter_root/lib/ui/text.dart",
......
......@@ -48,6 +48,9 @@ dynamic _saveCompilationTrace() native 'SaveCompilationTrace';
void _scheduleMicrotask(void callback()) native 'ScheduleMicrotask';
int _getCallbackHandle(Function closure) native 'GetCallbackHandle';
Function _getCallbackFromHandle(int handle) native 'GetCallbackFromHandle';
// Required for gen_snapshot to work correctly.
int _isolateId;
......
// Copyright 2018 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.
part of dart.ui;
/// An wrapper for a raw callback handle.
class CallbackHandle {
final int _handle;
/// Create an instance using a raw callback handle.
///
/// Only values produced by a call to [CallbackHandle.toRawHandle] should be
/// used, otherwise this object will be an invalid handle.
CallbackHandle.fromRawHandle(this._handle)
: assert(_handle != null, "'_handle' must not be null.");
/// Get the raw callback handle to pass over a [MethodChannel] or isolate
/// port.
int toRawHandle() => _handle;
@override
int get hashCode => _handle;
@override
bool operator ==(dynamic other) =>
(other is CallbackHandle) && (_handle == other._handle);
}
/// Functionality for Flutter plugin authors.
abstract class PluginUtilities {
// This class is only a namespace, and should not be instantiated or
// extended directly.
factory PluginUtilities._() => null;
static Map<Function, CallbackHandle> _forwardCache =
<Function, CallbackHandle>{};
static Map<CallbackHandle, Function> _backwardCache =
<CallbackHandle, Function>{};
/// Get a handle to a named top-level or static callback function which can
/// be easily passed between isolates.
///
/// `callback` must not be null.
///
/// Returns a [CallbackHandle] that can be provided to
/// [PluginUtilities.getCallbackFromHandle] to retrieve a tear-off of the
/// original callback. If `callback` is not a top-level or static function,
/// null is returned.
static CallbackHandle getCallbackHandle(Function callback) {
assert(callback != null, "'callback' must not be null.");
return _forwardCache.putIfAbsent(callback,
() => new CallbackHandle.fromRawHandle(_getCallbackHandle(callback)));
}
/// Get a tear-off of a named top-level or static callback represented by a
/// handle.
///
/// `handle` must not be null.
///
/// If `handle` is not a valid handle returned by
/// [PluginUtilities.getCallbackHandle], null is returned. Otherwise, a
/// tear-off of the callback associated with `handle` is returned.
static Function getCallbackFromHandle(CallbackHandle handle) {
assert(handle != null, "'handle' must not be null.");
return _backwardCache.putIfAbsent(
handle, () => _getCallbackFromHandle(handle.toRawHandle()));
}
}
// Copyright 2018 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.
#include "flutter/lib/ui/plugins/callback_cache.h"
#include "lib/fxl/logging.h"
#include "lib/tonic/converter/dart_converter.h"
using tonic::ToDart;
namespace blink {
std::mutex DartCallbackCache::mutex_;
std::map<int64_t, DartCallbackRepresentation> DartCallbackCache::cache_;
Dart_Handle DartCallbackCache::GetCallback(int64_t handle) {
std::unique_lock<std::mutex> lock(mutex_);
auto iterator = cache_.find(handle);
if (iterator != cache_.end()) {
DartCallbackRepresentation cb = iterator->second;
return LookupDartClosure(cb.name, cb.class_name, cb.library_path);
}
return Dart_Null();
}
int64_t DartCallbackCache::GetCallbackHandle(const std::string& name,
const std::string& class_name,
const std::string& library_path) {
std::unique_lock<std::mutex> lock(mutex_);
std::hash<std::string> hasher;
int64_t hash = hasher(name);
hash += hasher(class_name);
hash += hasher(library_path);
if (cache_.find(hash) == cache_.end()) {
cache_[hash] = {name, class_name, library_path};
}
return hash;
}
std::unique_ptr<DartCallbackRepresentation>
DartCallbackCache::GetCallbackInformation(int64_t handle) {
std::unique_lock<std::mutex> lock(mutex_);
auto iterator = cache_.find(handle);
if (iterator != cache_.end()) {
return std::make_unique<DartCallbackRepresentation>(iterator->second);
}
return nullptr;
}
Dart_Handle DartCallbackCache::LookupDartClosure(
const std::string& name,
const std::string& class_name,
const std::string& library_path) {
Dart_Handle closure_name = ToDart(name);
Dart_Handle library_name =
library_path.empty() ? Dart_Null() : ToDart(library_path);
Dart_Handle cls_name = class_name.empty() ? Dart_Null() : ToDart(class_name);
DART_CHECK_VALID(closure_name);
DART_CHECK_VALID(library_name);
DART_CHECK_VALID(cls_name);
Dart_Handle library;
if (library_name == Dart_Null()) {
library = Dart_RootLibrary();
} else {
library = Dart_LookupLibrary(library_name);
}
DART_CHECK_VALID(library);
Dart_Handle closure;
if (Dart_IsNull(cls_name)) {
closure = Dart_GetClosure(library, closure_name);
} else {
Dart_Handle cls = Dart_GetClass(library, cls_name);
DART_CHECK_VALID(cls);
if (Dart_IsNull(cls)) {
closure = Dart_Null();
} else {
closure = Dart_GetStaticMethodClosure(library, cls, closure_name);
}
}
DART_CHECK_VALID(closure);
return closure;
}
} // namespace blink
// Copyright 2018 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.
#ifndef FLUTTER_LIB_UI_CALLBACK_CACHE_H_
#define FLUTTER_LIB_UI_CALLBACK_CACHE_H_
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include "flutter/fml/synchronization/thread_annotations.h"
#include "lib/fxl/macros.h"
#include "third_party/dart/runtime/include/dart_api.h"
#define DART_CALLBACK_INVALID_HANDLE -1
#define LOCK_UNLOCK(m) FML_ACQUIRE(m) FML_RELEASE(m)
namespace blink {
typedef struct {
std::string name;
std::string class_name;
std::string library_path;
} DartCallbackRepresentation;
class DartCallbackCache {
public:
static int64_t GetCallbackHandle(const std::string& name,
const std::string& class_name,
const std::string& library_path)
LOCK_UNLOCK(mutex_);
static Dart_Handle GetCallback(int64_t handle) LOCK_UNLOCK(mutex_);
static std::unique_ptr<DartCallbackRepresentation> GetCallbackInformation(
int64_t handle) LOCK_UNLOCK(mutex_);
private:
static Dart_Handle LookupDartClosure(const std::string& name,
const std::string& class_name,
const std::string& library_path);
static std::mutex mutex_;
static std::map<int64_t, DartCallbackRepresentation> cache_
FML_GUARDED_BY(mutex_);
FXL_DISALLOW_IMPLICIT_CONSTRUCTORS(DartCallbackCache);
};
} // namespace blink
#endif // FLUTTER_LIB_UI_CALLBACK_CACHE_H_
......@@ -30,6 +30,7 @@ part 'isolate_name_server.dart';
part 'lerp.dart';
part 'natives.dart';
part 'painting.dart';
part 'plugins.dart';
part 'pointer.dart';
part 'semantics.dart';
part 'text.dart';
......
......@@ -487,6 +487,48 @@ bool DartIsolate::Run(const std::string& entrypoint_name) {
return true;
}
FXL_WARN_UNUSED_RESULT
bool DartIsolate::RunFromLibrary(const std::string& library_name,
const std::string& entrypoint_name) {
TRACE_EVENT0("flutter", "DartIsolate::RunFromLibrary");
if (phase_ != Phase::Ready) {
return false;
}
tonic::DartState::Scope scope(this);
Dart_Handle library = Dart_LookupLibrary(tonic::ToDart(library_name.c_str()));
if (tonic::LogIfError(library)) {
return false;
}
Dart_Handle entrypoint =
Dart_GetClosure(library, tonic::ToDart(entrypoint_name.c_str()));
if (tonic::LogIfError(entrypoint)) {
return false;
}
Dart_Handle isolate_lib = Dart_LookupLibrary(tonic::ToDart("dart:isolate"));
if (tonic::LogIfError(isolate_lib)) {
return false;
}
Dart_Handle isolate_args[] = {
entrypoint,
Dart_Null(),
};
if (tonic::LogIfError(Dart_Invoke(
isolate_lib, tonic::ToDart("_startMainIsolate"),
sizeof(isolate_args) / sizeof(isolate_args[0]), isolate_args))) {
return false;
}
phase_ = Phase::Running;
FXL_DLOG(INFO) << "New isolate is in the running state.";
return true;
}
bool DartIsolate::Shutdown() {
TRACE_EVENT0("flutter", "DartIsolate::Shutdown");
// This call may be re-entrant since Dart_ShutdownIsolate can invoke the
......
......@@ -79,6 +79,10 @@ class DartIsolate : public UIDartState {
FXL_WARN_UNUSED_RESULT
bool Run(const std::string& entrypoint);
FXL_WARN_UNUSED_RESULT
bool RunFromLibrary(const std::string& library_name,
const std::string& entrypoint);
FXL_WARN_UNUSED_RESULT
bool Shutdown();
......
......@@ -152,9 +152,17 @@ bool Engine::PrepareAndLaunchIsolate(RunConfiguration configuration) {
return false;
}
if (!isolate->Run(configuration.GetEntrypoint())) {
FXL_LOG(ERROR) << "Could not run the isolate.";
return false;
if (configuration.GetEntrypointLibrary().empty()) {
if (!isolate->Run(configuration.GetEntrypoint())) {
FXL_LOG(ERROR) << "Could not run the isolate.";
return false;
}
} else {
if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(),
configuration.GetEntrypoint())) {
FXL_LOG(ERROR) << "Could not run the isolate.";
return false;
}
}
return true;
......
......@@ -60,6 +60,12 @@ void RunConfiguration::SetEntrypoint(std::string entrypoint) {
entrypoint_ = std::move(entrypoint);
}
void RunConfiguration::SetEntrypointAndLibrary(std::string entrypoint,
std::string library) {
SetEntrypoint(entrypoint);
entrypoint_library_ = std::move(library);
}
fml::RefPtr<blink::AssetManager> RunConfiguration::GetAssetManager() const {
return asset_manager_;
}
......@@ -68,6 +74,10 @@ const std::string& RunConfiguration::GetEntrypoint() const {
return entrypoint_;
}
const std::string& RunConfiguration::GetEntrypointLibrary() const {
return entrypoint_library_;
}
std::unique_ptr<IsolateConfiguration>
RunConfiguration::TakeIsolateConfiguration() {
return std::move(isolate_configuration_);
......
......@@ -37,16 +37,21 @@ class RunConfiguration {
void SetEntrypoint(std::string entrypoint);
void SetEntrypointAndLibrary(std::string entrypoint, std::string library);
fml::RefPtr<blink::AssetManager> GetAssetManager() const;
const std::string& GetEntrypoint() const;
const std::string& GetEntrypointLibrary() const;
std::unique_ptr<IsolateConfiguration> TakeIsolateConfiguration();
private:
std::unique_ptr<IsolateConfiguration> isolate_configuration_;
fml::RefPtr<blink::AssetManager> asset_manager_;
std::string entrypoint_ = "main";
std::string entrypoint_library_ = "";
FXL_DISALLOW_COPY_AND_ASSIGN(RunConfiguration);
};
......
......@@ -22,6 +22,7 @@ _flutter_framework_headers = [
"framework/Headers/Flutter.h",
"framework/Headers/FlutterAppDelegate.h",
"framework/Headers/FlutterBinaryMessenger.h",
"framework/Headers/FlutterCallbackCache.h",
"framework/Headers/FlutterChannels.h",
"framework/Headers/FlutterCodecs.h",
"framework/Headers/FlutterDartProject.h",
......@@ -43,6 +44,8 @@ shared_library("create_flutter_framework_dylib") {
sources = [
"framework/Source/FlutterAppDelegate.mm",
"framework/Source/FlutterAppDelegate_Internal.h",
"framework/Source/FlutterCallbackCache.mm",
"framework/Source/FlutterChannels.mm",
"framework/Source/FlutterCodecs.mm",
"framework/Source/FlutterDartProject.mm",
......@@ -73,6 +76,8 @@ shared_library("create_flutter_framework_dylib") {
"framework/Source/platform_message_router.mm",
"framework/Source/vsync_waiter_ios.h",
"framework/Source/vsync_waiter_ios.mm",
"headless_platform_view_ios.h",
"headless_platform_view_ios.mm",
"ios_external_texture_gl.h",
"ios_external_texture_gl.mm",
"ios_gl_context.h",
......
......@@ -36,6 +36,7 @@
#include "FlutterAppDelegate.h"
#include "FlutterBinaryMessenger.h"
#include "FlutterCallbackCache.h"
#include "FlutterChannels.h"
#include "FlutterCodecs.h"
#include "FlutterDartProject.h"
......
// Copyright 2018 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_FLUTTERCALLBACKCACHE_H_
#define FLUTTER_FLUTTERCALLBACKCACHE_H_
#import <Foundation/Foundation.h>
#include "FlutterMacros.h"
FLUTTER_EXPORT
@interface FlutterCallbackInformation : NSObject
@property(retain) NSString* callbackName;
@property(retain) NSString* callbackClassName;
@property(retain) NSString* callbackLibraryPath;
@end
FLUTTER_EXPORT
@interface FlutterCallbackCache : NSObject
/**
Returns the callback information for the given callback handle.
This callback information can be used when spawning a
FlutterHeadlessDartRunner.
- Parameter handle: The handle for a callback, provided by the
Dart method `PluginUtilities.getCallbackHandle`.
- Returns: A FlutterCallbackInformation object which contains the name of the
callback, the name of the class in which the callback is defined, and the
path of the library which contains the callback. If the provided handle is
invalid, nil is returned.
*/
+ (FlutterCallbackInformation*)lookupCallbackInformation:(int64_t)handle;
@end
#endif // FLUTTER_FLUTTERCALLBACKCACHE_H_
......@@ -7,28 +7,51 @@
#import <Foundation/Foundation.h>
#include "FlutterBinaryMessenger.h"
#include "FlutterDartProject.h"
#include "FlutterMacros.h"
/**
A callback for when FlutterHeadlessDartRunner has attempted to start a Dart
Isolate in the background.
- Parameter success: YES if the Isolate was started and run successfully, NO
otherwise.
*/
typedef void (^FlutterHeadlessDartRunnerCallback)(BOOL success);
/**
The FlutterHeadlessDartRunner runs Flutter Dart code with a null rasterizer,
and no native drawing surface. It is appropriate for use in running Dart
code e.g. in the background from a plugin.
*/
FLUTTER_EXPORT
@interface FlutterHeadlessDartRunner : NSObject
@interface FlutterHeadlessDartRunner : NSObject <FlutterBinaryMessenger>
/**
Runs a Dart function on an Isolate that is not the main application's Isolate.
The first call will create a new Isolate. Subsequent calls will reuse that
Isolate. The Isolate is destroyed when the FlutterHeadlessDartRunner is
destroyed.
The first call will create a new Isolate. Subsequent calls will return
immediately.
- Parameter entrypoint: The name of a top-level function from the same Dart
library that contains the app's main() function.
*/
- (void)runWithEntrypoint:(NSString*)entrypoint;
/**
Runs a Dart function on an Isolate that is not the main application's Isolate.
The first call will create a new Isolate. Subsequent calls will return
immediately.
- Parameter entrypoint: The name of a top-level function from a Dart library.
- Parameter uri: The URI of the Dart library which contains entrypoint.
- Parameter callback: The callback to be invoked when the new Isolate is
invoked.
*/
- (void)runWithEntrypointAndCallback:(NSString*)entrypoint
libraryUri:(NSString*)uri
completion:(FlutterHeadlessDartRunnerCallback)callback;
@end
#endif // FLUTTER_FLUTTERHEADLESSDARTRUNNER_H_
// Copyright 2018 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.
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h"
@interface FlutterAppDelegate ()
@property(readonly, nonatomic) NSMutableArray* pluginDelegates;
@property(readonly, nonatomic) NSMutableDictionary* pluginPublications;
@end
@interface FlutterAppDelegateRegistrar : NSObject <FlutterPluginRegistrar>
- (instancetype)initWithPlugin:(NSString*)pluginKey appDelegate:(FlutterAppDelegate*)delegate;
@end
// Copyright 2018 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 "flutter/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h"
#include "flutter/lib/ui/plugins/callback_cache.h"
@implementation FlutterCallbackInformation
@end
@implementation FlutterCallbackCache
+ (FlutterCallbackInformation*)lookupCallbackInformation:(int64_t)handle {
auto info = blink::DartCallbackCache::GetCallbackInformation(handle);
if (info == nullptr) {
return nil;
}
FlutterCallbackInformation* new_info = [[FlutterCallbackInformation alloc] init];
new_info.callbackName = [NSString stringWithUTF8String:info->name.c_str()];
new_info.callbackClassName = [NSString stringWithUTF8String:info->class_name.c_str()];
new_info.callbackLibraryPath = [NSString stringWithUTF8String:info->library_path.c_str()];
return new_info;
}
@end
\ No newline at end of file
......@@ -8,6 +8,7 @@
#include <functional>
#include <memory>
#include <sstream>
#include "flutter/fml/message_loop.h"
#include "flutter/shell/common/engine.h"
......@@ -17,29 +18,44 @@
#include "flutter/shell/common/switches.h"
#include "flutter/shell/common/thread_host.h"
#include "flutter/shell/platform/darwin/common/command_line.h"
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h"
#include "flutter/shell/platform/darwin/ios/headless_platform_view_ios.h"
#include "flutter/shell/platform/darwin/ios/platform_view_ios.h"
#include "lib/fxl/functional/make_copyable.h"
static std::unique_ptr<shell::PlatformView> CreateHeadlessPlatformView(shell::Shell& shell) {
return std::make_unique<shell::PlatformView>(shell, shell.GetTaskRunners());
static std::unique_ptr<shell::HeadlessPlatformViewIOS> CreateHeadlessPlatformView(
shell::Shell& shell) {
return std::make_unique<shell::HeadlessPlatformViewIOS>(shell, shell.GetTaskRunners());
}
static std::unique_ptr<shell::Rasterizer> CreateHeadlessRasterizer(shell::Shell& shell) {
return std::make_unique<shell::Rasterizer>(shell.GetTaskRunners());
}
static std::string CreateShellLabel() {
static size_t count = 1;
std::stringstream stream;
stream << "io.flutter.headless.";
stream << count++;
return stream.str();
}
@implementation FlutterHeadlessDartRunner {
shell::ThreadHost _threadHost;
std::unique_ptr<shell::Shell> _shell;
}
- (void)runWithEntrypoint:(NSString*)entrypoint {
- (void)runWithEntrypointAndCallback:(NSString*)entrypoint
libraryUri:(NSString*)uri
completion:(FlutterHeadlessDartRunnerCallback)callback {
if (_shell != nullptr || entrypoint.length == 0) {
FXL_LOG(ERROR) << "This headless dart runner was already used to run some code.";
return;
}
const auto label = "io.flutter.headless";
const auto label = CreateShellLabel();
// Create the threads to run the shell on.
_threadHost = {
......@@ -59,6 +75,10 @@ static std::unique_ptr<shell::Rasterizer> CreateHeadlessRasterizer(shell::Shell&
auto settings = shell::SettingsFromCommandLine(shell::CommandLineFromNSProcessInfo());
// These values set the name of the isolate for debugging.
settings.advisory_script_entrypoint = entrypoint.UTF8String;
settings.advisory_script_uri = uri.UTF8String;
// Create the shell. This is a blocking operation.
_shell = shell::Shell::Create(
std::move(task_runners), // task runners
......@@ -77,16 +97,61 @@ static std::unique_ptr<shell::Rasterizer> CreateHeadlessRasterizer(shell::Shell&
[[[FlutterDartProject alloc] initFromDefaultSourceForConfiguration] autorelease];
auto config = project.runConfiguration;
config.SetEntrypoint(entrypoint.UTF8String);
config.SetEntrypointAndLibrary(entrypoint.UTF8String, uri.UTF8String);
// Override the default run configuration with the specified entrypoint.
_shell->GetTaskRunners().GetUITaskRunner()->PostTask(
fxl::MakeCopyable([engine = _shell->GetEngine(), config = std::move(config)]() mutable {
fxl::MakeCopyable([engine = _shell->GetEngine(), config = std::move(config),
callback = Block_copy(callback)]() mutable {
BOOL success = NO;
FXL_LOG(INFO) << "Attempting to launch background engine configuration...";
if (!engine || !engine->Run(std::move(config))) {
FXL_LOG(ERROR) << "Could not launch engine with configuration.";
} else {
FXL_LOG(INFO) << "Background Isolate successfully started and run.";
success = YES;
}
if (callback != nil) {
callback(success);
Block_release(callback);
}
}));
}
- (void)runWithEntrypoint:(NSString*)entrypoint {
[self runWithEntrypointAndCallback:entrypoint libraryUri:nil completion:nil];
}
#pragma mark - FlutterBinaryMessenger
- (void)sendOnChannel:(NSString*)channel message:(NSData*)message {
[self sendOnChannel:channel message:message binaryReply:nil];
}
- (void)sendOnChannel:(NSString*)channel
message:(NSData*)message
binaryReply:(FlutterBinaryReply)callback {
NSAssert(channel, @"The channel must not be null");
fxl::RefPtr<shell::PlatformMessageResponseDarwin> response =
(callback == nil) ? nullptr
: fxl::MakeRefCounted<shell::PlatformMessageResponseDarwin>(
^(NSData* reply) {
callback(reply);
},
_shell->GetTaskRunners().GetPlatformTaskRunner());
fxl::RefPtr<blink::PlatformMessage> platformMessage =
(message == nil) ? fxl::MakeRefCounted<blink::PlatformMessage>(channel.UTF8String, response)
: fxl::MakeRefCounted<blink::PlatformMessage>(
channel.UTF8String, shell::GetVectorFromNSData(message), response);
_shell->GetPlatformView()->DispatchPlatformMessage(platformMessage);
}
- (void)setMessageHandlerOnChannel:(NSString*)channel
binaryMessageHandler:(FlutterBinaryMessageHandler)handler {
reinterpret_cast<shell::HeadlessPlatformViewIOS*>(_shell->GetPlatformView().get())
->GetPlatformMessageRouter()
.SetMessageHandler(channel.UTF8String, handler);
}
@end
// Copyright 2018 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 SHELL_PLATFORM_IOS_HEADLESS_PLATFORM_VIEW_IOS_H_
#define SHELL_PLATFORM_IOS_HEADLESS_PLATFORM_VIEW_IOS_H_
#include <memory>
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/fml/platform/darwin/scoped_nsobject.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h"
#include "lib/fxl/functional/closure.h"
#include "lib/fxl/macros.h"
namespace shell {
class HeadlessPlatformViewIOS : public PlatformView {
public:
explicit HeadlessPlatformViewIOS(Delegate& delegate,
blink::TaskRunners task_runners);
virtual ~HeadlessPlatformViewIOS();
PlatformMessageRouter& GetPlatformMessageRouter();
private:
PlatformMessageRouter platform_message_router_;
// |shell::PlatformView|
void HandlePlatformMessage(fxl::RefPtr<blink::PlatformMessage> message);
FXL_DISALLOW_COPY_AND_ASSIGN(HeadlessPlatformViewIOS);
};
} // namespace shell
#endif // SHELL_PLATFORM_IOS_HEADLESS_PLATFORM_VIEW_IOS_H_
\ No newline at end of file
#include "flutter/shell/platform/darwin/ios/headless_platform_view_ios.h"
namespace shell {
HeadlessPlatformViewIOS::HeadlessPlatformViewIOS(PlatformView::Delegate& delegate,
blink::TaskRunners task_runners)
: PlatformView(delegate, std::move(task_runners)) {}
HeadlessPlatformViewIOS::~HeadlessPlatformViewIOS() = default;
PlatformMessageRouter& HeadlessPlatformViewIOS::GetPlatformMessageRouter() {
return platform_message_router_;
}
// |shell::PlatformView|
void HeadlessPlatformViewIOS::HandlePlatformMessage(fxl::RefPtr<blink::PlatformMessage> message) {
platform_message_router_.HandlePlatformMessage(std::move(message));
}
}
\ No newline at end of file
......@@ -14,14 +14,14 @@
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h"
#include "flutter/shell/platform/darwin/ios/headless_platform_view_ios.h"
#include "flutter/shell/platform/darwin/ios/ios_surface.h"
#include "lib/fxl/functional/closure.h"
#include "lib/fxl/macros.h"
namespace shell {
class PlatformViewIOS final : public PlatformView {
class PlatformViewIOS final : public HeadlessPlatformViewIOS {
public:
explicit PlatformViewIOS(PlatformView::Delegate& delegate,
blink::TaskRunners task_runners,
......@@ -30,8 +30,6 @@ class PlatformViewIOS final : public PlatformView {
~PlatformViewIOS() override;
PlatformMessageRouter& GetPlatformMessageRouter();
FlutterViewController* GetOwnerViewController() const;
void RegisterExternalTexture(int64_t id, NSObject<FlutterTexture>* texture);
......@@ -59,9 +57,6 @@ class PlatformViewIOS final : public PlatformView {
// |shell::PlatformView|
void SetSemanticsEnabled(bool enabled) override;
// |shell::PlatformView|
void HandlePlatformMessage(
fxl::RefPtr<blink::PlatformMessage> message) override;
// |shell::PlatformView|
void UpdateSemantics(blink::SemanticsNodeUpdates update,
......
......@@ -21,7 +21,7 @@ PlatformViewIOS::PlatformViewIOS(PlatformView::Delegate& delegate,
blink::TaskRunners task_runners,
FlutterViewController* owner_controller,
FlutterView* owner_view)
: PlatformView(delegate, std::move(task_runners)),
: HeadlessPlatformViewIOS(delegate, std::move(task_runners)),
owner_controller_(owner_controller),
owner_view_(owner_view),
ios_surface_(owner_view_.createSurface) {
......@@ -36,10 +36,6 @@ FlutterViewController* PlatformViewIOS::GetOwnerViewController() const {
return owner_controller_;
}
PlatformMessageRouter& PlatformViewIOS::GetPlatformMessageRouter() {
return platform_message_router_;
}
void PlatformViewIOS::RegisterExternalTexture(int64_t texture_id,
NSObject<FlutterTexture>* texture) {
RegisterTexture(std::make_shared<IOSExternalTextureGL>(texture_id, texture));
......@@ -79,11 +75,6 @@ void PlatformViewIOS::UpdateSemantics(blink::SemanticsNodeUpdates update,
}
}
// |shell::PlatformView|
void PlatformViewIOS::HandlePlatformMessage(fxl::RefPtr<blink::PlatformMessage> message) {
platform_message_router_.HandlePlatformMessage(std::move(message));
}
// |shell::PlatformView|
std::unique_ptr<VsyncWaiter> PlatformViewIOS::CreateVSyncWaiter() {
return std::make_unique<VsyncWaiterIOS>(task_runners_);
......
// Copyright 2018 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 'dart:ui';
import 'package:test/test.dart';
String top() => "top";
class Foo {
const Foo();
static int getInt() => 1;
double getDouble() => 1.0;
}
const Foo foo = const Foo();
void main() {
test('PluginUtilities Callback Handles', () {
// Top level callback.
final hTop = PluginUtilities.getCallbackHandle(top);
expect(hTop, isNotNull);
expect(hTop, isNot(0));
expect(PluginUtilities.getCallbackHandle(top), hTop);
final topClosure = PluginUtilities.getCallbackFromHandle(hTop);
expect(topClosure, isNotNull);
expect(topClosure(), "top");
// Static method callback
final hGetInt = PluginUtilities.getCallbackHandle(Foo.getInt);
expect(hGetInt, isNotNull);
expect(hGetInt, isNot(0));
expect(PluginUtilities.getCallbackHandle(Foo.getInt), hGetInt);
final getIntClosure = PluginUtilities.getCallbackFromHandle(hGetInt);
expect(getIntClosure, isNotNull);
expect(getIntClosure(), 1);
// Instance method callbacks cannot be looked up.
final foo = new Foo();
expect(PluginUtilities.getCallbackHandle(foo.getDouble), isNull);
});
}
# Generated by pub
# See https://www.dartlang.org/tools/pub/glossary#lockfile
# See http://pub.dartlang.org/doc/glossary.html#lockfile
packages:
archive:
dependency: "direct main"
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.33"
args:
dependency: "direct main"
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.7"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.5"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
crypto:
dependency: "direct main"
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2+1"
path:
dependency: "direct main"
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.1"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.5"
sdks:
dart: ">=1.21.0 <=2.0.0-edge.2b36f923d95a41b2f1c5cbb5edd9872f68c18112"
dart: ">=1.21.0 <2.0.0"
......@@ -206,6 +206,7 @@ FILE: ../../../flutter/shell/platform/darwin/desktop/Info.plist
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Flutter.podspec
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Info.plist
FILE: ../../../flutter/shell/platform/darwin/ios/framework/module.modulemap
FILE: ../../../flutter/shell/platform/darwin/ios/headless_platform_view_ios.mm
FILE: ../../../flutter/shell/platform/embedder/assets/EmbedderInfo.plist
FILE: ../../../flutter/shell/platform/embedder/assets/embedder.modulemap
FILE: ../../../flutter/shell/platform/embedder/fixtures/simple_main.dart
......@@ -489,6 +490,7 @@ FILE: ../../../flutter/flutter_kernel_transformers/lib/track_widget_constructor_
FILE: ../../../flutter/lib/ui/isolate_name_server.dart
FILE: ../../../flutter/lib/ui/painting/image_encoding.cc
FILE: ../../../flutter/lib/ui/painting/image_encoding.h
FILE: ../../../flutter/lib/ui/plugins.dart
FILE: ../../../flutter/lib/ui/semantics/custom_accessibility_action.cc
FILE: ../../../flutter/lib/ui/semantics/custom_accessibility_action.h
FILE: ../../../flutter/lib/ui/text/asset_manager_font_provider.cc
......@@ -499,10 +501,13 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/Platfor
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewRegistry.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewRegistryImpl.java
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.mm
FILE: ../../../flutter/shell/platform/darwin/ios/headless_platform_view_ios.h
----------------------------------------------------------------------------------------------------
Copyright 2018 The Chromium Authors. All rights reserved.
......@@ -590,12 +595,15 @@ FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server.cc
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server.h
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server_natives.cc
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server_natives.h
FILE: ../../../flutter/lib/ui/plugins/callback_cache.cc
FILE: ../../../flutter/lib/ui/plugins/callback_cache.h
FILE: ../../../flutter/shell/common/isolate_configuration.cc
FILE: ../../../flutter/shell/common/isolate_configuration.h
FILE: ../../../flutter/shell/platform/android/android_shell_holder.cc
FILE: ../../../flutter/shell/platform/android/android_shell_holder.h
FILE: ../../../flutter/shell/platform/android/platform_message_response_android.cc
FILE: ../../../flutter/shell/platform/android/platform_message_response_android.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm
----------------------------------------------------------------------------------------------------
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册