Skip to content

Commit 6aaba83

Browse files
authored
refactor(plugin): add PluginApi and PluginHandle, expose on setup hook (#6291)
1 parent ec007ef commit 6aaba83

File tree

9 files changed

+396
-377
lines changed

9 files changed

+396
-377
lines changed

.changes/plugin-setup-refactor.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": major
3+
---
4+
5+
Changed the plugin setup hook to take a second argument of type `PluginApi`.

core/tauri/src/app.rs

Lines changed: 1 addition & 286 deletions
Original file line numberDiff line numberDiff line change
@@ -383,90 +383,6 @@ impl<R: Runtime> AppHandle<R> {
383383
pub(crate) fn create_proxy(&self) -> R::EventLoopProxy {
384384
self.runtime_handle.create_proxy()
385385
}
386-
387-
/// Initializes an iOS plugin.
388-
#[cfg(target_os = "ios")]
389-
pub fn initialize_ios_plugin(
390-
&self,
391-
init_fn: unsafe extern "C" fn(cocoa::base::id),
392-
) -> crate::Result<()> {
393-
if let Some(window) = self.windows().values().next() {
394-
window.with_webview(move |w| {
395-
unsafe { init_fn(w.inner()) };
396-
})?;
397-
} else {
398-
unsafe { init_fn(cocoa::base::nil) };
399-
}
400-
Ok(())
401-
}
402-
403-
/// Initializes an Android plugin.
404-
#[cfg(target_os = "android")]
405-
pub fn initialize_android_plugin(
406-
&self,
407-
plugin_name: &'static str,
408-
plugin_identifier: &str,
409-
class_name: &str,
410-
) -> crate::Result<()> {
411-
use jni::{errors::Error as JniError, objects::JObject, JNIEnv};
412-
413-
fn initialize_plugin<'a, R: Runtime>(
414-
env: JNIEnv<'a>,
415-
activity: JObject<'a>,
416-
webview: JObject<'a>,
417-
runtime_handle: &R::Handle,
418-
plugin_name: &'static str,
419-
plugin_class: String,
420-
) -> Result<(), JniError> {
421-
let plugin_manager = env
422-
.call_method(
423-
activity,
424-
"getPluginManager",
425-
format!("()Lapp/tauri/plugin/PluginManager;"),
426-
&[],
427-
)?
428-
.l()?;
429-
430-
// instantiate plugin
431-
let plugin_class = runtime_handle.find_class(env, activity, plugin_class)?;
432-
let plugin = env.new_object(
433-
plugin_class,
434-
"(Landroid/app/Activity;)V",
435-
&[activity.into()],
436-
)?;
437-
438-
// load plugin
439-
env.call_method(
440-
plugin_manager,
441-
"load",
442-
format!("(Landroid/webkit/WebView;Ljava/lang/String;Lapp/tauri/plugin/Plugin;)V"),
443-
&[
444-
webview.into(),
445-
env.new_string(plugin_name)?.into(),
446-
plugin.into(),
447-
],
448-
)?;
449-
450-
Ok(())
451-
}
452-
453-
let plugin_class = format!("{}/{}", plugin_identifier.replace(".", "/"), class_name);
454-
let runtime_handle = self.runtime_handle.clone();
455-
self
456-
.runtime_handle
457-
.run_on_android_context(move |env, activity, webview| {
458-
let _ = initialize_plugin::<R>(
459-
env,
460-
activity,
461-
webview,
462-
&runtime_handle,
463-
plugin_name,
464-
plugin_class,
465-
);
466-
});
467-
468-
Ok(())
469-
}
470386
}
471387

