All Ruby on Rails Node JS Android iOS React Native Frontend

Handling Cross-Platform Frameworks in Native Applications

In this article, I will cover how we connected to our Android project, shared (between iOS and Android) library written in C++. If you don't know anything about Android NDK (native development kit) or C++, you can still learn from this article the overall method. That could help your team write logic once and share it.
So let’s begin from the library file structure. In the image below we can see that we have three subfolders in our library.

Screenshot 2019-01-18 at 10.24.28

“Shared” folder is a place where we keep our shared library logic written in C++. In the “Android” folder, we have a project with our Android library module (which use shared code) and sample app, and of course the same is in “iOS” folder but for iOS platform of course.

Screenshot 2019-01-18 at 10.40.15

Our Android project has three modules:

  • The sample app where we connect our library module and check if all is working just fine,

  • OpenCV module which is needed by our library,

  • Library module itself.

Our Android library uses Shared code which uses OpenCV so we need to add it to our library in the first place. If you have a hard time to fully understand you can go to our example.

Ok so let's focus on library module. In build.gradle from this module, under android {..  we need to add two things.

A path to our shared logic:

sourceSets {
   main {
       jni.srcDirs "../../Shared"
   }
}
and information that we are using native build, with a path to CMakeLists.txt file (which we will add later).
externalNativeBuild {
   cmake {
       path "CMakeLists.txt"
   }
}

Also, we need to add our dependence to opencv module.

implementation project(':opencv')

Let's move to CMakeLists.txt file. We need to add it next to build.gradle in the library module. If you create a new project and mark to include C++ support it will generate automatically in your app module. You can then copy that file to your library module and based on comments change to use your native library code.

Define the name of the library, set it as “SHARED” and add the path to your source files.

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/native-lib.cpp
            ../../Shared/SheetDetection.cpp
       )

Under that in the same file, add the library to target_link_libraries(.. and add the same for OpenCV (example below). The best way is to check our sample and read the comments or documentation.

You can say, “Ok, but how OpenCV is connected to your shared files?”.

So in shared C++ classes, we have importes to OpenCV like

#include <opencv2/core/core.hpp>

which are ok because we added dependency in CMakeLists.txt file as:

set(OpenCV_DIR "../opencv/src/sdk/native/jni")
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV libraries: ${OpenCV_LIBS}")
target_link_libraries(native-lib ${OpenCV_LIBS})

Screenshot 2019-01-18 at 13.35.36Now it’s time to add our native-lib.cpp under main -> cpp folder. If you want to know how to write your own just check documentation and you can look at our example. Sample function starts like:

 

extern "C" JNIEXPORT jobject JNICALL
Java_co_netguru_vrhouseframework_NativeRecognizer_cropSelectedArea(
       JNIEnv *env,
       jobject _this,
       jobject bitmap,
       jfloatArray points) {...

Inside we declare functions that we will use in our Kotlin (or Java) classes which will be the “interface” for our library.

So moving to those classes first you need to load your native library you can do it in static function to do it as quick as possible.

companion object {
   init {
       System.loadLibrary("native-lib")
   }
}

To expose your native method you need to override it with a special keyword for Kotlin it will be “external” and for Java “native”.

external override fun cropSelectedArea(bitmap: Bitmap, points: FloatArray): Bitma

Remember that function from native-lib.cpp must be correct with you package, class name and function name (each separated by “_”) like in the example above with Java_co_netguru_vrhouseframework_NativeRecognizer_cropSelectedArea(...).

That’s all for the library part!

Now how to add it to your project:

  1. Open AndroidStudio project (I assume it has Git configured).

  2. From android studio project terminal add library repository as a submodule (our example)
    git submodule add git@github.com:netguru/3d-house-framework.git
    It will also add files like sample app but don’t worry it won't be added to our app repository.

  3. You will get a message like "Unregistered VCS root detected ..." Click on "Add root". Now you can see multiple git repositories at the bottom right of the android studio (Git branches view).

  4. Go to “File” menu  ->  project structure

  5. Click ‘+’ on left top to add a module

  6. Select ‘Import Gradle Project’ from the new window

  7. Select the sub-module folder with lib

  8. Give the actual sub-module project name (if needed)

  9. Sync

  10. You should have your sub-module added!

  11. Just add library module to app level build.gradle as a dependency (eg. implementation project(':vrhouseframework') and that's all!

Now you can use your library in app classes.

Photo by rawpixel on Unsplash

Let's make the world better for everyone - join us
READ ALSO FROM Android
Read also
Need a successful project?
Estimate project or contact us