Android: Add some developer documentation to AndroidBackendRegister

A quick blurb to explain the usecase and limitations of
AndroidBackendRegister, meant for future developers.

Also documents the two public-facing functions, getInterface()
and callInterface().

Change-Id: I79f07d4a19fdb1f4a53529ab42a8663999759f85
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
Petri Virkkunen 2025-05-22 14:14:30 +03:00
parent c2ec20b226
commit 43e52253d5

View File

@ -19,6 +19,57 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcAndroidBackendRegister)
/*
\internal
This class is used to [un]register QJniObjects which implement specific interfaces. These
objects can then be fetched or directly called by using that interface.
This is intended to decouple the Qt C++ code from the underlying Java implementation, as Qt now
has multiple separate usecases, each of which may have different implementations and support
different features.
To use this register, the interface must be declared as a JNI class via Q_DECLARE_JNI_CLASS:
Q_DECLARE_JNI_CLASS(ImaginaryInterface, "org/qtproject/qt/android/ImaginaryInterface")
Where ImaginaryInterface is a Java interface like this:
@UsedFromNativeCode
interface ImaginaryInterface {
void doSomething(int imaginary, int imaginary2);
}
After that, the features provided by that interface can be used in the C++ code in two ways:
Use the convenience method callInterface() to call a method directly:
AndroidBackendRegister *reg = QtAndroid::backendRegister();
int imaginary, imaginary2;
reg->callInterface<QtJniTypes::ImaginaryInterface, void>("doSomething", imaginary, imaginary2);
Or get the QJniObject directly and use it as you would any other QJniObject:
AndroidBackendRegister *reg = QtAndroid::backendRegister();
auto imaginary = reg->getInterface<QtJniTypes::ImaginaryInterface>();
// ... do whatever with QJniObject
In order to register a new interface on the Java side, the BackendRegister class must be used,
with its native functions registerBackend() and unregisterBackend():
BackendRegister.registerBackend(ImaginaryInterface.class, imaginaryInterfaceObject);
and
BackendRegister.unregisterBackend(ImaginaryInterface.class);
Note that only one object can be registered for each interface. If multiple objects are
registered, only the latest one is kept. Thus, you only need to declare the interface you want
to unregister, not the object that implements the interface as well.
If the interface needs to be available as soon as possible, it should be registered immediately
after Qt has started, by using the QtNative app state listener functionality.
*/
template <typename T>
using ValidInterfaceType = std::enable_if_t<std::is_base_of_v<QtJniTypes::JObjectBase, T>, bool>;
@ -27,6 +78,13 @@ class AndroidBackendRegister
public:
static bool registerNatives();
/*
\internal
Returns a QJniObject which is registered for the given interface.
Requires the type of the requested interface to be registered via
Q_DECLARE_JNI_CLASS. (see ValidInterfaceType).
*/
template <typename T, ValidInterfaceType<T> = true>
[[nodiscard]] T getInterface()
{
@ -39,6 +97,14 @@ public:
typename std::disjunction<std::is_base_of<QJniObject, Object>,
std::is_base_of<QtJniTypes::JObjectBase, Object>>;
/*
\internal
Convenience function that calls getInterface<Interface>() and then QJniObject::callMethod()
on the resulting object, forwarding the rest of the parameters to that function.
If the interface is not registered, a warning is printed and an empty object is returned.
*/
template <typename Interface, typename Ret, typename... Args,
ValidInterfaceType<Interface> = true>
auto callInterface(const char *func, Args... args)