472388
/// APIs specific to the wry runtime.
@@ -876,156 +792,6 @@ macro_rules! shared_app_impl {
876792
}
877793
Ok(())
878794
}
879-
880-
/// Executes the given plugin mobile method.
881-
#[cfg(mobile)]
882-
pub fn run_mobile_plugin<T: serde::de::DeserializeOwned, E: serde::de::DeserializeOwned>(
883-
&self,
884-
plugin: impl AsRef<str>,
885-
method: impl AsRef<str>,
886-
payload: impl serde::Serialize
887-
) -> crate::Result<Result<T, E>> {
888-
#[cfg(target_os = "ios")]
889-
{
890-
Ok(self.run_ios_plugin(plugin, method, payload))
891-
}
892-
#[cfg(target_os = "android")]
893-
{
894-
self.run_android_plugin(plugin, method, payload).map_err(Into::into)
895-
}
896-
}
897-
898-
/// Executes the given iOS plugin method.
899-
#[cfg(target_os = "ios")]
900-
fn run_ios_plugin<T: serde::de::DeserializeOwned, E: serde::de::DeserializeOwned>(
901-
&self,
902-
plugin: impl AsRef<str>,
903-
method: impl AsRef<str>,
904-
payload: impl serde::Serialize
905-
) -> Result<T, E> {
906-
use std::{os::raw::{c_int, c_char}, ffi::CStr, sync::mpsc::channel};
907-
908-
let id: i32 = rand::random();
909-
let (tx, rx) = channel();
910-
PENDING_PLUGIN_CALLS
911-
.get_or_init(Default::default)
912-
.lock()
913-
.unwrap().insert(id, Box::new(move |arg| {
914-
tx.send(arg).unwrap();
915-
}));
916-
917-
unsafe {
918-
extern "C" fn plugin_method_response_handler(id: c_int, success: c_int, payload: *const c_char) {
919-
let payload = unsafe {
920-
assert!(!payload.is_null());
921-
CStr::from_ptr(payload)
922-
};
923-
924-
if let Some(handler) = PENDING_PLUGIN_CALLS
925-
.get_or_init(Default::default)
926-
.lock()
927-
.unwrap()
928-
.remove(&id)
929-
{
930-
let payload = serde_json::from_str(payload.to_str().unwrap()).unwrap();
931-
handler(if success == 1 { Ok(payload) } else { Err(payload) });
932-
}
933-
}
934-
935-
crate::ios::run_plugin_method(
936-
id,
937-
&plugin.as_ref().into(),
938-
&method.as_ref().into(),
939-
crate::ios::json_to_dictionary(serde_json::to_value(payload).unwrap()),
940-
plugin_method_response_handler,
941-
);
942-
}
943-
rx.recv().unwrap()
944-
.map(|r| serde_json::from_value(r).unwrap())
945-
.map_err(|e| serde_json::from_value(e).unwrap())
946-
}
947-
948-
/// Executes the given Android plugin method.
949-
#[cfg(target_os = "android")]
950-
fn run_android_plugin<T: serde::de::DeserializeOwned, E: serde::de::DeserializeOwned>(
951-
&self,
952-
plugin: impl AsRef<str>,
953-
method: impl AsRef<str>,
954-
payload: impl serde::Serialize
955-
) -> Result<Result<T, E>, jni::errors::Error> {
956-
use jni::{
957-
errors::Error as JniError,
958-
objects::JObject,
959-
JNIEnv,
960-
};
961-
962-
fn run<R: Runtime>(
963-
id: i32,
964-
plugin: String,
965-
method: String,
966-
payload: serde_json::Value,
967-
runtime_handle: &R::Handle,
968-
env: JNIEnv<'_>,
969-
activity: JObject<'_>,
970-
) -> Result<(), JniError> {
971-
let data = crate::jni_helpers::to_jsobject::<R>(env, activity, runtime_handle, payload)?;
972-
let plugin_manager = env
973-
.call_method(
974-
activity,
975-
"getPluginManager",
976-
"()Lapp/tauri/plugin/PluginManager;",
977-
&[],
978-
)?
979-
.l()?;
980-
981-
env.call_method(
982-
plugin_manager,
983-
"runPluginMethod",
984-
"(ILjava/lang/String;Ljava/lang/String;Lapp/tauri/plugin/JSObject;)V",
985-
&[
986-
id.into(),
987-
env.new_string(plugin)?.into(),
988-
env.new_string(&method)?.into(),
989-
data.into(),
990-
],
991-
)?;
992-
993-
Ok(())
994-
}
995-
996-
let handle = match self.runtime() {
997-
RuntimeOrDispatch::Runtime(r) => r.handle(),
998-
RuntimeOrDispatch::RuntimeHandle(h) => h,
999-
_ => unreachable!(),
1000-
};
1001-
1002-
let id: i32 = rand::random();
1003-
let plugin = plugin.as_ref().to_string();
1004-
let method = method.as_ref().to_string();
1005-
let payload = serde_json::to_value(payload).unwrap();
1006-
let handle_ = handle.clone();
1007-
1008-
let (tx, rx) = std::sync::mpsc::channel();
1009-
let tx_ = tx.clone();
1010-
PENDING_PLUGIN_CALLS
1011-
.get_or_init(Default::default)
1012-
.lock()
1013-
.unwrap().insert(id, Box::new(move |arg| {
1014-
tx.send(Ok(arg)).unwrap();
1015-
}));
1016-
1017-
handle.run_on_android_context(move |env, activity, _webview| {
1018-
if let Err(e) = run::<R>(id, plugin, method, payload, &handle_, env, activity) {
1019-
tx_.send(Err(e)).unwrap();
1020-
}
1021-
});
1022-
1023-
rx.recv().unwrap().map(|response| {
1024-
response
1025-
.map(|r| serde_json::from_value(r).unwrap())
1026-
.map_err(|e| serde_json::from_value(e).unwrap())
1027-
})
1028-
}
1029795
}
1030796
};
1031797
}
@@ -1443,7 +1209,7 @@ impl<R: Runtime> Builder<R> {
14431209
/// }
14441210
/// pub fn init<R: Runtime>() -> TauriPlugin<R> {
14451211
/// PluginBuilder::new("window")
1446-
/// .setup(|app| {
1212+
/// .setup(|app, api| {
14471213
/// // initialize the plugin here
14481214
/// Ok(())
14491215
/// })
@@ -2094,57 +1860,6 @@ impl Default for Builder<crate::Wry> {
20941860
}
20951861
}
20961862

