@@ -860,6 +860,88 @@ macro_rules! shared_app_impl {
860860 }
861861 Ok ( ( ) )
862862 }
863+
864+ /// Executes the given Android plugin method.
865+ #[ cfg( target_os = "android" ) ]
866+ pub fn run_android_plugin<T : serde:: de:: DeserializeOwned , E : serde:: de:: DeserializeOwned >(
867+ & self ,
868+ plugin: impl Into <String >,
869+ method: impl Into <String >,
870+ payload: impl serde:: Serialize
871+ ) -> Result <Result <T , E >, jni:: errors:: Error > {
872+ use jni:: {
873+ errors:: Error as JniError ,
874+ objects:: JObject ,
875+ JNIEnv ,
876+ } ;
877+
878+ fn run<R : Runtime >(
879+ id: i32 ,
880+ plugin: String ,
881+ method: String ,
882+ payload: serde_json:: Value ,
883+ runtime_handle: & R :: Handle ,
884+ env: JNIEnv <' _>,
885+ activity: JObject <' _>,
886+ ) -> Result <( ) , JniError > {
887+ let data = crate :: jni_helpers:: to_jsobject:: <R >( env, activity, runtime_handle, payload) ?;
888+ let plugin_manager = env
889+ . call_method(
890+ activity,
891+ "getPluginManager" ,
892+ "()Lapp/tauri/plugin/PluginManager;" ,
893+ & [ ] ,
894+ ) ?
895+ . l( ) ?;
896+
897+ env. call_method(
898+ plugin_manager,
899+ "runPluginMethod" ,
900+ "(ILjava/lang/String;Ljava/lang/String;Lapp/tauri/plugin/JSObject;)V" ,
901+ & [
902+ id. into( ) ,
903+ env. new_string( plugin) ?. into( ) ,
904+ env. new_string( & method) ?. into( ) ,
905+ data. into( ) ,
906+ ] ,
907+ ) ?;
908+
909+ Ok ( ( ) )
910+ }
911+
912+ let handle = match self . runtime( ) {
913+ RuntimeOrDispatch :: Runtime ( r) => r. handle( ) ,
914+ RuntimeOrDispatch :: RuntimeHandle ( h) => h,
915+ _ => unreachable!( ) ,
916+ } ;
917+
918+ let id: i32 = rand:: random( ) ;
919+ let plugin = plugin. into( ) ;
920+ let method = method. into( ) ;
921+ let payload = serde_json:: to_value( payload) . unwrap( ) ;
922+ let handle_ = handle. clone( ) ;
923+
924+ let ( tx, rx) = std:: sync:: mpsc:: channel( ) ;
925+ let tx_ = tx. clone( ) ;
926+ PENDING_PLUGIN_CALLS
927+ . get_or_init( Default :: default )
928+ . lock( )
929+ . unwrap( ) . insert( id, Box :: new( move |arg| {
930+ tx. send( Ok ( arg) ) . unwrap( ) ;
931+ } ) ) ;
932+
933+ handle. run_on_android_context( move |env, activity, _webview| {
934+ if let Err ( e) = run:: <R >( id, plugin, method, payload, & handle_, env, activity) {
935+ tx_. send( Err ( e) ) . unwrap( ) ;
936+ }
937+ } ) ;
938+
939+ rx. recv( ) . unwrap( ) . map( |response| {
940+ response
941+ . map( |r| serde_json:: from_value( r) . unwrap( ) )
942+ . map_err( |e| serde_json:: from_value( e) . unwrap( ) )
943+ } )
944+ }
863945 }
864946 } ;
865947}
@@ -1868,6 +1950,57 @@ impl Default for Builder<crate::Wry> {
18681950 }
18691951}
18701952
1953+ #[ cfg( target_os = "android" ) ]
1954+ type PendingPluginCallHandler =
1955+ Box < dyn FnOnce ( std:: result:: Result < serde_json:: Value , serde_json:: Value > ) + Send + ' static > ;
1956+
1957+ #[ cfg( target_os = "android" ) ]
1958+ static PENDING_PLUGIN_CALLS : once_cell:: sync:: OnceCell <
1959+ std:: sync:: Mutex < HashMap < i32 , PendingPluginCallHandler > > ,
1960+ > = once_cell:: sync:: OnceCell :: new ( ) ;
1961+
1962+ #[ cfg( target_os = "android" ) ]
1963+ #[ doc( hidden) ]
1964+ pub fn handle_android_plugin_response (
1965+ env : jni:: JNIEnv < ' _ > ,
1966+ id : i32 ,
1967+ success : jni:: objects:: JString < ' _ > ,
1968+ error : jni:: objects:: JString < ' _ > ,
1969+ ) {
1970+ let ( payload, is_ok) : ( serde_json:: Value , bool ) = match (
1971+ env
1972+ . is_same_object ( success, jni:: objects:: JObject :: default ( ) )
1973+ . unwrap_or_default ( ) ,
1974+ env
1975+ . is_same_object ( error, jni:: objects:: JObject :: default ( ) )
1976+ . unwrap_or_default ( ) ,
1977+ ) {
1978+ // both null
1979+ ( true , true ) => ( serde_json:: Value :: Null , true ) ,
1980+ // error null
1981+ ( false , true ) => (
1982+ serde_json:: from_str ( env. get_string ( success) . unwrap ( ) . to_str ( ) . unwrap ( ) ) . unwrap ( ) ,
1983+ true ,
1984+ ) ,
1985+ // success null
1986+ ( true , false ) => (
1987+ serde_json:: from_str ( env. get_string ( error) . unwrap ( ) . to_str ( ) . unwrap ( ) ) . unwrap ( ) ,
1988+ false ,
1989+ ) ,
1990+ // both are set - impossible in the Kotlin code
1991+ ( false , false ) => unreachable ! ( ) ,
1992+ } ;
1993+
1994+ if let Some ( handler) = PENDING_PLUGIN_CALLS
1995+ . get_or_init ( Default :: default)
1996+ . lock ( )
1997+ . unwrap ( )
1998+ . remove ( & id)
1999+ {
2000+ handler ( if is_ok { Ok ( payload) } else { Err ( payload) } ) ;
2001+ }
2002+ }
2003+
18712004#[ cfg( test) ]
18722005mod tests {
18732006 #[ test]
0 commit comments