Using C++ within an Android Java app

Just putting this here so I have it when I need it. I haven’t cleaned this up so it’s easy to understand, but there’s not a lot to it. Just need to have the pieces below and you’ve got everything you need to quickly and easily bold cpp into an Android Java app.

Handy links I used to figure it out: –

here

and here

and maybe here too

Prereqs: Android Studio 3.4.1, NDK version 16.1 (but I doubt it matters which NDK)

Files you’ll need: –

DeltaJNI.cpp: Simple cpp file with a method that returns a String to Java. Must be in a cpp directory

#include <jni.h>        // JNI header provided by JDK
#include <stdio.h>      // C Standard IO Header
#include <iostream>
#include "DeltaJNI.h"      // Generated
#include <string>

// Implementation of the native method sayHello()
JNIEXPORT jstring JNICALL Java_com_ancientcoder_recog_MainActivity_sayHello(JNIEnv *env, jobject thisObj) {

    std::string hello = "-------------------------------- Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

 

DeltaJNI.h: Header file to go with the above cpp. Must be with the cpp file above in a cpp directory (see CMakeLists.txt for where I put it)

#include <jni.h>

#ifndef RECOG_DELTAJNI_H
#define RECOG_DELTAJNI_H

#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jstring JNICALL Java_com_ancientcoder_recog_MainActivity_sayHello(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif

#endif //RECOG_DELTA_H

 

CMakeLists.txt: Added to the app directory to facilitate building of the ‘native-lib’ lib

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
        src/main/cpp/DeltaJNI.cpp)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

 

build.gradle (in the ‘app’ directory): Add this at the bottom of (and inside of ) the “android {}” section:

externalNativeBuild {
    cmake {
        path "CMakeLists.txt"
    }
}

…and this at the bottom of (and inside of) of the “defaultConfig {}” section: –

externalNativeBuild {
    cmake {
        cppFlags ""
    }
}

 

Java: Add this to the java class that’s calling the C++. This loads the lib that’s built by the above CMakeLists.txt (includes the cpp file(s)) and declares a prototype for the sayHello method.

static {
    System.loadLibrary("native-lib"); // Load native library at runtime
    // This library contains a native method called sayHello()
}
private native String sayHello();

 

More Java: …and finally, add this to actually call the cpp from the java code. This will log out the returned string from the cpp code: –

Log.e(TAG, sayHello());

 

 

Advertisements

CUDA Project Import Problem on Visual Studio 2019

I had a CUDA project that was running under Visual Studio 2017 and I moved to Visual Studio 2019, and got this error: –

The imported project “C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\BuildCustomizations\CUDA 10.1.props” was not found

The problem was a missing extension that had been installed as part of the CUDA SDK. To solve it, copy this directory content…

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\extras\visual_studio_integration\MSBuildExtensions

…into this directory: –

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\BuildCustomizations

Hope it helps!

 

 

 

 

 

 

C#: Get the current method name

Quick bit of code to display the current method name (Switch “Debug.Log” for “Console.WriteLine” to use it without Unity)

System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace();
Debug.Log(st.GetFrame(0).GetMethod().Name);

 

 

C# Serialize to Binary

Quick code snippet to show serialization of a class to a binary file called data.bin.

Two points to note; 1) The constructor on the class must be parameter-less and 2) the class (and all sub-classes) must be marker as [Serializable].

using System.Runtime.Serialization.Formatters.Binary;

using (Stream stream = File.Open("./data.bin", FileMode.Create))
{
var bin = new BinaryFormatter();
bin.Serialize(stream, classToSerialize);
stream.Close();
}

 

 

Unity: Is this point inside a box?

See if a point is inside a box by doing a reverse transform on the point into box local space.

bool PointInBox(Vector3 a_point, BoxCollider a_box)
{
    // Transform the point into box local space
    a_point = a_box.transform.InverseTransformPoint(a_point) - a_box.center;

    // see if the point is inside the box local space
    Vector3 half = a_box.size * 0.5f;
    if (a_point.x < half.x && a_point.x > -half.x &&
    a_point.y < half.y && a_point.y > -half.y &&
    a_point.z < half.z && a_point.z > -half.z)
    {
        // Get a 0.0 to 1.0 range for each axis
        Vector3 current = a_point + half;
        m_last.x = current.x / a_box.size.x;
        m_last.y = current.y / a_box.size.y;
        m_last.z = current.z / a_box.size.z;

        m_lastPoint = a_point; // Set the last valid point inside the test area
        return true;
    }
    return false;
}