Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ In general, we can implement native libraries in CheerpJ by following these step
2. Create a JavaScript module that implements the native methods.
3. Load the native library in the Java class with CheerpJ.

### Loading native nibraries and declaring native methods in Java
### Loading native libraries and declaring native methods in Java

To declare a native method in Java, use the `native` keyword in the method declaration. The method is defined in the Java class but is not implemented in Java. Instead, the implementation will be provided in the native library JavaScript module which is loaded with `System.loadLibrary`.

Expand All @@ -39,7 +39,7 @@ public class ClassName {
}
```

### Creating a JavaScript module
### Creating a JavaScript module and implementing the native methods

A JavaScript module is a file that contains code which can be exported and imported by other files for better organization and reuse. You create modules using the `export` keyword to expose classes, methods, or other resources, and you can use `export default` to make a primary, easy-to-import item from the module. For more information on JavaScript modules, check out the official [`documentation`].

Expand All @@ -49,7 +49,7 @@ export default {
};
```

JavaScript functions that implement native methods should follow a specific naming convention - `Java_<fully-qualified-class-name>_<method-name>`. For instance, if `com.foo.Bar` has a native method called `baz`, the function will be called `Java_com_foo_Bar_baz`
To implement a native method in JavaScript, create an `async` function that follows the naming convention `Java_<fully-qualified-class-name>_<method-name>`. For instance, if `com.foo.Bar` has a native method called `baz`, the function will be called `Java_com_foo_Bar_baz`.

The JavaScript function should accept the following parameters:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,36 @@ title: Implementing Native Methods
description: Java Native Interface (JNI) with CheerpJ
---

In this guide, we’ll explore how to use **native methods** in CheerpJ to implement Java native methods in JavaScript.

CheerpJ allows one to implement Java native methods (typically written in C/C++ or another AOT-compiled language) directly in JavaScript, similar to the Java Native Interface (JNI) in standard Java.

In Java, native methods are identified by the `native` keyword in their declaration. These methods are not implemented in Java but are instead defined in an external language, which in the case of CheerpJ, is JavaScript.

## Overview
## Steps to implement native methods in CheerpJ

In general, we can implement native methods in CheerpJ by following these steps:

1. Declare a native method in Java using the `native` keyword.
2. Implement the native method in JavaScript.
3. Pass the native function to CheerpJ.

## Declaring Native Methods in Java

To declare a native method in Java, use the `native` keyword in the method declaration. Here’s an example of a Java class with a native method:
### Declaring Native Methods in Java

