diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index dc110cc7204df..7aeb58b5adf50 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -497,6 +497,8 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/Platfor FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java +FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterCallbackInformation.java +FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArguments.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 diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 1723c52fc9fd2..f332a60f7a97d 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -133,8 +133,10 @@ java_library("flutter_shell_java") { "io/flutter/util/PathUtils.java", "io/flutter/util/Preconditions.java", "io/flutter/view/AccessibilityBridge.java", + "io/flutter/view/FlutterCallbackInformation.java", "io/flutter/view/FlutterMain.java", "io/flutter/view/FlutterNativeView.java", + "io/flutter/view/FlutterRunArguments.java", "io/flutter/view/FlutterView.java", "io/flutter/view/ResourceCleaner.java", "io/flutter/view/ResourceExtractor.java", diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index 0420d3ba80967..83d495347122f 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -23,7 +23,8 @@ namespace shell { AndroidShellHolder::AndroidShellHolder( blink::Settings settings, - fml::jni::JavaObjectWeakGlobalRef java_object) + fml::jni::JavaObjectWeakGlobalRef java_object, + bool is_background_view) : settings_(std::move(settings)), java_object_(java_object) { static size_t shell_count = 1; auto thread_label = std::to_string(shell_count++); @@ -31,26 +32,42 @@ AndroidShellHolder::AndroidShellHolder( FML_CHECK(pthread_key_create(&thread_destruct_key_, ThreadDestructCallback) == 0); - thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU | - ThreadHost::Type::IO}; + if (is_background_view) { + thread_host_ = {thread_label, ThreadHost::Type::UI}; + } else { + thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU | + ThreadHost::Type::IO}; + } // Detach from JNI when the UI and GPU threads exit. auto jni_exit_task([key = thread_destruct_key_]() { FML_CHECK(pthread_setspecific(key, reinterpret_cast(1)) == 0); }); thread_host_.ui_thread->GetTaskRunner()->PostTask(jni_exit_task); - thread_host_.gpu_thread->GetTaskRunner()->PostTask(jni_exit_task); + if (!is_background_view) { + thread_host_.gpu_thread->GetTaskRunner()->PostTask(jni_exit_task); + } fml::WeakPtr weak_platform_view; Shell::CreateCallback on_create_platform_view = - [java_object, &weak_platform_view](Shell& shell) { - auto platform_view_android = std::make_unique( - shell, // delegate - shell.GetTaskRunners(), // task runners - java_object, // java object handle for JNI interop - shell.GetSettings() - .enable_software_rendering // use software rendering - ); + [is_background_view, java_object, &weak_platform_view](Shell& shell) { + std::unique_ptr platform_view_android; + if (is_background_view) { + platform_view_android = std::make_unique( + shell, // delegate + shell.GetTaskRunners(), // task runners + java_object // java object handle for JNI interop + ); + + } else { + platform_view_android = std::make_unique( + shell, // delegate + shell.GetTaskRunners(), // task runners + java_object, // java object handle for JNI interop + shell.GetSettings() + .enable_software_rendering // use software rendering + ); + } weak_platform_view = platform_view_android->GetWeakPtr(); return platform_view_android; }; @@ -62,13 +79,26 @@ AndroidShellHolder::AndroidShellHolder( // The current thread will be used as the platform thread. Ensure that the // message loop is initialized. fml::MessageLoop::EnsureInitializedForCurrentThread(); - - blink::TaskRunners task_runners( - thread_label, // label - fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform - thread_host_.gpu_thread->GetTaskRunner(), // gpu - thread_host_.ui_thread->GetTaskRunner(), // ui - thread_host_.io_thread->GetTaskRunner() // io + fml::RefPtr gpu_runner; + fml::RefPtr ui_runner; + fml::RefPtr io_runner; + fml::RefPtr platform_runner = + fml::MessageLoop::GetCurrent().GetTaskRunner(); + if (is_background_view) { + auto single_task_runner = thread_host_.ui_thread->GetTaskRunner(); + gpu_runner = single_task_runner; + ui_runner = single_task_runner; + io_runner = single_task_runner; + } else { + gpu_runner = thread_host_.gpu_thread->GetTaskRunner(); + ui_runner = thread_host_.ui_thread->GetTaskRunner(); + io_runner = thread_host_.io_thread->GetTaskRunner(); + } + blink::TaskRunners task_runners(thread_label, // label + platform_runner, // platform + gpu_runner, // gpu + ui_runner, // ui + io_runner // io ); shell_ = @@ -131,10 +161,12 @@ void AndroidShellHolder::Launch(RunConfiguration config) { fml::MakeCopyable([engine = shell_->GetEngine(), // config = std::move(config) // ]() mutable { - if (engine) { - if (!engine->Run(std::move(config))) { - FML_LOG(ERROR) << "Could not launch engine in configuration."; - } + FML_LOG(INFO) << "Attempting to launch engine configuration..."; + if (!engine || !engine->Run(std::move(config))) { + FML_LOG(ERROR) << "Could not launch engine in configuration."; + } else { + FML_LOG(INFO) << "Isolate for engine configuration successfully " + "started and run."; } })); } diff --git a/shell/platform/android/android_shell_holder.h b/shell/platform/android/android_shell_holder.h index 46492282f7667..e401816d3da7c 100644 --- a/shell/platform/android/android_shell_holder.h +++ b/shell/platform/android/android_shell_holder.h @@ -21,7 +21,8 @@ namespace shell { class AndroidShellHolder { public: AndroidShellHolder(blink::Settings settings, - fml::jni::JavaObjectWeakGlobalRef java_object); + fml::jni::JavaObjectWeakGlobalRef java_object, + bool is_background_view); ~AndroidShellHolder(); diff --git a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java index 3d06d7f8505b5..5c5c367723272 100644 --- a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java +++ b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java @@ -30,6 +30,7 @@ import io.flutter.util.Preconditions; import io.flutter.view.FlutterMain; import io.flutter.view.FlutterNativeView; +import io.flutter.view.FlutterRunArguments; import io.flutter.view.FlutterView; import java.util.ArrayList; @@ -162,19 +163,16 @@ public void onCreate(Bundle savedInstanceState) { } } - // When an activity is created for the first time, we direct the - // FlutterView to re-use a pre-existing Isolate rather than create a new - // one. This is so that an Isolate coming in from the ViewFactory is - // used. - final boolean reuseIsolate = true; - - if (loadIntent(activity.getIntent(), reuseIsolate)) { + if (loadIntent(activity.getIntent())) { return; } if (!flutterView.getFlutterNativeView().isApplicationRunning()) { String appBundlePath = FlutterMain.findAppBundlePath(activity.getApplicationContext()); if (appBundlePath != null) { - flutterView.runFromBundle(appBundlePath, null, "main", reuseIsolate); + FlutterRunArguments arguments = new FlutterRunArguments(); + arguments.bundlePath = appBundlePath; + arguments.entrypoint = "main"; + flutterView.runFromBundle(arguments); } } } @@ -325,11 +323,6 @@ private static String[] getArgsFromIntent(Intent intent) { } private boolean loadIntent(Intent intent) { - final boolean reuseIsolate = false; - return loadIntent(intent, reuseIsolate); - } - - private boolean loadIntent(Intent intent, boolean reuseIsolate) { String action = intent.getAction(); if (Intent.ACTION_RUN.equals(action)) { String route = intent.getStringExtra("route"); @@ -343,7 +336,10 @@ private boolean loadIntent(Intent intent, boolean reuseIsolate) { flutterView.setInitialRoute(route); } if (!flutterView.getFlutterNativeView().isApplicationRunning()) { - flutterView.runFromBundle(appBundlePath, null, "main", reuseIsolate); + FlutterRunArguments args = new FlutterRunArguments(); + args.bundlePath = appBundlePath; + args.entrypoint = "main"; + flutterView.runFromBundle(args); } return true; } diff --git a/shell/platform/android/io/flutter/view/FlutterCallbackInformation.java b/shell/platform/android/io/flutter/view/FlutterCallbackInformation.java new file mode 100644 index 0000000000000..20006dd60547c --- /dev/null +++ b/shell/platform/android/io/flutter/view/FlutterCallbackInformation.java @@ -0,0 +1,34 @@ +// 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. + +package io.flutter.view; + +/** + * A class representing information for a callback registered using + * `PluginUtilities` from `dart:ui`. + */ +public final class FlutterCallbackInformation { + final public String callbackName; + final public String callbackClassName; + final public String callbackLibraryPath; + + /** + * Get callback information for a given handle. + * @param handle the handle for the callback, generated by + * `PluginUtilities.getCallbackHandle` in `dart:ui`. + * @return an instance of FlutterCallbackInformation for the provided handle. + */ + public static FlutterCallbackInformation lookupCallbackInformation(long handle) { + return nativeLookupCallbackInformation(handle); + } + + private FlutterCallbackInformation(String callbackName, + String callbackClassName, String callbackLibraryPath) { + this.callbackName = callbackName; + this.callbackClassName = callbackClassName; + this.callbackLibraryPath = callbackLibraryPath; + } + + private static native FlutterCallbackInformation nativeLookupCallbackInformation(long handle); +} diff --git a/shell/platform/android/io/flutter/view/FlutterNativeView.java b/shell/platform/android/io/flutter/view/FlutterNativeView.java index f7b0b1b362484..c1ef24fdbe50b 100644 --- a/shell/platform/android/io/flutter/view/FlutterNativeView.java +++ b/shell/platform/android/io/flutter/view/FlutterNativeView.java @@ -29,9 +29,13 @@ public class FlutterNativeView implements BinaryMessenger { private boolean applicationIsRunning; public FlutterNativeView(Context context) { + this(context, false); + } + + public FlutterNativeView(Context context, boolean isBackgroundView) { mContext = context; mPluginRegistry = new FlutterPluginRegistry(this, context); - attach(this); + attach(this, isBackgroundView); assertAttached(); mMessageHandlers = new HashMap<>(); } @@ -68,22 +72,44 @@ public long get() { } public void assertAttached() { - if (!isAttached()) - throw new AssertionError("Platform view is not attached"); + if (!isAttached()) throw new AssertionError("Platform view is not attached"); + } + + public void runFromBundle(FlutterRunArguments args) { + if (args.bundlePath == null) { + throw new AssertionError("A bundlePath must be specified"); + } else if (args.entrypoint == null) { + throw new AssertionError("An entrypoint must be specified"); + } + runFromBundleInternal(args.bundlePath, args.entrypoint, + args.libraryPath, null); + } + + /** + * @deprecated + * Please use runFromBundle with `FlutterRunArguments`. Parameters + * `snapshotOverride` and `reuseRuntimeController` have no effect. + */ + public void runFromBundle(String bundlePath, String snapshotOverride, String entrypoint, + boolean reuseRuntimeController) { + runFromBundleInternal(bundlePath, entrypoint, null, null); } - public void runFromBundle(String bundlePath, String snapshotOverride, String entrypoint, boolean reuseRuntimeController) { + private void runFromBundleInternal(String bundlePath, String entrypoint, + String libraryPath, String snapshotOverride) { assertAttached(); if (applicationIsRunning) - throw new AssertionError("This Flutter engine instance is already running an application"); - - nativeRunBundleAndSnapshot(mNativePlatformView, bundlePath, snapshotOverride, entrypoint, reuseRuntimeController, mContext.getResources().getAssets()); + throw new AssertionError( + "This Flutter engine instance is already running an application"); + nativeRunBundleAndSnapshotFromLibrary(mNativePlatformView, bundlePath, + snapshotOverride, entrypoint, libraryPath, + mContext.getResources().getAssets()); applicationIsRunning = true; } public boolean isApplicationRunning() { - return applicationIsRunning; + return applicationIsRunning; } public static String getObservatoryUri() { @@ -92,7 +118,7 @@ public static String getObservatoryUri() { @Override public void send(String channel, ByteBuffer message) { - send(channel, message, null); + send(channel, message, null); } @Override @@ -110,8 +136,8 @@ public void send(String channel, ByteBuffer message, BinaryReply callback) { if (message == null) { nativeDispatchEmptyPlatformMessage(mNativePlatformView, channel, replyId); } else { - nativeDispatchPlatformMessage(mNativePlatformView, channel, message, - message.position(), replyId); + nativeDispatchPlatformMessage( + mNativePlatformView, channel, message, message.position(), replyId); } } @@ -124,8 +150,8 @@ public void setMessageHandler(String channel, BinaryMessageHandler handler) { } } - private void attach(FlutterNativeView view) { - mNativePlatformView = nativeAttach(view); + private void attach(FlutterNativeView view, boolean isBackgroundView) { + mNativePlatformView = nativeAttach(view, isBackgroundView); } // Called by native to send us a platform message. @@ -135,27 +161,28 @@ private void handlePlatformMessage(final String channel, byte[] message, final i if (handler != null) { try { final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message)); - handler.onMessage(buffer, - new BinaryReply() { - private final AtomicBoolean done = new AtomicBoolean(false); - @Override - public void reply(ByteBuffer reply) { - if (!isAttached()) { - Log.d(TAG, "handlePlatformMessage replying to a detached view, channel=" + channel); - return; - } - if (done.getAndSet(true)) { - throw new IllegalStateException("Reply already submitted"); - } - if (reply == null) { - nativeInvokePlatformMessageEmptyResponseCallback(mNativePlatformView, - replyId); - } else { - nativeInvokePlatformMessageResponseCallback(mNativePlatformView, - replyId, reply, reply.position()); - } + handler.onMessage(buffer, new BinaryReply() { + private final AtomicBoolean done = new AtomicBoolean(false); + @Override + public void reply(ByteBuffer reply) { + if (!isAttached()) { + Log.d(TAG, + "handlePlatformMessage replying to a detached view, channel=" + + channel); + return; + } + if (done.getAndSet(true)) { + throw new IllegalStateException("Reply already submitted"); } - }); + if (reply == null) { + nativeInvokePlatformMessageEmptyResponseCallback( + mNativePlatformView, replyId); + } else { + nativeInvokePlatformMessageResponseCallback( + mNativePlatformView, replyId, reply, reply.position()); + } + } + }); } catch (Exception ex) { Log.e(TAG, "Uncaught exception in binary message listener", ex); nativeInvokePlatformMessageEmptyResponseCallback(mNativePlatformView, replyId); @@ -179,8 +206,7 @@ private void handlePlatformMessageResponse(int replyId, byte[] reply) { // Called by native to update the semantics/accessibility tree. private void updateSemantics(ByteBuffer buffer, String[] strings) { - if (mFlutterView == null) - return; + if (mFlutterView == null) return; mFlutterView.updateSemantics(buffer, strings); } @@ -193,8 +219,7 @@ private void updateCustomAccessibilityActions(ByteBuffer buffer, String[] string // Called by native to notify first Flutter frame rendered. private void onFirstFrame() { - if (mFlutterView == null) - return; + if (mFlutterView == null) return; mFlutterView.onFirstFrame(); } @@ -206,32 +231,30 @@ private void onPreEngineRestart() { mPluginRegistry.onPreEngineRestart(); } - private static native long nativeAttach(FlutterNativeView view); + private static native long nativeAttach(FlutterNativeView view, boolean isBackgroundView); private static native void nativeDestroy(long nativePlatformViewAndroid); private static native void nativeDetach(long nativePlatformViewAndroid); - private static native void nativeRunBundleAndSnapshot(long nativePlatformViewAndroid, - String bundlePath, - String snapshotOverride, - String entrypoint, - boolean reuseRuntimeController, - AssetManager manager); + private static native void nativeRunBundleAndSnapshotFromLibrary( + long nativePlatformViewAndroid, String bundlePath, + String snapshotOverride, String entrypoint, String libraryUrl, + AssetManager manager); private static native String nativeGetObservatoryUri(); // Send an empty platform message to Dart. - private static native void nativeDispatchEmptyPlatformMessage(long nativePlatformViewAndroid, - String channel, int responseId); + private static native void nativeDispatchEmptyPlatformMessage( + long nativePlatformViewAndroid, String channel, int responseId); // Send a data-carrying platform message to Dart. private static native void nativeDispatchPlatformMessage(long nativePlatformViewAndroid, - String channel, ByteBuffer message, int position, int responseId); + String channel, ByteBuffer message, int position, int responseId); // Send an empty response to a platform message received from Dart. private static native void nativeInvokePlatformMessageEmptyResponseCallback( - long nativePlatformViewAndroid, int responseId); + long nativePlatformViewAndroid, int responseId); // Send a data-carrying response to a platform message received from Dart. private static native void nativeInvokePlatformMessageResponseCallback( - long nativePlatformViewAndroid, int responseId, ByteBuffer message, int position); + long nativePlatformViewAndroid, int responseId, ByteBuffer message, int position); } diff --git a/shell/platform/android/io/flutter/view/FlutterRunArguments.java b/shell/platform/android/io/flutter/view/FlutterRunArguments.java new file mode 100644 index 0000000000000..fb1218f57b168 --- /dev/null +++ b/shell/platform/android/io/flutter/view/FlutterRunArguments.java @@ -0,0 +1,16 @@ +// 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. + +package io.flutter.view; + +/** + * A class containing arguments for entering a FlutterNativeView's isolate for + * the first time. + */ +public class FlutterRunArguments { + public String bundlePath; + public String entrypoint; + public String libraryPath; + public String snapshotOverride; +} diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index dcd0eec65fc5e..b28ffa054d2be 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -602,20 +602,41 @@ private void preRun() { private void postRun() { } + public void runFromBundle(FlutterRunArguments args) { + assertAttached(); + preRun(); + mNativeView.runFromBundle(args); + postRun(); + } + + /** + * @deprecated + * Please use runFromBundle with `FlutterRunArguments`. Parameter + * `snapshotOverride` has no effect. + */ public void runFromBundle(String bundlePath, String snapshotOverride) { runFromBundle(bundlePath, snapshotOverride, "main", false); } + /** + * @deprecated + * Please use runFromBundle with `FlutterRunArguments`. Parameter + * `snapshotOverride` has no effect. + */ public void runFromBundle(String bundlePath, String snapshotOverride, String entrypoint) { runFromBundle(bundlePath, snapshotOverride, entrypoint, false); } - public void runFromBundle(String bundlePath, String snapshotOverride, String entrypoint, - boolean reuseRuntimeController) { - assertAttached(); - preRun(); - mNativeView.runFromBundle(bundlePath, snapshotOverride, entrypoint, reuseRuntimeController); - postRun(); + /** + * @deprecated + * Please use runFromBundle with `FlutterRunArguments`. Parameters + * `snapshotOverride` and `reuseRuntimeController` have no effect. + */ + public void runFromBundle(String bundlePath, String snapshotOverride, String entrypoint, boolean reuseRuntimeController) { + FlutterRunArguments args = new FlutterRunArguments(); + args.bundlePath = bundlePath; + args.entrypoint = entrypoint; + runFromBundle(args); } /** diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index 2df879cb40ad6..ccd6ccb0cafbe 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -30,21 +30,36 @@ PlatformViewAndroid::PlatformViewAndroid( "rendering."; } +PlatformViewAndroid::PlatformViewAndroid( + PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + fml::jni::JavaObjectWeakGlobalRef java_object) + : PlatformView(delegate, std::move(task_runners)), + java_object_(java_object), + android_surface_(nullptr) {} + PlatformViewAndroid::~PlatformViewAndroid() = default; void PlatformViewAndroid::NotifyCreated( fml::RefPtr native_window) { - InstallFirstFrameCallback(); - android_surface_->SetNativeWindow(native_window); + if (android_surface_) { + InstallFirstFrameCallback(); + android_surface_->SetNativeWindow(native_window); + } PlatformView::NotifyCreated(); } void PlatformViewAndroid::NotifyDestroyed() { PlatformView::NotifyDestroyed(); - android_surface_->TeardownOnScreenContext(); + if (android_surface_) { + android_surface_->TeardownOnScreenContext(); + } } void PlatformViewAndroid::NotifyChanged(const SkISize& size) { + if (!android_surface_) { + return; + } fml::AutoResetWaitableEvent latch; fml::TaskRunner::RunNowOrPostTask( task_runners_.GetGPUTaskRunner(), // @@ -345,11 +360,17 @@ std::unique_ptr PlatformViewAndroid::CreateVSyncWaiter() { // |shell::PlatformView| std::unique_ptr PlatformViewAndroid::CreateRenderingSurface() { + if (!android_surface_) { + return nullptr; + } return android_surface_->CreateGPUSurface(); } // |shell::PlatformView| sk_sp PlatformViewAndroid::CreateResourceContext() const { + if (!android_surface_) { + return nullptr; + } sk_sp resource_context; if (android_surface_->ResourceContextMakeCurrent()) { // TODO(chinmaygarde): Currently, this code depends on the fact that only diff --git a/shell/platform/android/platform_view_android.h b/shell/platform/android/platform_view_android.h index c3903d59e712b..b82f4474d973c 100644 --- a/shell/platform/android/platform_view_android.h +++ b/shell/platform/android/platform_view_android.h @@ -24,6 +24,13 @@ class PlatformViewAndroid final : public PlatformView { public: static bool Register(JNIEnv* env); + // Creates a PlatformViewAndroid with no rendering surface for use with + // background execution. + PlatformViewAndroid(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + fml::jni::JavaObjectWeakGlobalRef java_object); + + // Creates a PlatformViewAndroid with a rendering surface. PlatformViewAndroid(PlatformView::Delegate& delegate, blink::TaskRunners task_runners, fml::jni::JavaObjectWeakGlobalRef java_object, diff --git a/shell/platform/android/platform_view_android_jni.cc b/shell/platform/android/platform_view_android_jni.cc index 3426d5bbb5d3d..e59321ad0ce68 100644 --- a/shell/platform/android/platform_view_android_jni.cc +++ b/shell/platform/android/platform_view_android_jni.cc @@ -16,6 +16,7 @@ #include "flutter/fml/platform/android/jni_util.h" #include "flutter/fml/platform/android/jni_weak_ref.h" #include "flutter/fml/platform/android/scoped_java_ref.h" +#include "flutter/lib/ui/plugins/callback_cache.h" #include "flutter/runtime/dart_service_isolate.h" #include "flutter/shell/common/run_configuration.h" #include "flutter/shell/platform/android/android_external_texture_gl.h" @@ -43,6 +44,8 @@ bool CheckException(JNIEnv* env) { } // anonymous namespace +static fml::jni::ScopedJavaGlobalRef* g_flutter_callback_info_class = + nullptr; static fml::jni::ScopedJavaGlobalRef* g_flutter_view_class = nullptr; static fml::jni::ScopedJavaGlobalRef* g_flutter_native_view_class = nullptr; @@ -50,6 +53,19 @@ static fml::jni::ScopedJavaGlobalRef* g_surface_texture_class = nullptr; // Called By Native +static jmethodID g_flutter_callback_info_constructor = nullptr; +jobject CreateFlutterCallbackInformation( + JNIEnv* env, + const std::string& callbackName, + const std::string& callbackClassName, + const std::string& callbackLibraryPath) { + return env->NewObject(g_flutter_callback_info_class->obj(), + g_flutter_callback_info_constructor, + env->NewStringUTF(callbackName.c_str()), + env->NewStringUTF(callbackClassName.c_str()), + env->NewStringUTF(callbackLibraryPath.c_str())); +} + static jmethodID g_handle_platform_message_method = nullptr; void FlutterViewHandlePlatformMessage(JNIEnv* env, jobject obj, @@ -130,10 +146,13 @@ void SurfaceTextureDetachFromGLContext(JNIEnv* env, jobject obj) { // Called By Java -static jlong Attach(JNIEnv* env, jclass clazz, jobject flutterView) { +static jlong Attach(JNIEnv* env, + jclass clazz, + jobject flutterView, + jboolean is_background_view) { fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterView); auto shell_holder = std::make_unique( - FlutterMain::Get().GetSettings(), java_object); + FlutterMain::Get().GetSettings(), java_object, is_background_view); if (shell_holder->IsValid()) { return reinterpret_cast(shell_holder.release()); } else { @@ -218,15 +237,14 @@ std::unique_ptr CreateIsolateConfiguration( return IsolateConfiguration::CreateForAppSnapshot(); } -static void RunBundleAndSnapshot( - JNIEnv* env, - jobject jcaller, - jlong shell_holder, - jstring jbundlepath, - jstring jsnapshotOverride, - jstring jEntrypoint, - jboolean /* reuse runtime controller (unused) */, - jobject jAssetManager) { +static void RunBundleAndSnapshotFromLibrary(JNIEnv* env, + jobject jcaller, + jlong shell_holder, + jstring jbundlepath, + jstring jsnapshotOverride, + jstring jEntrypoint, + jstring jLibraryUrl, + jobject jAssetManager) { auto asset_manager = fml::MakeRefCounted(); const auto bundlepath = fml::jni::JavaStringToString(env, jbundlepath); @@ -275,7 +293,12 @@ static void RunBundleAndSnapshot( { auto entrypoint = fml::jni::JavaStringToString(env, jEntrypoint); - if (entrypoint.size() > 0) { + auto libraryUrl = fml::jni::JavaStringToString(env, jLibraryUrl); + + if ((entrypoint.size() > 0) && (libraryUrl.size() > 0)) { + config.SetEntrypointAndLibrary(std::move(entrypoint), + std::move(libraryUrl)); + } else if (entrypoint.size() > 0) { config.SetEntrypoint(std::move(entrypoint)); } } @@ -283,6 +306,17 @@ static void RunBundleAndSnapshot( ANDROID_SHELL_HOLDER->Launch(std::move(config)); } +static jobject LookupCallbackInformation(JNIEnv* env, + /* unused */ jobject, + jlong handle) { + auto cbInfo = blink::DartCallbackCache::GetCallbackInformation(handle); + if (cbInfo == nullptr) { + return nullptr; + } + return CreateFlutterCallbackInformation(env, cbInfo->name, cbInfo->class_name, + cbInfo->library_path); +} + static void SetViewportMetrics(JNIEnv* env, jobject jcaller, jlong shell_holder, @@ -516,6 +550,19 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { return false; } + g_flutter_callback_info_class = new fml::jni::ScopedJavaGlobalRef( + env, env->FindClass("io/flutter/view/FlutterCallbackInformation")); + if (g_flutter_callback_info_class->is_null()) { + return false; + } + + g_flutter_callback_info_constructor = env->GetMethodID( + g_flutter_callback_info_class->obj(), "", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (g_flutter_callback_info_constructor == nullptr) { + return false; + } + g_flutter_view_class = new fml::jni::ScopedJavaGlobalRef( env, env->FindClass("io/flutter/view/FlutterView")); if (g_flutter_view_class->is_null()) { @@ -537,7 +584,7 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { static const JNINativeMethod native_view_methods[] = { { .name = "nativeAttach", - .signature = "(Lio/flutter/view/FlutterNativeView;)J", + .signature = "(Lio/flutter/view/FlutterNativeView;Z)J", .fnPtr = reinterpret_cast(&shell::Attach), }, { @@ -546,10 +593,12 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { .fnPtr = reinterpret_cast(&shell::Destroy), }, { - .name = "nativeRunBundleAndSnapshot", - .signature = "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/" - "String;ZLandroid/content/res/AssetManager;)V", - .fnPtr = reinterpret_cast(&shell::RunBundleAndSnapshot), + .name = "nativeRunBundleAndSnapshotFromLibrary", + .signature = + "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;" + "Ljava/lang/String;Landroid/content/res/AssetManager;)V", + .fnPtr = + reinterpret_cast(&shell::RunBundleAndSnapshotFromLibrary), }, { .name = "nativeDetach", @@ -654,6 +703,14 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { }, }; + static const JNINativeMethod callback_info_methods[] = { + { + .name = "nativeLookupCallbackInformation", + .signature = "(J)Lio/flutter/view/FlutterCallbackInformation;", + .fnPtr = reinterpret_cast(&shell::LookupCallbackInformation), + }, + }; + if (env->RegisterNatives(g_flutter_native_view_class->obj(), native_view_methods, arraysize(native_view_methods)) != 0) { @@ -665,6 +722,12 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { return false; } + if (env->RegisterNatives(g_flutter_callback_info_class->obj(), + callback_info_methods, + arraysize(callback_info_methods)) != 0) { + return false; + } + g_handle_platform_message_method = env->GetMethodID(g_flutter_native_view_class->obj(), "handlePlatformMessage", "(Ljava/lang/String;[BI)V"); diff --git a/shell/platform/darwin/ios/headless_platform_view_ios.h b/shell/platform/darwin/ios/headless_platform_view_ios.h index 6481b24cfbb8d..940e2ade4af58 100644 --- a/shell/platform/darwin/ios/headless_platform_view_ios.h +++ b/shell/platform/darwin/ios/headless_platform_view_ios.h @@ -35,4 +35,4 @@ class HeadlessPlatformViewIOS : public PlatformView { } // namespace shell -#endif // SHELL_PLATFORM_IOS_HEADLESS_PLATFORM_VIEW_IOS_H_ \ No newline at end of file +#endif // SHELL_PLATFORM_IOS_HEADLESS_PLATFORM_VIEW_IOS_H_ diff --git a/shell/platform/darwin/ios/headless_platform_view_ios.mm b/shell/platform/darwin/ios/headless_platform_view_ios.mm index d80c4d50a0e5f..c496253494398 100644 --- a/shell/platform/darwin/ios/headless_platform_view_ios.mm +++ b/shell/platform/darwin/ios/headless_platform_view_ios.mm @@ -17,4 +17,4 @@ void HeadlessPlatformViewIOS::HandlePlatformMessage(fml::RefPtr message) { platform_message_router_.HandlePlatformMessage(std::move(message)); } -} \ No newline at end of file +}