2097-
#[cfg(mobile)]
2098-
type PendingPluginCallHandler =
2099-
Box<dyn FnOnce(std::result::Result<serde_json::Value, serde_json::Value>) + Send + 'static>;
2100-
2101-
#[cfg(mobile)]
2102-
static PENDING_PLUGIN_CALLS: once_cell::sync::OnceCell<
2103-
std::sync::Mutex<HashMap<i32, PendingPluginCallHandler>>,
2104-
> = once_cell::sync::OnceCell::new();
2105-
2106-
#[cfg(target_os = "android")]
2107-
#[doc(hidden)]
2108-
pub fn handle_android_plugin_response(
2109-
env: jni::JNIEnv<'_>,
2110-
id: i32,
2111-
success: jni::objects::JString<'_>,
2112-
error: jni::objects::JString<'_>,
2113-
) {
2114-
let (payload, is_ok): (serde_json::Value, bool) = match (
2115-
env
2116-
.is_same_object(success, jni::objects::JObject::default())
2117-
.unwrap_or_default(),
2118-
env
2119-
.is_same_object(error, jni::objects::JObject::default())
2120-
.unwrap_or_default(),
2121-
) {
2122-
// both null
2123-
(true, true) => (serde_json::Value::Null, true),
2124-
// error null
2125-
(false, true) => (
2126-
serde_json::from_str(env.get_string(success).unwrap().to_str().unwrap()).unwrap(),
2127-
true,
2128-
),
2129-
// success null
2130-
(true, false) => (
2131-
serde_json::from_str(env.get_string(error).unwrap().to_str().unwrap()).unwrap(),
2132-
false,
2133-
),
2134-
// both are set - impossible in the Kotlin code
2135-
(false, false) => unreachable!(),
2136-
};
2137-
2138-
if let Some(handler) = PENDING_PLUGIN_CALLS
2139-
.get_or_init(Default::default)
2140-
.lock()
2141-
.unwrap()
2142-
.remove(&id)
2143-
{
2144-
handler(if is_ok { Ok(payload) } else { Err(payload) });
2145-
}
2146-
}
2147-
21481863
#[cfg(test)]
21491864
mod tests {
21501865
#[test]

core/tauri/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ macro_rules! android_binding {
240240

241241
#[cfg(all(feature = "wry", target_os = "android"))]
242242
#[doc(hidden)]
243-
pub use app::handle_android_plugin_response;
243+
pub use plugin::handle_android_plugin_response;
244244
#[cfg(all(feature = "wry", target_os = "android"))]
245245
#[doc(hidden)]
246246
pub use tauri_runtime_wry::wry;

0 commit comments

Comments
 (0)