Forums

OverviewV-Play 2 Support (Qt 5) › extending android Activity

Viewing 7 posts - 1 through 7 (of 7 total)
  • Author
    Posts
  • #14962

    Bas

    hi I need to add some custom java to my game.

    what is the best way to do this?

    #14964

    Günther
    V-Play Team

    Hi Bas!

    The general process of mixing Java code with QML/V-Play goes over C++, which can communicate with custom Java classes over JNI.

    In *.pro file configuration you can add a setting that includes custom java-sources in the compilation process, for example:

    android {
        QT += androidextras # for QAndroidJNIObject
    
        HEADERS += \
          cpp/myandroidutils.h # c++ class that will be accessible through QML
    
        SOURCES += \
            cpp/myandroidutils.cpp # implementation of c++ class, uses JNI to access JAVA sources
    
        # java class that will be called via JNI
        JAVASOURCES += \
            $$PWD/android/src/net/myproject/helper/MyAndroidUtils.java
    
    }

    The androidextras Qt module holds C++ classes for communicating with Java/Android over JNI.
    The HEADERS and SOURCES configuration in the above example add a C++ class called “myandroidutils”, which we can make accessible from QML later.
    The JAVASOURCES setting let’s you define the java classes you want to include in the build.

    As everything is put inside the android { } block, you can later add a different implementation of “myandroidutils” for other platforms like desktop or iOS, and e.g. print a warning that this feature is only available on Android when the myandroidutils component is used.

    In the main.cpp, you can then e.g. create an instance of the new class and add it as a context property:

    // ... 
    #include <QQmlContext>
    #include "cpp/mynativeutils.h"
    
    
    int main(int argc, char *argv[])
    {
      // ...
      engine.load(QUrl(vplay.mainQmlFileName()));
    
      // add myAndroidUtils as context property
      MyAndroidUtils *utils = new MyAndroidUtils(engine);
      engine.rootContext()->setContextProperty("myAndroidUtils", utils);
    
      return app.exec();
    }
    

    You can then use myAndroidUtils.myFunction(…) anywhere in your QML code, to access the MyAndroidUtils instance.
    This is also the way we integrate native Android features within the V-Play lib.

    Within your java class, you can access the root activity with QtNative.activity() and import org.qtproject.qt5.android.QtNative.
    Everything else comes down to implementing the Java parts and the C++ class for the communication C++ <-> JNI <-> JAVA.

    Best,
    Günther

     

     

     

     

     

    #14966

    Marcin
    #14967

    Bas

    hi Günther & Marcin,

    thanx both for the info.

    I need screen pinning on android, it is not that hard to implement, but i need to understand how to implement the bridge C++ <-> JNI <-> JAVA.

    Greetz,

    Bas

    #14968

    Bas

    hmm i cannot get it to work.

    # allows to add DEPLOYMENTFOLDERS and links to the V-Play library and QtCreator auto-completion
    CONFIG += v-play
    
    qmlFolder.source = qml
    DEPLOYMENTFOLDERS += qmlFolder # comment for publishing
    
    assetsFolder.source = assets
    DEPLOYMENTFOLDERS += assetsFolder
    
    # Add more folders to ship with the application here
    
    RESOURCES += #    resources.qrc # uncomment for publishing
    
    # NOTE: for PUBLISHING, perform the following steps:
    # 1. comment the DEPLOYMENTFOLDERS += qmlFolder line above, to avoid shipping your qml files with the application (instead they get compiled to the app binary)
    # 2. uncomment the resources.qrc file inclusion and add any qml subfolders to the .qrc file; this compiles your qml files and js files to the app binary and protects your source code
    # 3. change the setMainQmlFile() call in main.cpp to the one starting with "qrc:/" - this loads the qml files from the resources
    # for more details see the "Deployment Guides" in the V-Play Documentation
    
    # during development, use the qmlFolder deployment because you then get shorter compilation times (the qml files do not need to be compiled to the binary but are just copied)
    # also, for quickest deployment on Desktop disable the "Shadow Build" option in Projects/Builds - you can then select "Run Without Deployment" from the Build menu in Qt Creator if you only changed QML files; this speeds up application start, because your app is not copied & re-compiled but just re-interpreted
    
    
    # The .cpp file which was generated for your project. Feel free to hack it.
    SOURCES += main.cpp
    
    android {
        QT += androidextras # for QAndroidJNIObject
    
        ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
        OTHER_FILES += android/AndroidManifest.xml
    
        HEADERS += \
          basandroidutils.h # c++ class that will be accessible through QML
    
        SOURCES += \
          basandroidutils.cpp # implementation of c++ class, uses JNI to access JAVA sources
    
        # java class that will be called via JNI
    #    SOURCES += \
    #        android/com/lentfert/MyAndroidUtils.java
    #    OTHER_FILES += android/com/lentfert/MyAndroidUtils.java
        JAVASOURCES += \
            $$PWD/android/com/lentfert/MyAndroidUtils2.java
    }
    
    ios {
        QMAKE_INFO_PLIST = ios/Project-Info.plist
        OTHER_FILES += $$QMAKE_INFO_PLIST
    }
    
    # set application icons for win and macx
    win32 {
        RC_FILE += win/app_icon.rc
    }
    macx {
        ICON = macx/app_icon.icns
    }
    

     

    #ifndef BASANDROIDUTILS_H
    #define BASANDROIDUTILS_H
    
    #include <QObject>
    #include <QAndroidJniObject>
    #include <QQmlApplicationEngine>
    #include <QAndroidJniEnvironment>
    
    class basandroidutils : public QObject
    {
        Q_OBJECT
    
    public:
        explicit basandroidutils(QQmlApplicationEngine *parent = 0);
    
    
    public slots:
        int fibonacci(int n);
        int add1(int n);
    };
    
    #endif // BASANDROIDUTILS_H
    

     

    #include "basandroidutils.h"
    
    basandroidutils::basandroidutils(QQmlApplicationEngine *parent) : QObject(parent)
    {
    
    }
    
    int basandroidutils::fibonacci(int n)
    {
        qDebug("------------------------");
        qDebug("test call java static method -> fibonacci");
    
        jint result = -1;
        result = QAndroidJniObject::callStaticMethod<jint>
                ("com/lentfert/MyAndroidUtils" // class name
                 , "fibonacci" // method name
                 , "(I)I" // signature
                 , n);
    
    
        QAndroidJniEnvironment env;
        if (env->ExceptionCheck())
        {
            // Handle exception here.
            qDebug("*** JNI exception ***");
            env->ExceptionDescribe();
            env->ExceptionClear();
            env->ExceptionClear();
        }
        else
        {
            qDebug("result = %i", result);
        }
        return result;
    }
    int basandroidutils::add1(int n)
    {
        qDebug("------------------------");
        qDebug("test call java static method -> add1");
    
        jint result = -1;
    
        result = QAndroidJniObject::callStaticMethod<jint>
                ("com/lentfert/MyAndroidUtils" // class name
                 , "add1" // method name
                 , "(I)I" // signature
                 , n);
    
        QAndroidJniEnvironment env;
        if (env->ExceptionCheck())
        {
            // Handle exception here.
            qDebug("*** JNI exception ***");
            env->ExceptionDescribe();
            env->ExceptionClear();
            env->ExceptionClear();
        }
        else
        {
            qDebug("result = %i", result);
        }
        return result;
    }
    

     

    #include <QApplication>
    #include <VPApplication>
    
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    #include "basandroidutils.h"
    
    int main(int argc, char *argv[])
    {
    
        QApplication app(argc, argv);
    
        VPApplication vplay;
    
    //    qmlRegisterType<basandroidutils>("com.lentfert.basandroidutils", 1, 0, "BasAndroidUtils");
    
        // QQmlApplicationEngine is the preferred way to start qml projects since Qt 5.2
        // if you have older projects using Qt App wizards from previous QtCreator versions than 3.1, please change them to QQmlApplicationEngine
        QQmlApplicationEngine engine;
        vplay.initialize(&engine);
    
        // use this during development
        // for PUBLISHING, use the entry point below
        vplay.setMainQmlFileName(QStringLiteral("qml/Main.qml"));
    
    //    basandroidutils *utils = new basandroidutils(engine);
        basandroidutils *utils = new basandroidutils();
     //   QQmlContext *qqc = engine.rootContext();
    //    qqc->setContextProperty("myAndroidUtils", utils);
        engine.rootContext()->setContextProperty("myAndroidUtils", utils);
    
        // use this instead of the above call to avoid deployment of the qml files and compile them into the binary with qt's resource system qrc
        // this is the preferred deployment option for publishing games to the app stores, because then your qml files and js files are protected
        // to avoid deployment of your qml files and images, also comment the DEPLOYMENTFOLDERS command in the .pro file
        // also see the .pro file for more details
        //  vplay.setMainQmlFileName(QStringLiteral("qrc:/qml/Main.qml"));
    
        engine.load(QUrl(vplay.mainQmlFileName()));
    
        return app.exec();
    }
    

     

    import VPlay 2.0
    import QtQuick 2.0
    //import com.lentfert.basandroidutils 1.0
    
    GameWindow {
        id: gameWindow
    
        // You get free licenseKeys from http://v-play.net/licenseKey
        // With a licenseKey you can:
        //  * Publish your games & apps for the app stores
        //  * Remove the V-Play Splash Screen or set a custom one (available with the Pro Licenses)
        //  * Add plugins to monetize, analyze & improve your apps (available with the Pro Licenses)
        //licenseKey: "<generate one from http://v-play.net/licenseKey>"
    
        activeScene: scene
    
        // the size of the Window can be changed at runtime by pressing Ctrl (or Cmd on Mac) + the number keys 1-8
        // the content of the logical scene size (480x320 for landscape mode by default) gets scaled to the window size based on the scaleMode
        // you can set this size to any resolution you would like your project to start with, most of the times the one of your main target device
        // this resolution is for iPhone 4 & iPhone 4S
        screenWidth: 960
        screenHeight: 640
    
    
    
        Scene {
            id: scene
    
            // the "logical size" - the scene content is auto-scaled to match the GameWindow size
            width: 480
            height: 320
    
    
    //        BasAndroidUtils { id:butils }
    
            Component.onCompleted:  {
                var fib = myAndroidUtils.fibonacci(3)
                console.log("myAndroidUtils.fibonacci(3)")
                console.log(fib)
                var a1 = myAndroidUtils.add1(2);
                console.log("myAndroidUtils.add1(2)")
                console.log(a1)
            }
    
        }
    }
    

    D AndroidJniTest: ../AndroidJniTest/basandroidutils.cpp:10 (int basandroidutils::fibonacci(int)): ————————

    D AndroidJniTest: ../AndroidJniTest/basandroidutils.cpp:11 (int basandroidutils::fibonacci(int)): test call java static method -> fibonacci

    D AndroidJniTest: ../AndroidJniTest/basandroidutils.cpp:32 (int basandroidutils::fibonacci(int)): result = 0

    D AndroidJniTest: assets:/qml/Main.qml:38 (onCompleted): qml: myAndroidUtils.fibonacci(3)

    D AndroidJniTest: assets:/qml/Main.qml:39 (onCompleted): qml: 0

    D AndroidJniTest: ../AndroidJniTest/basandroidutils.cpp:38 (int basandroidutils::add1(int)): ————————

    D AndroidJniTest: ../AndroidJniTest/basandroidutils.cpp:39 (int basandroidutils::add1(int)): test call java static method add1

    D AndroidJniTest: ../AndroidJniTest/basandroidutils.cpp:60 (int basandroidutils::add1(int)): result = 0

    D AndroidJniTest: assets:/qml/Main.qml:41 (onCompleted): qml: myAndroidUtils.add1(2)

    D AndroidJniTest: assets:/qml/Main.qml:42 (onCompleted): qml: 0

    #14969

    Bas
    package com.lentfert;
    
    import android.util.Log;
    import org.qtproject.qt5.android.QtNative
    
    class MyJavaNatives
    {
    	// declare the native method
    	public static native void sendFibonaciResult(int n);
    }
    
    public class MyAndroidUtils
    {
        private static final String TAG = "MyAndroidUtils";
        
        // this method will be called from C/C++
        public static int add1(int n)
        {
            LOG.d(TAG, "add1 = " + n);
            
            return n + 1;
        }
        
        public static int fibonacci(int n)
        {
            if (n < 2)
                return n;
            return fibonacci(n-1) + fibonacci(n-2);
        }
    
    
        // the second method that will be called from C/C++
        public static void compute_fibonacci(int n)
        {
            // callback the native method with the computed result.
            MyJavaNatives.sendFibonaciResult(fibonacci(n));
        }
        
    }

    and a simple java class, i forgot

    #14971

    Bas

    ok I had the java file not in src directory:)

    now its working.

Viewing 7 posts - 1 through 7 (of 7 total)

RSS feed for this thread

You must be logged in to reply to this topic.

Voted #1 for:

  • Easiest to learn
  • Most time saving
  • Best support

Develop Cross-Platform Apps and Games 50% Faster!

  • Voted the best supported, most time-saving and easiest to learn cross-platform development tool
  • Based on the Qt framework, with native performance and appearance on all platforms including iOS and Android
  • Offers a variety of plugins to monetize, analyze and engage users
FREE!
create apps
create games
cross platform
native performance
3rd party services
game network
multiplayer
level editor
easiest to learn
biggest time saving
best support