Documentation improvements to JNI API
Amends 4e60681c879a54cf5b34862a30e27c492ed36363. Fixes: QTBUG-89632 Change-Id: I7856e9b63eea5ba68a5472575016540ae656ec5f Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> Reviewed-by: Alex Blasche <alexander.blasche@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> (cherry picked from commit 817f8ac03cd4e85b7813b45f8cabf5b679f28702) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
bbdcc86c52
commit
77b035aa6e
@ -79,7 +79,7 @@ void functionScope()
|
||||
}
|
||||
//! [QJniObject scope]
|
||||
|
||||
//! [Registering native methods]
|
||||
//! [C++ native methods]
|
||||
static void fromJavaOne(JNIEnv *env, jobject thiz, jint x)
|
||||
{
|
||||
Q_UNUSED(env);
|
||||
@ -94,26 +94,19 @@ static void fromJavaTwo(JNIEnv *env, jobject thiz, jint x)
|
||||
qDebug() << x << ">= 100";
|
||||
}
|
||||
|
||||
void registerNativeMethods() {
|
||||
JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)},
|
||||
{"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}};
|
||||
|
||||
QJniObject javaClass("my/java/project/FooJavaClass");
|
||||
QJniEnvironment env;
|
||||
jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
|
||||
env->RegisterNatives(objectClass,
|
||||
methods,
|
||||
sizeof(methods) / sizeof(methods[0]));
|
||||
env->DeleteLocalRef(objectClass);
|
||||
}
|
||||
|
||||
void foo()
|
||||
{
|
||||
// register the native methods first, ideally it better be done with the app start
|
||||
JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)},
|
||||
{"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}};
|
||||
QJniEnvironment env;
|
||||
env.registerNativeMethods("my/java/project/FooJavaClass", methods, 2);
|
||||
|
||||
// Call the java method which will calls back to the C++ functions
|
||||
QJniObject::callStaticMethod<void>("my/java/project/FooJavaClass", "foo", "(I)V", 10); // Output: 10 < 100
|
||||
QJniObject::callStaticMethod<void>("my/java/project/FooJavaClass", "foo", "(I)V", 100); // Output: 100 >= 100
|
||||
}
|
||||
|
||||
//! [Registering native methods]
|
||||
//! [C++ native methods]
|
||||
|
||||
//! [Java native methods]
|
||||
class FooJavaClass
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the documentation of the Qt Toolkit.
|
||||
@ -65,3 +65,28 @@
|
||||
\externalpage https://marcmutz.wordpress.com/effective-qt/containers/
|
||||
\title Understand the Qt Containers
|
||||
*/
|
||||
|
||||
/*!
|
||||
\externalpage https://developer.android.com/training/articles/perf-jni#javavm-and-jnienv
|
||||
\title JNI tips: JavaVM and JNIEnv
|
||||
*/
|
||||
|
||||
/*!
|
||||
\externalpage https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html
|
||||
\title Java Native Interface Specification
|
||||
*/
|
||||
|
||||
/*!
|
||||
\externalpage https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html
|
||||
\title Oracle: JNI Functions
|
||||
*/
|
||||
|
||||
/*!
|
||||
\externalpage https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references
|
||||
\title JNI Design Overview: Global and Local References
|
||||
*/
|
||||
|
||||
/*!
|
||||
\externalpage https://developer.android.com/training/articles/perf-jni#local-and-global-references
|
||||
\title JNI tips: Local and global references
|
||||
*/
|
||||
|
@ -49,11 +49,19 @@ QT_BEGIN_NAMESPACE
|
||||
/*!
|
||||
\class QJniEnvironment
|
||||
\inmodule QtCore
|
||||
\brief The QJniEnvironment provides access to the JNI Environment.
|
||||
\since 6.1
|
||||
\brief The QJniEnvironment class provides access to the JNI Environment (JNIEnv).
|
||||
|
||||
\note This API has been tested and meant to be mainly used for Android and it hasn't been tested
|
||||
for other platforms.
|
||||
When using JNI, the \l {JNI tips: JavaVM and JNIEnv}{JNIEnv} class is a pointer to a function
|
||||
table and a member function for each JNI function that indirects through the table. \c JNIEnv
|
||||
provides most of the JNI functions. Every C++ native function receives a \c JNIEnv as the first
|
||||
argument. The JNI environment cannot be shared between threads.
|
||||
|
||||
Since \c JNIEnv doesn't do much error checking, such as exception checking and clearing,
|
||||
QJniEnvironment allows you to do that easily.
|
||||
|
||||
\note This API has been designed and tested for use with Android.
|
||||
It has not been tested for other platforms.
|
||||
*/
|
||||
|
||||
static const char qJniThreadName[] = "QtThread";
|
||||
@ -96,7 +104,7 @@ Q_GLOBAL_STATIC(QThreadStorage<QJniEnvironmentPrivateTLS *>, jniEnvTLS)
|
||||
/*!
|
||||
\fn QJniEnvironment::QJniEnvironment()
|
||||
|
||||
Constructs a new QJniEnvironment object and attaches the current thread to the Java VM.
|
||||
Constructs a new JNI Environment object and attaches the current thread to the Java VM.
|
||||
*/
|
||||
QJniEnvironment::QJniEnvironment()
|
||||
: d(new QJniEnvironmentPrivate{})
|
||||
@ -120,6 +128,7 @@ QJniEnvironment::QJniEnvironment()
|
||||
\fn QJniEnvironment::~QJniEnvironment()
|
||||
|
||||
Detaches the current thread from the Java VM and destroys the QJniEnvironment object.
|
||||
This will clear any pending exception by calling exceptionCheckAndClear().
|
||||
*/
|
||||
QJniEnvironment::~QJniEnvironment()
|
||||
{
|
||||
@ -152,13 +161,13 @@ QJniEnvironment::operator JNIEnv* () const
|
||||
Searches for \a className using all available class loaders. Qt on Android
|
||||
uses a custom class loader to load all the .jar files and it must be used
|
||||
to find any classes that are created by that class loader because these
|
||||
classes are not visible in the default class loader.
|
||||
classes are not visible when using the default class loader.
|
||||
|
||||
Returns the class pointer or null if is not found.
|
||||
|
||||
A use case for this function is searching for a custom class then calling
|
||||
its memeber method. The following code snippet create an instance of the
|
||||
class \c CustomClass and then calls \c printFromJava() method:
|
||||
its member method. The following code snippet creates an instance of the
|
||||
class \c CustomClass and then calls the \c printFromJava() method:
|
||||
|
||||
\code
|
||||
QJniEnvironment env;
|
||||
@ -170,8 +179,6 @@ QJniEnvironment::operator JNIEnv* () const
|
||||
"(Ljava/lang/String;)V",
|
||||
javaMessage.object<jstring>());
|
||||
\endcode
|
||||
|
||||
\since Qt 6.1
|
||||
*/
|
||||
jclass QJniEnvironment::findClass(const char *className)
|
||||
{
|
||||
@ -181,9 +188,9 @@ jclass QJniEnvironment::findClass(const char *className)
|
||||
/*!
|
||||
\fn JavaVM *QJniEnvironment::javaVM()
|
||||
|
||||
Returns the Java VM interface.
|
||||
Returns the Java VM interface for the current process. Although it might
|
||||
be possible to have multiple Java VMs per process, Android allows only one.
|
||||
|
||||
\since Qt 6.1
|
||||
*/
|
||||
JavaVM *QJniEnvironment::javaVM()
|
||||
{
|
||||
@ -191,10 +198,11 @@ JavaVM *QJniEnvironment::javaVM()
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMethod methods[])
|
||||
\fn bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMethod methods[], int size)
|
||||
|
||||
Registers the Java methods \a methods that can call native C++ functions from class \a
|
||||
className. These methods must be registered before any attempt to call them.
|
||||
Registers the Java methods in the array \a methods of size \a size, each of
|
||||
which can call native C++ functions from class \a className. These methods
|
||||
must be registered before any attempt to call them.
|
||||
|
||||
Returns True if the registration is successful, otherwise False.
|
||||
|
||||
@ -209,10 +217,8 @@ JavaVM *QJniEnvironment::javaVM()
|
||||
JNINativeMethod methods[] {{"callNativeOne", "(I)V", reinterpret_cast<void *>(fromJavaOne)},
|
||||
{"callNativeTwo", "(I)V", reinterpret_cast<void *>(fromJavaTwo)}};
|
||||
QJniEnvironment env;
|
||||
env.registerNativeMethods("org/qtproject/android/TestJavaClass", methods);
|
||||
env.registerNativeMethods("org/qtproject/android/TestJavaClass", methods, 2);
|
||||
\endcode
|
||||
|
||||
\since Qt 6.1
|
||||
*/
|
||||
bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMethod methods[], int size)
|
||||
{
|
||||
@ -233,18 +239,23 @@ bool QJniEnvironment::registerNativeMethods(const char *className, JNINativeMeth
|
||||
}
|
||||
|
||||
/*!
|
||||
\enum QJniExceptionCleaner::OutputMode
|
||||
\enum QJniEnvironment::OutputMode
|
||||
|
||||
\value Silent the exceptions are cleaned silently
|
||||
\value Verbose describes the exceptions before cleaning them
|
||||
\value Silent The exceptions are cleaned silently
|
||||
\value Verbose Prints the exceptions and their stack backtrace as an error
|
||||
to \c stderr stream.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QJniEnvironment::exceptionCheckAndClear(OutputMode outputMode = OutputMode::Silent)
|
||||
\fn QJniEnvironment::exceptionCheckAndClear(OutputMode outputMode = OutputMode::Verbose)
|
||||
|
||||
Cleans any pending exceptions either silently or with descriptions, depending on the \a outputMode.
|
||||
Cleans any pending exceptions either silently or reporting stack backtrace,
|
||||
depending on the \a outputMode.
|
||||
|
||||
\since 6.1
|
||||
In contrast to \l QJniObject, which handles exceptions internally, if you
|
||||
make JNI calls directly via \c JNIEnv, you need to clear any potential
|
||||
exceptions after the call using this function. For more information about
|
||||
\c JNIEnv calls that can throw an exception, see \l {Oracle: JNI Functions}{JNI Functions}.
|
||||
*/
|
||||
bool QJniEnvironment::exceptionCheckAndClear(QJniEnvironment::OutputMode outputMode)
|
||||
{
|
||||
@ -260,11 +271,16 @@ bool QJniEnvironment::exceptionCheckAndClear(QJniEnvironment::OutputMode outputM
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn QJniEnvironment::exceptionCheckAndClear(JNIEnv *env, OutputMode outputMode = OutputMode::Silent)
|
||||
\fn QJniEnvironment::exceptionCheckAndClear(JNIEnv *env, OutputMode outputMode = OutputMode::Verbose)
|
||||
|
||||
Cleans any pending exceptions for \a env, either silently or with descriptions, depending on the \a outputMode.
|
||||
Cleans any pending exceptions for \a env, either silently or reporting
|
||||
stack backtrace, depending on the \a outputMode. This is useful when you
|
||||
already have a \c JNIEnv pointer such as in a native function implementation.
|
||||
|
||||
\since 6.1
|
||||
In contrast to \l QJniObject, which handles exceptions internally, if you
|
||||
make JNI calls directly via \c JNIEnv, you need to clear any potential
|
||||
exceptions after the call using this function. For more information about
|
||||
\c JNIEnv calls that can throw an exception, see \l {Oracle: JNI Functions}{JNI Functions}.
|
||||
*/
|
||||
bool QJniEnvironment::exceptionCheckAndClear(JNIEnv *env, QJniEnvironment::OutputMode outputMode)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -58,9 +58,9 @@ class Q_CORE_EXPORT QJniObject
|
||||
public:
|
||||
QJniObject();
|
||||
explicit QJniObject(const char *className);
|
||||
explicit QJniObject(const char *className, const char *sig, ...);
|
||||
explicit QJniObject(const char *className, const char *signature, ...);
|
||||
explicit QJniObject(jclass clazz);
|
||||
explicit QJniObject(jclass clazz, const char *sig, ...);
|
||||
explicit QJniObject(jclass clazz, const char *signature, ...);
|
||||
QJniObject(jobject globalRef);
|
||||
~QJniObject();
|
||||
|
||||
@ -69,19 +69,20 @@ public:
|
||||
jobject object() const;
|
||||
|
||||
template <typename T>
|
||||
T callMethod(const char *methodName, const char *sig, ...) const;
|
||||
T callMethod(const char *methodName, const char *signature, ...) const;
|
||||
template <typename T>
|
||||
T callMethod(const char *methodName) const;
|
||||
template <typename T>
|
||||
QJniObject callObjectMethod(const char *methodName) const;
|
||||
QJniObject callObjectMethod(const char *methodName, const char *sig, ...) const;
|
||||
QJniObject callObjectMethod(const char *methodName, const char *signature, ...) const;
|
||||
|
||||
template <typename T>
|
||||
static T callStaticMethod(const char *className, const char *methodName, const char *sig, ...);
|
||||
static T callStaticMethod(const char *className, const char *methodName,
|
||||
const char *signature, ...);
|
||||
template <typename T>
|
||||
static T callStaticMethod(const char *className, const char *methodName);
|
||||
template <typename T>
|
||||
static T callStaticMethod(jclass clazz, const char *methodName, const char *sig, ...);
|
||||
static T callStaticMethod(jclass clazz, const char *methodName, const char *signature, ...);
|
||||
template <typename T>
|
||||
static T callStaticMethod(jclass clazz, const char *methodName);
|
||||
|
||||
@ -89,13 +90,13 @@ public:
|
||||
static QJniObject callStaticObjectMethod(const char *className, const char *methodName);
|
||||
static QJniObject callStaticObjectMethod(const char *className,
|
||||
const char *methodName,
|
||||
const char *sig, ...);
|
||||
const char *signature, ...);
|
||||
|
||||
template <typename T>
|
||||
static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName);
|
||||
static QJniObject callStaticObjectMethod(jclass clazz,
|
||||
const char *methodName,
|
||||
const char *sig, ...);
|
||||
const char *signature, ...);
|
||||
|
||||
template <typename T>
|
||||
T getField(const char *fieldName) const;
|
||||
@ -107,35 +108,38 @@ public:
|
||||
|
||||
template <typename T>
|
||||
QJniObject getObjectField(const char *fieldName) const;
|
||||
QJniObject getObjectField(const char *fieldName, const char *sig) const;
|
||||
QJniObject getObjectField(const char *fieldName, const char *signature) const;
|
||||
|
||||
template <typename T>
|
||||
static QJniObject getStaticObjectField(const char *className, const char *fieldName);
|
||||
static QJniObject getStaticObjectField(const char *className,
|
||||
const char *fieldName,
|
||||
const char *sig);
|
||||
const char *signature);
|
||||
template <typename T>
|
||||
static QJniObject getStaticObjectField(const char *className,
|
||||
const char *fieldName,
|
||||
const char *sig);
|
||||
const char *signature);
|
||||
|
||||
template <typename T>
|
||||
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName);
|
||||
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, const char *sig);
|
||||
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName,
|
||||
const char *signature);
|
||||
template <typename T>
|
||||
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName, const char *sig);
|
||||
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName,
|
||||
const char *signature);
|
||||
|
||||
template <typename T>
|
||||
void setField(const char *fieldName, T value);
|
||||
template <typename T>
|
||||
void setField(const char *fieldName, const char *sig, T value);
|
||||
void setField(const char *fieldName, const char *signature, T value);
|
||||
template <typename T>
|
||||
static void setStaticField(const char *className, const char *fieldName, T value);
|
||||
template <typename T>
|
||||
static void setStaticField(const char *className, const char *fieldName,
|
||||
const char *sig, T value);
|
||||
const char *signature, T value);
|
||||
template <typename T>
|
||||
static void setStaticField(jclass clazz, const char *fieldName, const char *sig, T value);
|
||||
static void setStaticField(jclass clazz, const char *fieldName,
|
||||
const char *signature, T value);
|
||||
|
||||
template <typename T>
|
||||
static void setStaticField(jclass clazz, const char *fieldName, T value);
|
||||
@ -154,31 +158,33 @@ public:
|
||||
private:
|
||||
struct QVaListPrivate { operator va_list &() const { return m_args; } va_list &m_args; };
|
||||
|
||||
QJniObject(const char *className, const char *sig, const QVaListPrivate &args);
|
||||
QJniObject(jclass clazz, const char *sig, const QVaListPrivate &args);
|
||||
QJniObject(const char *className, const char *signature, const QVaListPrivate &args);
|
||||
QJniObject(jclass clazz, const char *signature, const QVaListPrivate &args);
|
||||
|
||||
template <typename T>
|
||||
T callMethodV(const char *methodName, const char *sig, va_list args) const;
|
||||
QJniObject callObjectMethodV(const char *methodName, const char *sig, va_list args) const;
|
||||
T callMethodV(const char *methodName, const char *signature, va_list args) const;
|
||||
QJniObject callObjectMethodV(const char *methodName,
|
||||
const char *signature,
|
||||
va_list args) const;
|
||||
template <typename T>
|
||||
static T callStaticMethodV(const char *className,
|
||||
const char *methodName,
|
||||
const char *sig,
|
||||
const char *signature,
|
||||
va_list args);
|
||||
template <typename T>
|
||||
static T callStaticMethodV(jclass clazz,
|
||||
const char *methodName,
|
||||
const char *sig,
|
||||
const char *signature,
|
||||
va_list args);
|
||||
|
||||
static QJniObject callStaticObjectMethodV(const char *className,
|
||||
const char *methodName,
|
||||
const char *sig,
|
||||
const char *signature,
|
||||
va_list args);
|
||||
|
||||
static QJniObject callStaticObjectMethodV(jclass clazz,
|
||||
const char *methodName,
|
||||
const char *sig,
|
||||
const char *signature,
|
||||
va_list args);
|
||||
|
||||
bool isSameObject(jobject obj) const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user