Im attempting to build an Android NDK sample app supplied by Occipital Camera.
My gradle file is this:
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.example.myoccipitaltestapp"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
abiFilters 'arm64-v8a'
}
externalNativeBuild {
cmake {
cppFlags '-std=c++11'
arguments '-DANDROID_STL=c++_shared',
'-DANDROID_PLATFORM=android-24'
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path 'src/main/CMakeLists.txt'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
My CMakeLists.txt is (I had to hard code path to MainActivity, it was not being resolved otherwise):
# Autogenerated, do not edit
cmake_minimum_required(VERSION 3.6)
project(MainActivity)
add_library(MainActivity SHARED C:/Users/Fsydn/Desktop/occipital/StructureSDK-CrossPlatform-0.7.3-ROS/Libraries/MyOccipitalTestApp/app/src/main/cpp/MainActivity.cpp)
set_target_properties(MainActivity PROPERTIES LINK_FLAGS "-Wl,-rpath,'$ORIGIN'")
target_link_libraries(MainActivity PRIVATE
${PROJECT_SOURCE_DIR}/lib/${ANDROID_ABI}/libStructure.so
)
MainActivity.cpp with JNI wrappers is this:
// Autogenerated, do not edit
#include "AppInterface.h"
#include <jni.h>
#include <thread>
extern "C" JNIEXPORT void JNICALL Java_com_occipital_OccipitalTest_MainActivity_setupApp(JNIEnv*, jobject) {
AppInterface::setup();
}
extern "C" JNIEXPORT void JNICALL Java_com_occipital_OccipitalTest_MainActivity_teardownApp(JNIEnv*, jobject) {
AppInterface::teardown();
}
extern "C" JNIEXPORT void JNICALL Java_com_occipital_OccipitalTest_MainActivity_renderFrame(JNIEnv*, jobject, jint currentWidth, jint currentHeight, jfloat scaleFactor) {
AppInterface::renderFrame((unsigned)currentWidth, (unsigned)currentHeight, scaleFactor);
}
extern "C" JNIEXPORT void JNICALL Java_com_occipital_OccipitalTest_MainActivity_updateMouseState(JNIEnv*, jobject, jboolean down, jint x, jint y) {
AppInterface::updateMouseState(down, x, y);
}
extern "C" JNIEXPORT void JNICALL Java_com_occipital_OccipitalTest_MainActivity_plugStructureCoreFileDescriptor(JNIEnv*, jobject, jint fd) {
AppInterface::plugStructureCoreFileDescriptor(fd);
}
AppInterface.h:
#pragma once
/** These functions define the interface between cross-platform sample
application code and platform-specific wrappers. */
namespace AppInterface {
/** On desktop platforms this function is called in main() before
runUntilWindowClosed(). On Android it is called when the main activity
is created. */
void setup();
/** On desktop platforms this function is called in main() after
runUntilWindowClosed(). On Android it is called when the main activity
is destroyed. */
void teardown();
#if __ANDROID__
/** See Window::renderFrameInGLSurfaceViewContext(). */
void renderFrame(unsigned currentWidth, unsigned currentHeight, float scaleFactor);
/** See Window::updateMouseState(). */
void updateMouseState(bool down, int x, int y);
/** For applications that require Structure Core USB support. The argument
is a file descriptor from the Android UsbDeviceConnection API and should
be passed to ST::registerSensorByUSBFileDescriptor() or equivalent. */
void plugStructureCoreFileDescriptor(int fd);
#else
/** Called in main(). */
void runUntilWindowClosed();
#endif
}
MainActivity.java (were libStructure.so is statically loaded):
package com.example.myoccipitaltestapp;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.usb.UsbDeviceConnection;
import android.Manifest;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.opengl.GLSurfaceView;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.egl.EGLConfig;
public class MainActivity extends Activity implements com.example.myoccipitaltestapp.StructureCoreUSBHelper.Delegate, ActivityCompat.OnRequestPermissionsResultCallback {
private class GLRenderer implements GLSurfaceView.Renderer {
private MainActivity owner;
private int width;
private int height;
public GLRenderer(MainActivity owner) {
this.owner = owner;
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {}
public void onSurfaceChanged(GL10 gl, int width, int height) {
this.width = width;
this.height = height;
}
public void onDrawFrame(GL10 gl) {
owner.renderFrame(width, height, owner.scaleFactor);
}
}
private class GLView extends GLSurfaceView {
private MainActivity owner;
private boolean mouseDown;
public GLView(Context context, MainActivity owner) {
super(context);
this.owner = owner;
}
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mouseDown = true;
owner.updateMouseState(mouseDown, (int)x, (int)y);
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mouseDown = false;
owner.updateMouseState(mouseDown, (int)x, (int)y);
return true;
case MotionEvent.ACTION_MOVE:
owner.updateMouseState(mouseDown, (int)x, (int)y);
return true;
default:
return false;
}
}
}
private GLView glView;
private volatile float scaleFactor = 1.f;
private com.example.myoccipitaltestapp.StructureCoreUSBHelper usbHelper;
private float computeScaleFactor() {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
return metrics.density;
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupApp();
scaleFactor = computeScaleFactor();
glView = new GLView(this, this);
glView.setEGLContextClientVersion(3);
glView.setPreserveEGLContextOnPause(true);
glView.setRenderer(new GLRenderer(this));
glView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
setContentView(glView);
usbHelper = new com.example.myoccipitaltestapp.StructureCoreUSBHelper(this, this);
}
protected void onDestroy() {
super.onDestroy();
teardownApp();
}
public void onConfigurationChanged(Configuration config) {
super.onConfigurationChanged(config);
scaleFactor = computeScaleFactor();
glView.requestRender();
}
protected void onPause() {
super.onPause();
glView.onPause();
}
protected void onResume() {
super.onResume();
glView.onResume();
ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
}, 1);
}
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
}
public void newStructureCoreDevice(UsbDeviceConnection conn) {
plugStructureCoreFileDescriptor(conn.getFileDescriptor());
}
private native void setupApp();
private native void teardownApp();
private native void renderFrame(int currentWidth, int currentHeight, float scaleFactor);
private native void updateMouseState(boolean down, int x, int y);
private native void plugStructureCoreFileDescriptor(int fd);
static {
System.loadLibrary("Structure");
}
/*
Also tried
static {
System.loadLibrary("libStructure");
}
*/
}
When i run build in Android Studio, Im getting these errors:
1) issue:
Build command failed.
Error while executing process C:\Users\Fsydn\AppData\Local\Android\Sdk\cmake\3.10.2.4988404\bin\ninja.exe with arguments {-C C:\Users\Fsydn\Desktop\occipital\StructureSDK-CrossPlatform-0.7.3-ROS\Libraries\MyOccipitalTestApp\app\.cxx\cmake\debug\arm64-v8a MainActivity}
ninja: Entering directory `C:\Users\Fsydn\Desktop\occipital\StructureSDK-CrossPlatform-0.7.3-ROS\Libraries\MyOccipitalTestApp\app\.cxx\cmake\debug\arm64-v8a'
[1/2] Building CXX object CMakeFiles/MainActivity.dir/cpp/MainActivity.cpp.o
[2/2] Linking CXX shared library C:\Users\Fsydn\Desktop\occipital\StructureSDK-CrossPlatform-0.7.3-ROS\Libraries\MyOccipitalTestApp\app\build\intermediates\cmake\debug\obj\arm64-v8a\libMainActivity.so
FAILED: C:/Users/Fsydn/Desktop/occipital/StructureSDK-CrossPlatform-0.7.3-ROS/Libraries/MyOccipitalTestApp/app/build/intermediates/cmake/debug/obj/arm64-v8a/libMainActivity.so
cmd.exe /C "cd . && C:\Users\Fsydn\AppData\Local\Android\Sdk\ndk\21.1.6352462\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=aarch64-none-linux-android24 --gcc-toolchain=C:/Users/Fsydn/AppData/Local/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/windows-x86_64 --sysroot=C:/Users/Fsydn/AppData/Local/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/windows-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -std=c++11 -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -Wl,--build-id -Wl,--fatal-warnings -Wl,--no-undefined -Qunused-arguments -Wl,-rpath,'$ORIGIN' -shared -Wl,-soname,libMainActivity.so -o C:\Users\Fsydn\Desktop\occipital\StructureSDK-CrossPlatform-0.7.3-ROS\Libraries\MyOccipitalTestApp\app\build\intermediates\cmake\debug\obj\arm64-v8a\libMainActivity.so CMakeFiles/MainActivity.dir/cpp/MainActivity.cpp.o -LC:/Users/Fsydn/Desktop/occipital/StructureSDK-CrossPlatform-0.7.3-ROS/Libraries/MyOccipitalTestApp/app/src/main/lib/arm64-v8a -lStructure -latomic -lm && cd ."
CMakeFiles/MainActivity.dir/cpp/MainActivity.cpp.o: In function `Java_com_occipital_OccipitalTest_MainActivity_setupApp':
C:/Users/Fsydn/Desktop/occipital/StructureSDK-CrossPlatform-0.7.3-ROS/Libraries/MyOccipitalTestApp/app/src/main/cpp/MainActivity.cpp:8: undefined reference to `AppInterface::setup()'
CMakeFiles/MainActivity.dir/cpp/MainActivity.cpp.o: In function `Java_com_occipital_OccipitalTest_MainActivity_teardownApp':
C:/Users/Fsydn/Desktop/occipital/StructureSDK-CrossPlatform-0.7.3-ROS/Libraries/MyOccipitalTestApp/app/src/main/cpp/MainActivity.cpp:12: undefined reference to `AppInterface::teardown()'
CMakeFiles/MainActivity.dir/cpp/MainActivity.cpp.o: In function `Java_com_occipital_OccipitalTest_MainActivity_renderFrame':
C:/Users/Fsydn/Desktop/occipital/StructureSDK-CrossPlatform-0.7.3-ROS/Libraries/MyOccipitalTestApp/app/src/main/cpp/MainActivity.cpp:16: undefined reference to `AppInterface::renderFrame(unsigned int, unsigned int, float)'
CMakeFiles/MainActivity.dir/cpp/MainActivity.cpp.o: In function `Java_com_occipital_OccipitalTest_MainActivity_updateMouseState':
C:/Users/Fsydn/Desktop/occipital/StructureSDK-CrossPlatform-0.7.3-ROS/Libraries/MyOccipitalTestApp/app/src/main/cpp/MainActivity.cpp:20: undefined reference to `AppInterface::updateMouseState(bool, int, int)'
CMakeFiles/MainActivity.dir/cpp/MainActivity.cpp.o: In function `Java_com_occipital_OccipitalTest_MainActivity_plugStructureCoreFileDescriptor':
C:/Users/Fsydn/Desktop/occipital/StructureSDK-CrossPlatform-0.7.3-ROS/Libraries/MyOccipitalTestApp/app/src/main/cpp/MainActivity.cpp:24: undefined reference to `AppInterface::plugStructureCoreFileDescriptor(int)'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
2) issue, Also the Android IDE complains about , these lines in MainActivity.java
private native void setupApp();
private native void teardownApp();
private native void renderFrame(int currentWidth, int currentHeight, float scaleFactor);
private native void updateMouseState(boolean down, int x, int y);
private native void plugStructureCoreFileDescriptor(int fd);
cannot resolve corresponding JNI functions...
How can I resolve this problems to build this sample app?