From 43e52253d59c606ceca00a999b28eaf96365bc5c Mon Sep 17 00:00:00 2001 From: Petri Virkkunen Date: Thu, 22 May 2025 14:14:30 +0300 Subject: [PATCH] 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 --- .../android/androidbackendregister.h | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/plugins/platforms/android/androidbackendregister.h b/src/plugins/platforms/android/androidbackendregister.h index 06b7b832416..9c1975beecf 100644 --- a/src/plugins/platforms/android/androidbackendregister.h +++ b/src/plugins/platforms/android/androidbackendregister.h @@ -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("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(); + // ... 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 using ValidInterfaceType = std::enable_if_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 = true> [[nodiscard]] T getInterface() { @@ -39,6 +97,14 @@ public: typename std::disjunction, std::is_base_of>; + /* + \internal + + Convenience function that calls getInterface() 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 = true> auto callInterface(const char *func, Args... args)