```java title="Example.java"
public class Example {
public static void main(String[] args) {
nativeAlert("Hello, world!");
}
To declare a native method in Java, use the `native` keyword in the method declaration. The method is defined in the Java class but is not implemented in Java. Instead, the implementation will be provided in JavaScript.

public static native void nativeAlert(String message);
```java
public class ClassName {
// Native method declaration
private native void methodName(param1, param2, ...);
}
```

The method is defined in the Java class but is not implemented in Java. Instead, the implementation will be provided in JavaScript.
### Implementing Native Methods in JavaScript

## Implementing Native Methods in JavaScript
To implement a native method in JavaScript, create an `async` function that follows the naming convention `Java_<fully-qualified-class-name>_<method-name>`. For instance, if `com.foo.Bar` has a native method called `baz`, its object key is `Java_com_foo_Bar_baz`.

To implement a native method in JavaScript, create an `async` function that follows the naming convention `Java_<fully-qualified-class-name>_<method-name>`. For instance, if `com.foo.Bar` has a native method called `baz`, its object key is `Java_com_foo_Bar_baz`. The function takes:
The JavaScript function should accept the following parameters:

- A [`CJ3Library`] object `lib` as the first parameter, which provides access to other classes and methods within the library. The `lib` parameter can be used to call back into the Java class that calls the native method.
- `self` as the second parameter, the instance of the Java class calling the native method. This parameter can be omitted for static native methods.
Expand All @@ -50,68 +49,32 @@ async function Java_<fully-qualified-class-name>_<method-name>(lib, self, param1
> [!info] Handling Static Native Methods
> If the native method is static, the `self` parameter can be omitted.

## Calling back into Java from JavaScript

It is possible to call back into Java using the `lib` parameter received in the JavaScript implementation of the native Java method.

Let’s take this simple Java class as an example:

```java title="Example.java"
public class Example {
public static native void nativeFunction();

public static void printJava() {
System.out.println("Hello from Java!");
}
### Initializing CheerpJ with the `natives` option

public static void main(String[] args) {
nativeFunction();
}
}
```
To use the native method in CheerpJ, pass the function to the [`cheerpjInit`] function as a property of the [`natives`] option. There are two ways in which you can do this.

The `Example` class includes a `native` function that will be implemented in JavaScript, and a public print function that outputs `Hello from Java!`.
In the JavaScript implementation of `nativeFunction`, we can use the `lib` parameter to call back into the `Example` Java class and invoke the `printJava()` function from JavaScript.

```js
async function Java_Example_nativeFunction(lib) {
const Example = await lib.Example;
await Example.printJava();
}
```

This functionality is useful when you need to call back into the Java class in response to a native function call. If you need to call back into Java outside the context of a native function, you can use a long-running Java thread. You can learn more about how to achieve this in our [`Java and JavaScript Interoperability`] tutorial.

## Passing Native Functions to CheerpJ

To use the native method in CheerpJ, pass the function to the [`cheerpjInit`] function as a property of the [`natives`] option. You can pass:

1. **The function definition directly**:
1. **In the function definition directly**

```js
await cheerpjInit({
natives: {
async Java_Example_nativeAlert(lib, str) {
window.alert(str);
async Java_Example_nativeMethodName(lib, str) {
// Implementation
},
},
});
```

2. **Or just the function name if it was defined earlier**:
2. **Or just the function name if it was defined earlier**

```js
async function Java_Example_nativeAlert(lib, str) {
window.alert(str);
async function Java_Example_nativeMethodName(lib, str) {
// Implementation
}

await cheerpjInit({ natives: { Java_Example_nativeAlert } });
await cheerpjInit({ natives: { Java_Example_nativeMethodName } });
```

## Converting Parameters and Return Values

Parameters and return values of JNI calls are automatically converted between JavaScript and Java types based on [`conversion rules`].

## Example Walkthrough

Here’s a full example that demonstrates the native method setup in Java and its JavaScript implementation.
Expand Down Expand Up @@ -148,20 +111,59 @@ Here, we provide an implementation for the `nativeAlert` method in the `Example`
<script src="https://cjrtnc.leaningtech.com/4.2/loader.js"></script>
</head>
<body>
<script>
async function Java_Example_nativeAlert(lib, str) {
window.alert(str);
<script type="module">
async function Java_Example_Alert(lib, str) {
window.alert(str);
}

await cheerpjInit({ natives: { Java_Example_nativeAlert } });
await cheerpjRunMain("Example", "/app/");
// Init CheerpJ and register natives, then run your main
await cheerpjInit({
natives: { Java_Example_nativeAlert },
});
await cheerpjRunMain("Example", "/app");
</script>
</body>
</html>
```

In this setup, [`cheerpjInit`] loads `Java_Example_nativeAlert` as the native method implementation. When `Example.nativeAlert` is called in Java, it triggers the JavaScript `Java_Example_nativeAlert` function, displaying an alert dialog with the message.

## Calling back into Java from JavaScript

You can call back into Java from a JavaScript native method implementation using the `lib` parameter. The `lib` object exposes your Java classes so you can invoke their static methods.

```java
public class ClassName {
// Implemented in JavaScript
public static native void nativeMethodName();

public static void javaMethodName() {
// Your Java logic here
}

public static void main(String[] args) {
nativeMethodName(); // Triggers the JS implementation
}
}
```

The `ClassName` class defines a `native method` called `nativeMethodName`, which will be implemented in JavaScript. It also includes a public method, `javaMethodName`, that performs some Java logic.

In the JavaScript implementation of `nativeMethodName`, you can use the `lib` parameter to access the `ClassName` Java class and call its methods from JavaScript. This allows JavaScript code to call back into Java and execute Java logic directly from the browser.

```js
// Example placeholders — replace ClassName/javaMethodName with your own
async function Java_ClassName_nativeMethodName(lib) {
const ClassName = await lib.ClassName; // Access your Java class
await ClassName.javaMethodName(); // Call a Java static method
}
```

This functionality is useful when you need to call back into the Java class in response to a native function call. If you need to call back into Java outside the context of a native function, you can use a long-running Java thread. You can learn more about how to achieve this in our [`Java and JavaScript Interoperability`] tutorial.

## Converting Parameters and Return Values

Parameters and return values of JNI calls are automatically converted between JavaScript and Java types based on [`conversion rules`].

[`natives`]: /docs/reference/cheerpjInit#natives
[`CJ3Library`]: /docs/reference/CJ3Library
[`conversion rules`]: /docs/reference/CJ3Library#conversion-rules
Expand Down