This document describes how to use JNI Zero in Chromium.
Templates are in //third_party/jni_zero/jni_zero.gni.
Given a set of Java files, generates a header file to call into Java for all @CalledByNative functions. If @NativeMethods is present, also generates a .srcjar containing <ClassName>Jni.java, which should be depended on via the generated GN target <generate_jni's target name>_java.
Example:
generate_jni("abcd_jni") { sources = [ "org/chromium/foo/Bar.java" ] } android_library("abcd_java") { ... # For the generated `${Bar}Jni` classes. deps = [ ":abcd_jni_java" ] } source_set("abcd") { ... # Allows the cc files to include the generated `${OriginalClassName}_jni.h` # headers. deps = [ ":abcd_jni" ] }
Given a .jar file (defaults to android.jar), generates a header file similar to generate_jni, if every method and public field were annotated by @CalledByNative.
Generates a whole-program Java and native link - required for all Java that calls into native via @NativeMethods.
A wrapper around a shared_library that bundles a generate_jni_registration.
Same as shared_library but for a component.
Generates a RegisterNatives() for a list of .jar files.
import("//third_party/jni_zero/jni_zero.gni") generate_jar_jni_registration("my_library_jni_registration") { # List of classes.jar files extracted from the AARs. jar_files = [ "libs/my_library_classes.jar", ] # Optional: C++ namespace namespace = "my_namespace" # Optional: Name of the function (defaults to "RegisterNatives"). register_natives_name = "MyLibrary_RegisterNatives" # Optional: Path to output a linker version script to prevent exporting these # JNI symbols. linker_script_path = "$target_gen_dir/my_library_linker_script.txt" # Optional: List of class name globs to exclude from registration. # If specified, classes matching these globs will be ignored. # Useful if the C++ library does not implement JNI for some classes in the JAR. class_blocklist = [ "com.example.UnimplementedClass", "com.example.exclude.*", ] # Ensure the AARs are unpacked before this target runs. deps = [ ":my_aar_prebuilt", ] }
This will generate a header at $target_gen_dir/my_library_jni_registration.h (using the target name as the header name) containing:
JNI Zero supports automatic type conversions via the @JniType annotation. See the main README.md for details and a list of conversions provided by JNI Zero.
Use @JniType("std::string") for UTF-8 or @JniType("std::u16string") for UTF-16.
Java:
void onNameChanged(@JniType("std::string") String name); @JniType("std::string") String getName();
C++:
#include "base/android/jni_string.h" #include "path/to/generated_jni/MyClass_jni.h" void JNI_MyClass_OnNameChanged(JNIEnv* env, const std::string& name) { ... } std::string JNI_MyClass_GetName(JNIEnv* env) { return "name"; }
Null Handling: null Java strings are converted to empty std::string or std::u16string.
Runnable / Callback / Callback2 to C++ as a base::OnceCallback, use @JniType.Java:
void doSomething(@JniType("base::OnceClosure") Runnable callback); void fetchSuccess(@JniType("base::OnceCallback<void(std::string)>") Callback<String> callback); void fetchSuccess2(@JniType("base::OnceCallback<void(const jni_zero::JavaRef<jobject>&, long)>") Callback2<SomeClass, Long> callback);
C++:
#include "base/android/callback_android.h" #include "path/to/generated_jni/MyClass_jni.h" void JNI_MyClass_DoSomething(JNIEnv* env, base::OnceClosure callback) { std::move(callback).Run(); } void JNI_MyClass_FetchSuccess2(JNIEnv* env, base::OnceCallback<void(const jni_zero::JavaRef<jobject>&, long)> callback) { std::move(callback).Run(nullptr, 123L); }
@JniType on the Java side.JniOnceRunnable / JniRepeatingRunnableJniOnceCallback<T> / JniRepeatingCallback<T>,JniOnceCallback2<T1, T2> / JniRepeatingCallback2<T1. T2>,Repeating* variants, you must call destroy() when done with them.Once* variants, destroy() is called when it's run, but you must call it manually if it is never run.Once* variants, can be typed as Runnable / Callback / Callback2 if you don't need destroy().Java:
@CalledByNative void onResult(@JniType("base::OnceCallback<void(std::string)>&&") JniOnceCallback<String> callback) { callback.onResult("success"); } @CalledByNative void onResult2(@JniType("base::OnceCallback<void(const jni_zero::JavaRef<jobject>&, long)>&&") JniOnceCallback2<SomeClass, Long> callback) { callback.onResult(new SomeClass(), 123L); } @CalledByNative @JniType("base::OnceClosure") Runnable getClosure();
C++:
#include "base/android/callback_android.h" #include "path/to/generated_jni/MyClass_jni.h" void Finish(JNIEnv* env, base::OnceCallback<void(std::string)> callback) { Java_MyClass_onResult(env, std::move(callback)); } void Finish2(JNIEnv* env, base::OnceCallback<void(const jni_zero::JavaRef<jobject>&, long)> callback) { auto callback = base::BindOnce([](){ ... }); Java_MyClass_onResult2(env, std::move(callback)); } base::OnceClosure JNI_MyClass_GetClosure(JNIEnv* env) { return base::BindOnce([](){ ... }); }
Use std::optional<T> to handle nullable parameters.
Java:
void maybeDoSomething(@JniType("std::optional<std::string>") String maybeName);
C++:
#include "third_party/jni_zero/default_conversions.h" #include "base/android/jni_string.h" #include "path/to/generated_jni/MyClass_jni.h" void JNI_MyClass_MaybeDoSomething(JNIEnv* env, std::optional<std::string> maybeName) { if (maybeName) { ... } }
Header: #include "third_party/jni_zero/default_conversions.h"
Behavior: null is converted to std::nullopt.
JNI Zero can convert between Java arrays/Lists and C++ containers or base::span.
You can pass a base::span from Native to Java where Java expects an array or a List.
Java:
@CalledByNative void showItems(@JniType("base::span<const GURL>") GURL[] items);
C++:
#include "url/android/gurl_android.h" #include "path/to/generated_jni/MyClass_jni.h" void SendItems(JNIEnv* env, base::span<const GURL> items) { Java_MyClass_showItems(env, items); }
Header: #include "third_party/jni_zero/default_conversions.h" (and the header for the element type, e.g., url/android/gurl_android.h)
Searching for FromJniType or ToJniType specializations will reveal more. Common ones include:
| C++ Type | Java Type | Header |
|---|---|---|
std::string | String | base/android/jni_string.h |
std::u16string | String | base/android/jni_string.h |
base::OnceClosure | Runnable | base/android/callback_android.h |
base::OnceCallback<void(T)> | Callback<T> | base/android/callback_android.h |
base::OnceCallback<void(T1, T2)> | Callback2<T1, T2> | base/android/callback_android.h |
GURL | GURL | url/android/gurl_android.h |
base::Token | Token | base/android/token_android.h |
base::UnguessableToken | UnguessableToken | base/android/unguessable_token_android.h |