Skip to content

Commit

Permalink
Implement support for Flutter Plugins (#8)
Browse files Browse the repository at this point in the history
* plugins WIP

* Add flutter plugins support for macOS

#6

* Add flutter plugins support for windows

* Move macOS resources to res/macos

* Short-circuit to empty registrar if there are no plugins

* Add flutter plugin support for linux

* Update XCode project file to specify SWIFT_VERSION

* Handle FFI only plugins
  • Loading branch information
knopp committed Jun 6, 2021
1 parent e07c6b9 commit 9907040
Show file tree
Hide file tree
Showing 27 changed files with 986 additions and 109 deletions.
5 changes: 3 additions & 2 deletions nativeshell/src/shell/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ use std::rc::Rc;
use crate::{util::LateRefCell, Error, Result};

use super::{
platform::{drag_data::DragDataAdapter, init::init_platform},
platform::{drag_data::DragDataAdapter, engine::PlatformPlugin, init::init_platform},
EngineManager, MenuManager, MessageManager, RunLoop, WindowManager, WindowMethodChannel,
};

pub struct ContextOptions {
pub app_namespace: String,

pub flutter_plugins: Vec<PlatformPlugin>,
pub on_last_engine_removed: Box<dyn Fn(Rc<Context>)>,
pub custom_drag_data_adapters: Vec<Box<dyn DragDataAdapter>>,
}
Expand All @@ -18,6 +18,7 @@ impl Default for ContextOptions {
fn default() -> Self {
Self {
app_namespace: Default::default(),
flutter_plugins: Vec::new(),
on_last_engine_removed: Box::new(|context| context.run_loop.borrow().stop()),
custom_drag_data_adapters: Vec::new(),
}
Expand Down
9 changes: 6 additions & 3 deletions nativeshell/src/shell/engine.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use super::{platform::engine::PlatformEngine, BinaryMessenger};
use super::{
platform::engine::{PlatformEngine, PlatformPlugin},
BinaryMessenger,
};
use crate::Result;

pub struct FlutterEngine {
Expand All @@ -7,8 +10,8 @@ pub struct FlutterEngine {
}

impl FlutterEngine {
pub fn create() -> Self {
let platform_engine = PlatformEngine::new();
pub fn create(plugins: &[PlatformPlugin]) -> Self {
let platform_engine = PlatformEngine::new(plugins);

let messenger = BinaryMessenger::new(platform_engine.new_binary_messenger());
FlutterEngine {
Expand Down
2 changes: 1 addition & 1 deletion nativeshell/src/shell/engine_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ impl EngineManager {
}

pub fn create_engine(&mut self) -> EngineHandle {
let engine = FlutterEngine::create();
let engine = FlutterEngine::create(&self.context.options.flutter_plugins);
let handle = self.next_handle;
self.next_handle.0 += 1;
self.engines.insert(handle, Box::new(RefCell::new(engine)));
Expand Down
9 changes: 9 additions & 0 deletions nativeshell/src/shell/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#[macro_export]
macro_rules! include_flutter_plugins {
() => {
::std::include!(::std::concat!(
::std::env!("OUT_DIR"),
"/generated_plugins_registrar.rs"
));
};
}
2 changes: 2 additions & 0 deletions nativeshell/src/shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod context;
mod engine;
mod engine_manager;
mod geometry;
mod macros;
mod menu_manager;
mod message_manager;
mod observatory;
Expand All @@ -19,6 +20,7 @@ pub use context::*;
pub use engine::*;
pub use engine_manager::*;
pub use geometry::*;
pub use macros::*;
pub use menu_manager::*;
pub use message_manager::*;
pub use observatory::*;
Expand Down
15 changes: 14 additions & 1 deletion nativeshell/src/shell/platform/linux/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,23 @@ struct _FlEngine {
_engine: isize,
}

pub struct PlatformPlugin {
pub name: String,
pub register_func: Option<unsafe extern "C" fn(registrar: *mut std::os::raw::c_void)>,
}

impl PlatformEngine {
pub fn new() -> Self {
pub fn new(plugins: &[PlatformPlugin]) -> Self {
let project = flutter::DartProject::new();
let view = flutter::View::new(&project);
for plugin in plugins {
let registrar = view.get_registrar_for_plugin(&plugin.name);
if let Some(func) = plugin.register_func {
unsafe {
func(registrar);
}
}
}
PlatformEngine { view }
}

Expand Down
15 changes: 14 additions & 1 deletion nativeshell/src/shell/platform/linux/flutter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#![allow(clippy::from_over_into)]

use std::{mem::ManuallyDrop, os::raw::c_char};
use std::{
mem::ManuallyDrop,
os::raw::{c_char, c_void},
};

use super::flutter_sys;
use glib::{glib_wrapper, Object};
Expand Down Expand Up @@ -46,6 +49,7 @@ impl View {

pub trait ViewExt: 'static {
fn get_engine(&self) -> Engine;
fn get_registrar_for_plugin(&self, plugin: &str) -> *mut c_void;
}

impl<O: IsA<View>> ViewExt for O {
Expand All @@ -57,6 +61,15 @@ impl<O: IsA<View>> ViewExt for O {
.unsafe_cast()
}
}

fn get_registrar_for_plugin(&self, plugin: &str) -> *mut c_void {
unsafe {
flutter_sys::fl_plugin_registry_get_registrar_for_plugin(
self.as_ref().to_glib_none().0,
plugin.to_glib_none().0,
)
}
}
}

glib_wrapper! {
Expand Down
7 changes: 6 additions & 1 deletion nativeshell/src/shell/platform/linux/flutter_sys.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
extern crate gobject_sys;
extern crate gtk_sys;

use std::os::raw::c_char;
use std::os::raw::{c_char, c_void};

use gobject_sys::{GObject, GObjectClass};
use gtk_sys::{GtkContainer, GtkContainerClass, GtkWidget};
Expand Down Expand Up @@ -113,4 +113,9 @@ extern "C" {
result: *mut gio_sys::GAsyncResult,
error: *mut *mut glib_sys::GError,
) -> *mut glib_sys::GBytes;

pub fn fl_plugin_registry_get_registrar_for_plugin(
registry: *mut FlView,
name: *const c_char,
) -> *mut c_void;
}
29 changes: 27 additions & 2 deletions nativeshell/src/shell/platform/macos/engine.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use std::ffi::c_void;

use cocoa::base::{id, nil, BOOL, NO};
use log::warn;
use objc::rc::{autoreleasepool, StrongPtr};

use crate::shell::platform::key_interceptor::override_key_event;
use crate::shell::platform::{
key_interceptor::override_key_event,
platform_impl::utils::{class_from_string, to_nsstring},
};

use super::{
binary_messenger::PlatformBinaryMessenger,
Expand All @@ -15,14 +19,35 @@ pub struct PlatformEngine {
pub(super) view_controller: StrongPtr,
}

pub struct PlatformPlugin {
pub name: String,
pub class: String,
}

impl PlatformEngine {
pub fn new() -> Self {
pub fn new(plugins: &[PlatformPlugin]) -> Self {
autoreleasepool(|| unsafe {
let class = class!(FlutterViewController);
let view_controller: id = msg_send![class, alloc];
let view_controller = StrongPtr::new(msg_send![view_controller, initWithProject: nil]);
let engine: id = msg_send![*view_controller, engine];
let embedder_api: *mut c_void = msg_send![engine, embedderAPI];

// register plugins with this engine
for plugin in plugins {
let class = class_from_string(&plugin.class);
if class.is_null() {
warn!(
"Plugin {} for plugin {} not found",
plugin.name, plugin.class
);
} else {
let registrar: id =
msg_send![engine, registrarForPlugin: *to_nsstring(&plugin.name)];
let () = msg_send![class, registerWithRegistrar: registrar];
}
}

override_key_event(embedder_api);
Self {
handle: StrongPtr::retain(engine),
Expand Down
6 changes: 6 additions & 0 deletions nativeshell/src/shell/platform/macos/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,9 @@ pub(super) fn class_decl_from_name(name: &str) -> ManuallyDrop<ClassDecl> {
// class, and it's now worth replicating the entire functionality here
ManuallyDrop::new(unsafe { std::mem::transmute(res) })
}

pub(super) fn class_from_string(name: &str) -> *mut Class {
let name = CString::new(name).unwrap();
let class = unsafe { objc_getClass(name.as_ptr() as *const _) as *mut _ };
return class;
}
4 changes: 3 additions & 1 deletion nativeshell/src/shell/platform/null/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ use super::{binary_messenger::PlatformBinaryMessenger, error::PlatformResult};

pub struct PlatformEngine {}

pub type PlatformPlugin = isize;

impl PlatformEngine {
pub fn new() -> Self {
pub fn new(_plugins: &[PlatformPlugin]) -> Self {
PlatformEngine {}
}

Expand Down
24 changes: 21 additions & 3 deletions nativeshell/src/shell/platform/win32/engine.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{mem::size_of, ptr};
use std::{ffi::CString, mem::size_of, ptr};

use crate::shell::platform::key_interceptor::override_key_event;

Expand All @@ -7,7 +7,8 @@ use super::{
error::PlatformResult,
flutter_sys::{
FlutterDesktopEngineCreate, FlutterDesktopEngineDestroy, FlutterDesktopEngineGetMessenger,
FlutterDesktopEngineProperties, FlutterDesktopEngineRef,
FlutterDesktopEngineGetPluginRegistrar, FlutterDesktopEngineProperties,
FlutterDesktopEngineRef,
},
util::to_utf16,
};
Expand All @@ -16,8 +17,13 @@ pub struct PlatformEngine {
pub(super) handle: FlutterDesktopEngineRef,
}

pub struct PlatformPlugin {
pub name: String,
pub register_func: Option<unsafe extern "C" fn(registrar: *mut std::os::raw::c_void)>,
}

impl PlatformEngine {
pub fn new() -> Self {
pub fn new(plugins: &[PlatformPlugin]) -> Self {
let assets = to_utf16("data\\flutter_assets");
let icu = to_utf16("data\\icudtl.dat");
let aot = to_utf16("data\\app.so");
Expand All @@ -31,6 +37,18 @@ impl PlatformEngine {

let engine = unsafe { FlutterDesktopEngineCreate(&properties) };

// register plugins
for plugin in plugins {
let name = CString::new(plugin.name.as_str()).unwrap();
let registrar =
unsafe { FlutterDesktopEngineGetPluginRegistrar(engine, name.as_ptr()) };
if let Some(register_func) = plugin.register_func {
unsafe {
register_func(registrar as *mut _);
}
}
}

unsafe {
// TODO: This makes assumption about internal engine layout and will possibly
// break in future;
Expand Down
11 changes: 11 additions & 0 deletions nativeshell_build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,14 @@ pathdiff = "0.2.0"
path-slash = "0.1.4"
dunce = "1.0.1"
copy_dir = "0.1.2"
yaml-rust = "0.4"

[target.'cfg(target_os = "macos")'.dependencies]
tar = "0.4"

[target.'cfg(target_os = "windows")'.dependencies]
cmake = "0.1"

[target.'cfg(target_os = "linux")'.dependencies]
cmake = "0.1"
convert_case = "0.4.0"
Loading

0 comments on commit 9907040

Please sign in to comment.