astonbitecode / j4rs

Java for Rust
Apache License 2.0
643 stars 36 forks source link

Use Context - Android #121

Closed ClauberBM closed 1 week ago

ClauberBM commented 5 months ago

Example Java: class CallClass() {

fun abc(context: Context) {
    val namePackage = context.packageName
  }

}

Rust:

fn test() { let ctx = ndk_context::android_context(); let jvm: Jvm = Jvm::attach_thread().unwrap();

             let callClass = jvm.create_instance(
                "com.test.test2.CallClass",
               InvocationArg::empty(),
            ).unwrap();

   let teste =
        jvm.invoke(
        &callClass,
        "teste",
    &[ InvocationArg::try_from(&ctx)]
    ).unwrap();

} challenge in j4rs, how can I use ndk_context to pass it as a parameter using InvocationArg ?

astonbitecode commented 5 months ago

You could try creating the InvocationArg like:

let ctx = ndk_context::android_context();
let c = ctx.context();
let arg = InvocationArg::try_from(c);

Haven't tried myself, but it is mentioned here.

ClauberBM commented 5 months ago

InvocationArg::try_from(c); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait From<*mut c_void> is not implemented for InvocationArg, which is required by InvocationArg: TryFrom<*mut c_void>

the problem is that I can't get jObject from JNI and use it in InvocationArg::try_from

astonbitecode commented 5 months ago
let ctx = ndk_context::android_context();
let c = ctx.context();
let instance = Instance::from_jobject_with_global_ref(c)?;
let arg = InvocationArg::try_from(instance);
astonbitecode commented 5 months ago

I also implemented TryFrom jobject for Instance, so that you could also do:

let instance = Instance::try_from(c)?;

in current master.

ClauberBM commented 5 months ago
65 let instance = Instance::from_jobject_with_global_ref(c).unwrap(); -------------------------------------- ^ expected *mut _jobject, found *mut c_void
arguments to this function are incorrect

= note: expected raw pointer *mut j4rs::jni_sys::_jobject found raw pointer *mut std::ffi::c_void

Were you able to compile?

astonbitecode commented 5 months ago

I haven't tried, but I guess you could cast:

 let instance = Instance::from_jobject_with_global_ref(c as jobject).unwrap();
ClauberBM commented 5 months ago

java_vm_ext.cc:591] JNI DETECTED ERROR IN APPLICATION: JNI NewGlobalRef called with pending exception java.lang.ClassNotFoundException: Didn't find class "org.astonbitecode.j4rs.api.dtos.InvocationArg" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system_ext/lib64, /system/lib64, /system_ext/lib64]] java_vm_ext.cc:591] at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:259) java_vm_ext.cc:591] at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:379) java_vm_ext.cc:591] at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312) java_vm_ext.cc:591] java_vm_ext.cc:591] in call to NewGlobalRef

I tried but it doesn't work, if you can carry out a project and upload it to github I would really appreciate it

astonbitecode commented 4 months ago

You now get ClassNotFoundException, so, the compilation succeeded I guess.

The reason for this exception is that the j4rs-VERSION-jar-with-dependencies.jar should be in the classpath. Have you included it in the created apk?

astonbitecode commented 1 week ago

Implemented the ability to use j4rs along with android-activity. I will soon update the README with instructions how to do it. In a nutshell, you should be able to pass to j4rs the JavaVM and the NativeActivity jobject and overcome the classloading issues:

let jvm = JvmBuilder::new()
        .with_java_vm(java_vm.clone())
        .with_classloader_of_activity_(activity_obj.clone())
        .build()?;
astonbitecode commented 1 week ago

For more details, please see this example project.