未验证 提交 3cbb5e20 编写于 作者: B Ben Konyi 提交者: GitHub

Persist DartCallbackCache contents across launches (#5947)

* Updated DartCallbackCache to write callback cache to disk which is
restored on engine startup
* Ensure cache isn't moved off disk in iOS
上级 953570a7
...@@ -502,6 +502,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArgument ...@@ -502,6 +502,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArgument
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h 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/Headers/FlutterPluginAppLifeCycleDelegate.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache_Internal.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.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.h
FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.mm
......
...@@ -2,17 +2,39 @@ ...@@ -2,17 +2,39 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "flutter/lib/ui/plugins/callback_cache.h" #include <fstream>
#include <iterator>
#include "flutter/fml/build_config.h"
#include "flutter/fml/logging.h" #include "flutter/fml/logging.h"
#include "flutter/fml/paths.h"
#include "flutter/lib/ui/plugins/callback_cache.h"
#include "third_party/rapidjson/rapidjson/document.h"
#include "third_party/rapidjson/rapidjson/stringbuffer.h"
#include "third_party/rapidjson/rapidjson/writer.h"
#include "third_party/tonic/converter/dart_converter.h" #include "third_party/tonic/converter/dart_converter.h"
using rapidjson::Document;
using rapidjson::StringBuffer;
using rapidjson::Writer;
using tonic::ToDart; using tonic::ToDart;
namespace blink { namespace blink {
static const char* kHandleKey = "handle";
static const char* kRepresentationKey = "representation";
static const char* kNameKey = "name";
static const char* kClassNameKey = "class_name";
static const char* kLibraryPathKey = "library_path";
static const char* kCacheName = "flutter_callback_cache.json";
std::mutex DartCallbackCache::mutex_; std::mutex DartCallbackCache::mutex_;
std::string DartCallbackCache::cache_path_;
std::map<int64_t, DartCallbackRepresentation> DartCallbackCache::cache_; std::map<int64_t, DartCallbackRepresentation> DartCallbackCache::cache_;
void DartCallbackCache::SetCachePath(const std::string& path) {
cache_path_ = fml::paths::JoinPaths({path, kCacheName});
}
Dart_Handle DartCallbackCache::GetCallback(int64_t handle) { Dart_Handle DartCallbackCache::GetCallback(int64_t handle) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
auto iterator = cache_.find(handle); auto iterator = cache_.find(handle);
...@@ -34,6 +56,7 @@ int64_t DartCallbackCache::GetCallbackHandle(const std::string& name, ...@@ -34,6 +56,7 @@ int64_t DartCallbackCache::GetCallbackHandle(const std::string& name,
if (cache_.find(hash) == cache_.end()) { if (cache_.find(hash) == cache_.end()) {
cache_[hash] = {name, class_name, library_path}; cache_[hash] = {name, class_name, library_path};
SaveCacheToDisk();
} }
return hash; return hash;
} }
...@@ -48,6 +71,82 @@ DartCallbackCache::GetCallbackInformation(int64_t handle) { ...@@ -48,6 +71,82 @@ DartCallbackCache::GetCallbackInformation(int64_t handle) {
return nullptr; return nullptr;
} }
void DartCallbackCache::SaveCacheToDisk() {
// Cache JSON format
// [
// {
// "hash": 42,
// "representation": {
// "name": "...",
// "class_name": "...",
// "library_path": "..."
// }
// },
// {
// ...
// }
// ]
StringBuffer s;
Writer<StringBuffer> writer(s);
writer.StartArray();
for (auto iterator = cache_.begin(); iterator != cache_.end(); ++iterator) {
int64_t hash = iterator->first;
DartCallbackRepresentation cb = iterator->second;
writer.StartObject();
writer.Key(kHandleKey);
writer.Int64(hash);
writer.Key(kRepresentationKey);
writer.StartObject();
writer.Key(kNameKey);
writer.String(cb.name.c_str());
writer.Key(kClassNameKey);
writer.String(cb.class_name.c_str());
writer.Key(kLibraryPathKey);
writer.String(cb.library_path.c_str());
writer.EndObject();
writer.EndObject();
}
writer.EndArray();
std::ofstream output(cache_path_);
output << s.GetString();
output.close();
}
void DartCallbackCache::LoadCacheFromDisk() {
std::lock_guard<std::mutex> lock(mutex_);
// Don't reload the cache if it's already populated.
if (!cache_.empty()) {
return;
}
std::ifstream input(cache_path_);
if (!input) {
return;
}
std::string cache_contents{std::istreambuf_iterator<char>(input),
std::istreambuf_iterator<char>()};
Document d;
d.Parse(cache_contents.c_str());
if (d.HasParseError() || !d.IsArray()) {
FML_LOG(WARNING) << "Could not parse callback cache, aborting restore";
// TODO(bkonyi): log and bail (delete cache?)
return;
}
const auto entries = d.GetArray();
for (auto it = entries.begin(); it != entries.end(); ++it) {
const auto root_obj = it->GetObject();
const auto representation = root_obj[kRepresentationKey].GetObject();
const int64_t hash = root_obj[kHandleKey].GetInt64();
DartCallbackRepresentation cb;
cb.name = representation[kNameKey].GetString();
cb.class_name = representation[kClassNameKey].GetString();
cb.library_path = representation[kLibraryPathKey].GetString();
cache_[hash] = cb;
}
}
Dart_Handle DartCallbackCache::LookupDartClosure( Dart_Handle DartCallbackCache::LookupDartClosure(
const std::string& name, const std::string& name,
const std::string& class_name, const std::string& class_name,
......
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
#include "flutter/fml/synchronization/thread_annotations.h" #include "flutter/fml/synchronization/thread_annotations.h"
#include "third_party/dart/runtime/include/dart_api.h" #include "third_party/dart/runtime/include/dart_api.h"
#define DART_CALLBACK_INVALID_HANDLE -1
namespace blink { namespace blink {
typedef struct { typedef struct {
...@@ -26,6 +24,9 @@ typedef struct { ...@@ -26,6 +24,9 @@ typedef struct {
class DartCallbackCache { class DartCallbackCache {
public: public:
static void SetCachePath(const std::string& path);
static std::string GetCachePath() { return cache_path_; }
static int64_t GetCallbackHandle(const std::string& name, static int64_t GetCallbackHandle(const std::string& name,
const std::string& class_name, const std::string& class_name,
const std::string& library_path) const std::string& library_path)
...@@ -36,12 +37,17 @@ class DartCallbackCache { ...@@ -36,12 +37,17 @@ class DartCallbackCache {
static std::unique_ptr<DartCallbackRepresentation> GetCallbackInformation( static std::unique_ptr<DartCallbackRepresentation> GetCallbackInformation(
int64_t handle) FML_LOCKS_EXCLUDED(mutex_); int64_t handle) FML_LOCKS_EXCLUDED(mutex_);
static void LoadCacheFromDisk() FML_LOCKS_EXCLUDED(mutex_);
private: private:
static Dart_Handle LookupDartClosure(const std::string& name, static Dart_Handle LookupDartClosure(const std::string& name,
const std::string& class_name, const std::string& class_name,
const std::string& library_path); const std::string& library_path);
static void SaveCacheToDisk() FML_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
static std::mutex mutex_; static std::mutex mutex_;
static std::string cache_path_;
static std::map<int64_t, DartCallbackRepresentation> cache_ static std::map<int64_t, DartCallbackRepresentation> cache_
FML_GUARDED_BY(mutex_); FML_GUARDED_BY(mutex_);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "flutter/fml/message_loop.h" #include "flutter/fml/message_loop.h"
#include "flutter/fml/paths.h" #include "flutter/fml/paths.h"
#include "flutter/fml/platform/android/jni_util.h" #include "flutter/fml/platform/android/jni_util.h"
#include "flutter/lib/ui/plugins/callback_cache.h"
#include "flutter/runtime/dart_vm.h" #include "flutter/runtime/dart_vm.h"
#include "flutter/runtime/start_up.h" #include "flutter/runtime/start_up.h"
#include "flutter/shell/common/shell.h" #include "flutter/shell/common/shell.h"
...@@ -44,7 +45,8 @@ void FlutterMain::Init(JNIEnv* env, ...@@ -44,7 +45,8 @@ void FlutterMain::Init(JNIEnv* env,
jclass clazz, jclass clazz,
jobject context, jobject context,
jobjectArray jargs, jobjectArray jargs,
jstring bundlePath) { jstring bundlePath,
jstring appStoragePath) {
std::vector<std::string> args; std::vector<std::string> args;
args.push_back("flutter"); args.push_back("flutter");
for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) { for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) {
...@@ -56,6 +58,11 @@ void FlutterMain::Init(JNIEnv* env, ...@@ -56,6 +58,11 @@ void FlutterMain::Init(JNIEnv* env,
settings.assets_path = fml::jni::JavaStringToString(env, bundlePath); settings.assets_path = fml::jni::JavaStringToString(env, bundlePath);
// Restore the callback cache.
blink::DartCallbackCache::SetCachePath(
fml::jni::JavaStringToString(env, appStoragePath));
blink::DartCallbackCache::LoadCacheFromDisk();
if (!blink::DartVM::IsRunningPrecompiledCode()) { if (!blink::DartVM::IsRunningPrecompiledCode()) {
// Check to see if the appropriate kernel files are present and configure // Check to see if the appropriate kernel files are present and configure
// settings accordingly. // settings accordingly.
...@@ -97,7 +104,7 @@ bool FlutterMain::Register(JNIEnv* env) { ...@@ -97,7 +104,7 @@ bool FlutterMain::Register(JNIEnv* env) {
{ {
.name = "nativeInit", .name = "nativeInit",
.signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/" .signature = "(Landroid/content/Context;[Ljava/lang/String;Ljava/"
"lang/String;)V", "lang/String;Ljava/lang/String;)V",
.fnPtr = reinterpret_cast<void*>(&Init), .fnPtr = reinterpret_cast<void*>(&Init),
}, },
{ {
......
...@@ -31,7 +31,8 @@ class FlutterMain { ...@@ -31,7 +31,8 @@ class FlutterMain {
jclass clazz, jclass clazz,
jobject context, jobject context,
jobjectArray jargs, jobjectArray jargs,
jstring bundlePath); jstring bundlePath,
jstring appRootPath);
FML_DISALLOW_COPY_AND_ASSIGN(FlutterMain); FML_DISALLOW_COPY_AND_ASSIGN(FlutterMain);
}; };
......
...@@ -7,6 +7,10 @@ package io.flutter.util; ...@@ -7,6 +7,10 @@ package io.flutter.util;
import android.content.Context; import android.content.Context;
public final class PathUtils { public final class PathUtils {
public static String getFilesDir(Context applicationContext) {
return applicationContext.getFilesDir().getPath();
}
public static String getDataDirectory(Context applicationContext) { public static String getDataDirectory(Context applicationContext) {
return applicationContext.getDir("flutter", Context.MODE_PRIVATE).getPath(); return applicationContext.getDir("flutter", Context.MODE_PRIVATE).getPath();
} }
......
...@@ -219,8 +219,9 @@ public class FlutterMain { ...@@ -219,8 +219,9 @@ public class FlutterMain {
} }
String appBundlePath = findAppBundlePath(applicationContext); String appBundlePath = findAppBundlePath(applicationContext);
String appStoragePath = PathUtils.getFilesDir(applicationContext);
nativeInit(applicationContext, shellArgs.toArray(new String[0]), nativeInit(applicationContext, shellArgs.toArray(new String[0]),
appBundlePath); appBundlePath, appStoragePath);
sInitialized = true; sInitialized = true;
} catch (Exception e) { } catch (Exception e) {
...@@ -229,7 +230,7 @@ public class FlutterMain { ...@@ -229,7 +230,7 @@ public class FlutterMain {
} }
} }
private static native void nativeInit(Context context, String[] args, String bundlePath); private static native void nativeInit(Context context, String[] args, String bundlePath, String appStoragePath);
private static native void nativeRecordStartTimestamp(long initTimeMillis); private static native void nativeRecordStartTimestamp(long initTimeMillis);
/** /**
......
...@@ -46,6 +46,7 @@ shared_library("create_flutter_framework_dylib") { ...@@ -46,6 +46,7 @@ shared_library("create_flutter_framework_dylib") {
"framework/Source/FlutterAppDelegate.mm", "framework/Source/FlutterAppDelegate.mm",
"framework/Source/FlutterAppDelegate_Internal.h", "framework/Source/FlutterAppDelegate_Internal.h",
"framework/Source/FlutterCallbackCache.mm", "framework/Source/FlutterCallbackCache.mm",
"framework/Source/FlutterCallbackCache_Internal.h",
"framework/Source/FlutterChannels.mm", "framework/Source/FlutterChannels.mm",
"framework/Source/FlutterCodecs.mm", "framework/Source/FlutterCodecs.mm",
"framework/Source/FlutterDartProject.mm", "framework/Source/FlutterDartProject.mm",
......
...@@ -59,6 +59,15 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -59,6 +59,15 @@ NS_ASSUME_NONNULL_BEGIN
*/ */
- (BOOL)application:(UIApplication*)application - (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions; didFinishLaunchingWithOptions:(NSDictionary*)launchOptions;
/**
Called if this plugin has been registered for `UIApplicationDelegate` callbacks.
- Returns: `NO` if this plugin vetoes application launch.
*/
- (BOOL)application:(UIApplication*)application
willFinishLaunchingWithOptions:(NSDictionary*)launchOptions;
/** /**
Called if this plugin has been registered for `UIApplicationDelegate` callbacks. Called if this plugin has been registered for `UIApplicationDelegate` callbacks.
*/ */
...@@ -293,8 +302,8 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -293,8 +302,8 @@ NS_ASSUME_NONNULL_BEGIN
@end @end
/** /**
Implement this in the `UIAppDelegate` of your app to enable Flutter plugins to register themselves to the application Implement this in the `UIAppDelegate` of your app to enable Flutter plugins to register themselves
life cycle events. to the application life cycle events.
*/ */
@protocol FlutterAppLifeCycleProvider @protocol FlutterAppLifeCycleProvider
- (void)addApplicationLifeCycleDelegate:(NSObject<FlutterPlugin>*)delegate; - (void)addApplicationLifeCycleDelegate:(NSObject<FlutterPlugin>*)delegate;
......
...@@ -15,7 +15,8 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -15,7 +15,8 @@ NS_ASSUME_NONNULL_BEGIN
FLUTTER_EXPORT FLUTTER_EXPORT
@interface FlutterPluginAppLifeCycleDelegate : NSObject @interface FlutterPluginAppLifeCycleDelegate : NSObject
/** /**
Registers `delegate` to receive life cycle callbacks via this FlutterPluginAppLifecycleDelegate as long as it is alive. Registers `delegate` to receive life cycle callbacks via this FlutterPluginAppLifecycleDelegate as
long as it is alive.
`delegate` will only referenced weakly. `delegate` will only referenced weakly.
*/ */
...@@ -29,6 +30,14 @@ FLUTTER_EXPORT ...@@ -29,6 +30,14 @@ FLUTTER_EXPORT
- (BOOL)application:(UIApplication*)application - (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions; didFinishLaunchingWithOptions:(NSDictionary*)launchOptions;
/**
Calls all plugins registered for `UIApplicationDelegate` callbacks.
- Returns: `NO` if any plugin vetoes application launch.
*/
- (BOOL)application:(UIApplication*)application
willFinishLaunchingWithOptions:(NSDictionary*)launchOptions;
/** /**
Calls all plugins registered for `UIApplicationDelegate` callbacks. Calls all plugins registered for `UIApplicationDelegate` callbacks.
*/ */
...@@ -74,8 +83,8 @@ FLUTTER_EXPORT ...@@ -74,8 +83,8 @@ FLUTTER_EXPORT
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler;
/** /**
Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until some plugin handles Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until
the request. some plugin handles the request.
- Returns: `YES` if any plugin handles the request. - Returns: `YES` if any plugin handles the request.
*/ */
...@@ -84,16 +93,16 @@ FLUTTER_EXPORT ...@@ -84,16 +93,16 @@ FLUTTER_EXPORT
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options; options:(NSDictionary<UIApplicationOpenURLOptionsKey, id>*)options;
/** /**
Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until some plugin handles Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until
the request. some plugin handles the request.
- Returns: `YES` if any plugin handles the request. - Returns: `YES` if any plugin handles the request.
*/ */
- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url; - (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url;
/** /**
Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until some plugin handles Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until
the request. some plugin handles the request.
- Returns: `YES` if any plugin handles the request. - Returns: `YES` if any plugin handles the request.
*/ */
...@@ -111,8 +120,8 @@ FLUTTER_EXPORT ...@@ -111,8 +120,8 @@ FLUTTER_EXPORT
API_AVAILABLE(ios(9.0)); API_AVAILABLE(ios(9.0));
/** /**
Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until some plugin handles Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until
the request. some plugin handles the request.
- Returns: `YES` if any plugin handles the request. - Returns: `YES` if any plugin handles the request.
*/ */
...@@ -121,8 +130,8 @@ FLUTTER_EXPORT ...@@ -121,8 +130,8 @@ FLUTTER_EXPORT
completionHandler:(nonnull void (^)(void))completionHandler; completionHandler:(nonnull void (^)(void))completionHandler;
/** /**
Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until some plugin handles Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until
the request. some plugin handles the request.
- Returns: `YES` if any plugin handles the request. - Returns: `YES` if any plugin handles the request.
*/ */
...@@ -130,8 +139,8 @@ FLUTTER_EXPORT ...@@ -130,8 +139,8 @@ FLUTTER_EXPORT
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler;
/** /**
Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until some plugin handles Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until
the request. some plugin handles the request.
- Returns: `YES` if any plugin handles the request. - Returns: `YES` if any plugin handles the request.
*/ */
- (BOOL)application:(UIApplication*)application - (BOOL)application:(UIApplication*)application
......
...@@ -22,6 +22,11 @@ ...@@ -22,6 +22,11 @@
[super dealloc]; [super dealloc];
} }
- (BOOL)application:(UIApplication*)application
willFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
return [_lifeCycleDelegate application:application willFinishLaunchingWithOptions:launchOptions];
}
- (BOOL)application:(UIApplication*)application - (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
return [_lifeCycleDelegate application:application didFinishLaunchingWithOptions:launchOptions]; return [_lifeCycleDelegate application:application didFinishLaunchingWithOptions:launchOptions];
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache_Internal.h"
#include "flutter/lib/ui/plugins/callback_cache.h" #include "flutter/lib/ui/plugins/callback_cache.h"
...@@ -23,4 +23,24 @@ ...@@ -23,4 +23,24 @@
return new_info; return new_info;
} }
@end + (void)setCachePath:(NSString*)path {
\ No newline at end of file assert(path != nil);
blink::DartCallbackCache::SetCachePath([path UTF8String]);
NSString* cache_path =
[NSString stringWithUTF8String:blink::DartCallbackCache::GetCachePath().c_str()];
// Set the "Do Not Backup" flag to ensure that the cache isn't moved off disk in
// low-memory situations.
if (![[NSFileManager defaultManager] fileExistsAtPath:cache_path]) {
[[NSFileManager defaultManager] createFileAtPath:cache_path contents:nil attributes:nil];
NSError* error = nil;
NSURL* URL = [NSURL fileURLWithPath:cache_path];
BOOL success = [URL setResourceValue:[NSNumber numberWithBool:YES]
forKey:NSURLIsExcludedFromBackupKey
error:&error];
if (!success) {
NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
}
}
}
@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 FLUTTER_FLUTTERCALLBACKCACHE_INTERNAL_H_
#define FLUTTER_FLUTTERCALLBACKCACHE_INTERNAL_H_
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h"
@interface FlutterCallbackCache ()
+ (void)setCachePath:(NSString*)path;
@end
#endif // FLUTTER_FLUTTERCALLBACKCACHE_INTERNAL_H_
...@@ -4,7 +4,12 @@ ...@@ -4,7 +4,12 @@
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h"
#include "flutter/fml/logging.h" #include "flutter/fml/logging.h"
#include "flutter/fml/paths.h"
#include "flutter/lib/ui/plugins/callback_cache.h"
#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache_Internal.h"
static const char* kCallbackCacheSubDir = "Library/Caches/";
@implementation FlutterPluginAppLifeCycleDelegate { @implementation FlutterPluginAppLifeCycleDelegate {
UIBackgroundTaskIdentifier _debugBackgroundTask; UIBackgroundTaskIdentifier _debugBackgroundTask;
...@@ -15,6 +20,8 @@ ...@@ -15,6 +20,8 @@
- (instancetype)init { - (instancetype)init {
if (self = [super init]) { if (self = [super init]) {
std::string cachePath = fml::paths::JoinPaths({getenv("HOME"), kCallbackCacheSubDir});
[FlutterCallbackCache setCachePath:[NSString stringWithUTF8String:cachePath.c_str()]];
_pluginDelegates = [[NSPointerArray weakObjectsPointerArray] retain]; _pluginDelegates = [[NSPointerArray weakObjectsPointerArray] retain];
} }
return self; return self;
...@@ -51,6 +58,22 @@ static BOOL isPowerOfTwo(NSUInteger x) { ...@@ -51,6 +58,22 @@ static BOOL isPowerOfTwo(NSUInteger x) {
return YES; return YES;
} }
- (BOOL)application:(UIApplication*)application
willFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
blink::DartCallbackCache::LoadCacheFromDisk();
for (id<FlutterPlugin> plugin in [_pluginDelegates allObjects]) {
if (!plugin) {
continue;
}
if ([plugin respondsToSelector:_cmd]) {
if (![plugin application:application willFinishLaunchingWithOptions:launchOptions]) {
return NO;
}
}
}
return YES;
}
// Returns the key window's rootViewController, if it's a FlutterViewController. // Returns the key window's rootViewController, if it's a FlutterViewController.
// Otherwise, returns nil. // Otherwise, returns nil.
- (FlutterViewController*)rootFlutterViewController { - (FlutterViewController*)rootFlutterViewController {
......
...@@ -11171,37 +11171,6 @@ distribution. ...@@ -11171,37 +11171,6 @@ distribution.
contributors may be used to endorse or promote products derived from contributors may be used to endorse or promote products derived from
this software without specific prior written permission. this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
topaz
Copyright 2017, the Flutter project authors. Please see the AUTHORS file
for details. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册