Trying to run local server from inside an android app, but the app keep trashing the time the button is clicked to run the server, my code is:
package tk.android
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Example of a call to a native method
findViewById<TextView>(R.id.sample_text).text = stringFromJNI()
btn.setOnClickListener {
txt.setText(reverse(txt.text.toString()))
server()
}
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
external fun stringFromJNI(): String
external fun server() : Void // extern void server(); // Here is the server
private external fun reverse(str: String): String // extern char* reverse(char* in)
companion object {
// Used to load the 'native-lib' library on application startup.
init {
System.loadLibrary("native-lib")
}
}
}
The android app is built with Native where 3 functions are defined, 2 of then running smoothly, but the one related to the server is crasking.
My native functions are defined as:
// file cpp/native-lib.cpp
#include <jni.h>
#include <string>
#include "libfoo.h" // our library header
extern "C" JNIEXPORT jstring JNICALL
Java_tk_android_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C" {
jstring
Java_tk_android_MainActivity_reverse(JNIEnv* env, jobject, jstring str) {
// Reverse text here
const char* cstr = env->GetStringUTFChars(str, 0);
char* cout = reverse(const_cast<char*>(cstr));
jstring out = env->NewStringUTF(cout);
env->ReleaseStringUTFChars(str, cstr);
free(cout);
return out;
}
}
extern "C" {
void
Java_tk_android_MainActivity_server() {
// Nothing here, as it is void input and void output
server();
}
}
With the CMake file defined as:
cmake_minimum_required(VERSION 3.10.2)
project("android")
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).
native-lib.cpp )
add_library(lib_foo SHARED IMPORTED)
set_property(TARGET lib_foo PROPERTY IMPORTED_NO_SONAME 1)
set_target_properties(lib_foo PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libfoo.so)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}/)
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 )
target_link_libraries( # Specifies the target library.
native-lib
lib_foo
# Links the target library to the log library
# included in the NDK.
${log-lib} )
The server file I'm running is simple one built with GO, and compiled as shared library
package main
import "C"
// other imports should be seperate from the special Cgo import
import (
"fmt"
"log"
"net/http"
)
//export reverse
func reverse(in *C.char) *C.char {
return C.CString(foo.Reverse(C.GoString(in)))
}
//export server
func server() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func Reverse(in string) string {
n := 0
rune := make([]rune, len(in))
for _, r := range in {
rune[n] = r
n++
}
rune = rune[0:n]
for i := 0; i < n/2; i++ {
rune[i], rune[n-1-i] = rune[n-1-i], rune[i]
}
return string(rune)
}
func main() {}
Compiled to Android with the below Make file:
//file: Makefile
ANDROID_OUT=../myApp/app/src/main/jniLibs
ANDROID_SDK=$(HOME)/Library/Android/sdk
NDK_BIN=$(ANDROID_SDK)/ndk/23.0.7599858/toolchains/llvm/prebuilt/darwin-x86_64/bin
android-armv7a:
CGO_ENABLED=1 \
GOOS=android \
GOARCH=arm \
GOARM=7 \
CC=$(NDK_BIN)/armv7a-linux-androideabi21-clang \
go build -buildmode=c-shared -o $(ANDROID_OUT)/armeabi-v7a/libfoo.so ./cmd/libfoo
android-arm64:
CGO_ENABLED=1 \
GOOS=android \
GOARCH=arm64 \
CC=$(NDK_BIN)/aarch64-linux-android21-clang \
go build -buildmode=c-shared -o $(ANDROID_OUT)/arm64-v8a/libfoo.so ./cmd/libfoo
android-x86:
CGO_ENABLED=1 \
GOOS=android \
GOARCH=386 \
CC=$(NDK_BIN)/i686-linux-android21-clang \
go build -buildmode=c-shared -o $(ANDROID_OUT)/x86/libfoo.so ./cmd/libfoo
android-x86_64:
CGO_ENABLED=1 \
GOOS=android \
GOARCH=amd64 \
CC=$(NDK_BIN)/x86_64-linux-android21-clang \
go build -buildmode=c-shared -o $(ANDROID_OUT)/x86_64/libfoo.so ./cmd/libfoo
android: android-armv7a android-arm64 android-x86 android-x86_64
I do not know if there is something wrong in the definision of Java_tk_android_MainActivity_server() or it is crashing because the server will be listening to http signal!
I got the follwoing only once the app crash:
I/chatty: uid=10104(tk.android) Thread-2 identical 1 line
W/tk.android: Accessing hidden method
Landroid/database/sqlite/SQLiteDatabase;->yieldIfContendedHelper(ZJ)Z
(greylist-max-o, linking, denied)
Related
I have been trying to read JSON data from a JSON string, but my app keeps crashing immediately after it starts. No errors are displayed.
The JSON string is passed from the Javascript code in React Native :
let myJSONString = JSON.stringify({foo: "bar"});
The CMakeLists.txt file that sets up boost :
set(my_boost_dir ${CMAKE_CURRENT_SOURCE_DIR}/libs/ndk_25_boost_1.79.0)
set(MY_BOOST_LIBS_DIR ${my_boost_dir}/libs)
set(MY_BOOST_INC_DIR ${my_boost_dir}/include)
#-----------------------------------------
add_library (libboost_container SHARED IMPORTED)
set_target_properties( libboost_container PROPERTIES IMPORTED_LOCATION
${MY_BOOST_LIBS_DIR}/${ANDROID_ABI}/libboost_container.so
)
#-----------------------------------------
#-----------------------------------------
add_library (libboost_json SHARED IMPORTED)
set_target_properties( libboost_json PROPERTIES IMPORTED_LOCATION
${MY_BOOST_LIBS_DIR}/${ANDROID_ABI}/libboost_json.so
)
#-----------------------------------------
#-----------------------------------------
add_library (libboost_system SHARED IMPORTED)
set_target_properties( libboost_system PROPERTIES IMPORTED_LOCATION
${MY_BOOST_LIBS_DIR}/${ANDROID_ABI}/libboost_system.so
)
#-----------------------------------------
add_library( libboost_chrono SHARED IMPORTED)
set_target_properties(libboost_chrono PROPERTIES IMPORTED_LOCATION
${MY_BOOST_LIBS_DIR}/${ANDROID_ABI}/libboost_chrono.so
)
#-----------------------------------------
include_directories( ${MY_BOOST_INC_DIR}
)
This is how I try reading the JSON string :
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/json.hpp>
JNIEXPORT jstring JNICALL
Java_com_ca_com_1gen_1lib_1pers_c_1libs_1core_MyStringToJSON_myStringToJSON(JNIEnv *env,
jobject instance,
jstring myJSONStringEntity_)
{
const char *myJSONStringEntity = env->GetStringUTFChars(myJSONStringEntity_, 0);
// Short alias for this namespace
namespace pt = boost::property_tree;
// Create a root
pt::ptree root;
// Load the json file in this ptree
pt::read_json(myJSONStringEntity, root);
// Read values
std::string returnVal = root.get<std::string>("foo", 0);
return returnVal;
}
Where am I doing it wrong?
Thank you all in advance.
You're mixing Boost JSON (a JSON library) and Boost Property (a Property Tree Library). Only use the first!
Live On Coliru
#include <boost/json.hpp>
#include <boost/json/src.hpp> // for COLIRU (header-only)
#include <iostream>
#define JNIEXPORT
#define JNICALL
using jstring = std::string;
struct jobject { };
struct JNIEnv { char const* GetStringUTFChars(jstring const& s, int) { return s.data(); } };
JNIEXPORT jstring JNICALL
Java_com_ca_com_1gen_1lib_1pers_c_1libs_1core_MyStringToJSON_myStringToJSON(JNIEnv *env,
jobject /*instance*/,
jstring myJSONStringEntity_)
{
const char *myJSONStringEntity = env->GetStringUTFChars(myJSONStringEntity_, 0);
// Short alias for this namespace
namespace bj = boost::json;
// Create a root
bj::value root = bj::parse(myJSONStringEntity);
// Read values
std::string returnVal{root.at("foo").as_string()};
return returnVal;
}
int main() {
auto f = Java_com_ca_com_1gen_1lib_1pers_c_1libs_1core_MyStringToJSON_myStringToJSON;
std::cout << "Example: " << f(nullptr, {}, R"({"foo":"bar", "qux": [1,2,3]})") << "\n";
}
Prints
Example: bar
In Android, I am facing issues in connecting two cpp class in native Android. I have tested with the single class it working fine.
but when I have created another file and now facing an issue in linking it with current cpp file.
MainClass.cpp
#include <jni.h>
#include "native-handler.h"
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_fragment_SampleFragment_setTitle(JNIEnv *env,jobject instance,jobject context) {
ClassNativeHandler classNativeHandler;
return classNativeHandler.getType(env,context);
}
native-handler.cpp
#include <jni.h>
#include "native-handler.h"
jstring jstringObject;
jstring ClassNativeHandler::getType(JNIEnv *env, jobject contextObject) {
jstring jstringObject = env->NewStringUTF("Hello world");
return jstringObject;
}
void ClassNativeHandler::setType(jstring string) {
myType = string;
jstringObject = string;
}
native-handler.h
#ifndef SAMPLE_NATIVE_HANDLER_H
#define SAMPLE_NATIVE_HANDLER_H
#include <iostream>
#include <string>
class ClassNativeHandler
{
private:
jstring myType;
public:
void setType(jstring string);
jstring getType(JNIEnv *env, jobject contextObject);
jstring getHeaderName(JNIEnv *env);
};
#endif //SAMPLE_NATIVE_HANDLER_H
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Native
LOCAL_SRC_FILES := ../cpp/mainClass.cpp
LOCAL_C_INCLUDES := ../cpp/native-handler.h
LOCAL_LDLIBS := -lz -llog -ljnigraphics
include $(BUILD_SHARED_LIBRARY)
Error : undefined reference to `ClassNativeHandler::getType(_JNIEnv*, _jobject*)'
on this line
return classNativeHandler.getType(env,context);
So I am not able to build the .so file. Please guide me
You haven't compiled native-handler.cpp. You need to specify it in LOCAL_SRC_FILES so that NDK compiles it.
LOCAL_SRC_FILES := ../cpp/mainClass.cpp ../cpp/native-handler.cpp
I want to use dynamic registration in native method, so I need set JNI_onLoad function. I just write a function to get sum of two numbers. But, it can't build correctly. How can I correct the error?
This is my *.cpp file, I name this file jni.cpp
#include <jni.h>
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
jni::jclass& nativeClass = jni::FindClass(env, "com/test/NativeClass");
#define MAKE_NATIVE_METHOD(name, sig) jni::MakeNativeMethod<decltype(name), name>( #name, sig )
jni::RegisterNatives(env, nativeClass, MAKE_NATIVE_METHOD(nativeAddTest, "(II)I") );
return JNI_VERSION_1_6;
}
jlong nativeAddTest(JNIEnv *env, jni::jobject* obj, jni::jint a, jni::jint b) {
return a+b;
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := jni.cpp
LOCAL_LDLIBS := -L/ndk-path/sources/cxx-stl/stlport/libs/armeabi
include $(BUILD_SHARED_LIBRARY)
When I use ndk-build command, it's wrong. But I really dont't konw the reason...
D:\WorkSpaces\Test\app\src\main\jni>ndk-build
[x86] Compile++ : test <= jni.cpp
D:/WorkSpaces/Test/app/src/main/jni/jni.cpp: In function 'jint JNI_OnLoad(JavaVM*, void*)':
D:/WorkSpaces/Test/app/src/main/jni/jni.cpp:9:5: error: 'jni' has not been declared
jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
^
D:/WorkSpaces/Test/app/src/main/jni/jni.cpp:9:18: error: 'env' was not declared in this scope
jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
....
It seems can't find jni.h, but I already have #include<jni.h>
In Android NDK, <jni.h> does not define a jni namespace. Simply remove all jni::
#include <jni.h>
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv env;
vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
jclass nativeClass = env->FindClass("com/test/NativeClass");
… and so on.
Add header location to your android.mk
LOCAL_C_INCLUDES := "path to your header location"
I have a perfectly working android project in Eclipse, the project includes NDK support and uses Gstreamer.
When I migrate the project from Eclipse to Android Studio all sorts of problems pop up, and I just cant successfully compile the project.
I did a thorough research on each and every error I've encountered but still couldn't compile and run the project on android studio.
https://drive.google.com/file/d/0B_euzgSjTAqcQngwbzR1cXY0MkU/view?usp=sharing
A link to the working Eclipse project, I hope someone could direct me on the right way.
This is the import summary:
ECLIPSE ANDROID PROJECT IMPORT SUMMARY
Ignored Files:
The following files were not copied into the new Gradle project; you
should evaluate whether these are still needed in your project and if
so manually move them:
.externalToolBuilders\
.externalToolBuilders\Wiz.launch
gst-build\
gst-build\gstreamer_android.c
gst-build\gstreamer_android.o
Replaced Jars with Dependencies:
The importer recognized the following .jar files as third party
libraries and replaced them with Gradle dependencies instead. This has
the advantage that more explicit version information is known, and the
libraries can be updated automatically. However, it is possible that
the .jar file in your project was of an older version than the
dependency we picked, which could render the project not compileable.
You can disable the jar replacement in the import wizard and try again:
android-support-v4.jar => com.android.support:support-v4:23.3.0
Moved Files:
Android Gradle projects use a different directory structure than ADT
Eclipse projects. Here's how the projects were restructured:
AndroidManifest.xml => app\src\main\AndroidManifest.xml
assets\ => app\src\main\assets\
jni\ => app\src\main\jni\
libs\armeabi\libavcodec.so => app\src\main\jniLibs\armeabi\libavcodec.so
libs\armeabi\libavdevice.so => app\src\main\jniLibs\armeabi\libavdevice.so
libs\armeabi\libavfilter.so => app\src\main\jniLibs\armeabi\libavfilter.so
libs\armeabi\libavformat.so => app\src\main\jniLibs\armeabi\libavformat.so
libs\armeabi\libavutil.so => app\src\main\jniLibs\armeabi\libavutil.so
libs\armeabi\libgstreamer_android.so => app\src\main\jniLibs\armeabi\libgstreamer_android.so
libs\armeabi\libjniARToolKitPlus.so => app\src\main\jniLibs\armeabi\libjniARToolKitPlus.so
libs\armeabi\libjniavcodec.so => app\src\main\jniLibs\armeabi\libjniavcodec.so
libs\armeabi\libjniavdevice.so => app\src\main\jniLibs\armeabi\libjniavdevice.so
libs\armeabi\libjniavfilter.so => app\src\main\jniLibs\armeabi\libjniavfilter.so
libs\armeabi\libjniavformat.so => app\src\main\jniLibs\armeabi\libjniavformat.so
libs\armeabi\libjniavutil.so => app\src\main\jniLibs\armeabi\libjniavutil.so
libs\armeabi\libjnicvkernels.so => app\src\main\jniLibs\armeabi\libjnicvkernels.so
libs\armeabi\libjniopencv_calib3d.so => app\src\main\jniLibs\armeabi\libjniopencv_calib3d.so
libs\armeabi\libjniopencv_contrib.so => app\src\main\jniLibs\armeabi\libjniopencv_contrib.so
libs\armeabi\libjniopencv_core.so => app\src\main\jniLibs\armeabi\libjniopencv_core.so
libs\armeabi\libjniopencv_features2d.so => app\src\main\jniLibs\armeabi\libjniopencv_features2d.so
libs\armeabi\libjniopencv_flann.so => app\src\main\jniLibs\armeabi\libjniopencv_flann.so
libs\armeabi\libjniopencv_highgui.so => app\src\main\jniLibs\armeabi\libjniopencv_highgui.so
libs\armeabi\libjniopencv_imgproc.so => app\src\main\jniLibs\armeabi\libjniopencv_imgproc.so
libs\armeabi\libjniopencv_legacy.so => app\src\main\jniLibs\armeabi\libjniopencv_legacy.so
libs\armeabi\libjniopencv_ml.so => app\src\main\jniLibs\armeabi\libjniopencv_ml.so
libs\armeabi\libjniopencv_nonfree.so => app\src\main\jniLibs\armeabi\libjniopencv_nonfree.so
libs\armeabi\libjniopencv_objdetect.so => app\src\main\jniLibs\armeabi\libjniopencv_objdetect.so
libs\armeabi\libjniopencv_photo.so => app\src\main\jniLibs\armeabi\libjniopencv_photo.so
libs\armeabi\libjniopencv_stitching.so => app\src\main\jniLibs\armeabi\libjniopencv_stitching.so
libs\armeabi\libjniopencv_video.so => app\src\main\jniLibs\armeabi\libjniopencv_video.so
libs\armeabi\libjniopencv_videostab.so => app\src\main\jniLibs\armeabi\libjniopencv_videostab.so
libs\armeabi\libjnipostproc.so => app\src\main\jniLibs\armeabi\libjnipostproc.so
libs\armeabi\libjniswresample.so => app\src\main\jniLibs\armeabi\libjniswresample.so
libs\armeabi\libjniswscale.so => app\src\main\jniLibs\armeabi\libjniswscale.so
libs\armeabi\libopencv_calib3d.so => app\src\main\jniLibs\armeabi\libopencv_calib3d.so
libs\armeabi\libopencv_contrib.so => app\src\main\jniLibs\armeabi\libopencv_contrib.so
libs\armeabi\libopencv_core.so => app\src\main\jniLibs\armeabi\libopencv_core.so
libs\armeabi\libopencv_features2d.so => app\src\main\jniLibs\armeabi\libopencv_features2d.so
libs\armeabi\libopencv_flann.so => app\src\main\jniLibs\armeabi\libopencv_flann.so
libs\armeabi\libopencv_highgui.so => app\src\main\jniLibs\armeabi\libopencv_highgui.so
libs\armeabi\libopencv_imgproc.so => app\src\main\jniLibs\armeabi\libopencv_imgproc.so
libs\armeabi\libopencv_info.so => app\src\main\jniLibs\armeabi\libopencv_info.so
libs\armeabi\libopencv_legacy.so => app\src\main\jniLibs\armeabi\libopencv_legacy.so
libs\armeabi\libopencv_ml.so => app\src\main\jniLibs\armeabi\libopencv_ml.so
libs\armeabi\libopencv_nonfree.so => app\src\main\jniLibs\armeabi\libopencv_nonfree.so
libs\armeabi\libopencv_objdetect.so => app\src\main\jniLibs\armeabi\libopencv_objdetect.so
libs\armeabi\libopencv_photo.so => app\src\main\jniLibs\armeabi\libopencv_photo.so
libs\armeabi\libopencv_stitching.so => app\src\main\jniLibs\armeabi\libopencv_stitching.so
libs\armeabi\libopencv_ts.so => app\src\main\jniLibs\armeabi\libopencv_ts.so
libs\armeabi\libopencv_video.so => app\src\main\jniLibs\armeabi\libopencv_video.so
libs\armeabi\libopencv_videostab.so => app\src\main\jniLibs\armeabi\libopencv_videostab.so
libs\armeabi\libpostproc.so => app\src\main\jniLibs\armeabi\libpostproc.so
libs\armeabi\libswresample.so => app\src\main\jniLibs\armeabi\libswresample.so
libs\armeabi\libswscale.so => app\src\main\jniLibs\armeabi\libswscale.so
libs\armeabi\libtbb.so => app\src\main\jniLibs\armeabi\libtbb.so
libs\javacpp.jar => app\libs\javacpp.jar
libs\javacv.jar => app\libs\javacv.jar
res\ => app\src\main\res\
src\ => app\src\main\java\
Next Steps:
You can now build the project. The Gradle project needs network
connectivity to download dependencies.
Bugs:
If for some reason your project does not build, and you determine that
it is due to a bug or limitation of the Eclipse to Gradle importer,
please file a bug at http://b.android.com with category
Component-Tools.
(This import summary is for your information only, and can be deleted
after import once you are satisfied with the results.)
Build.Gradle:
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.2"
defaultConfig.with {
applicationId = "com.gst_sdk_tutorials.tutorial_4"
minSdkVersion.apiLevel = 17
targetSdkVersion.apiLevel = 22
}
}
android.ndk {
moduleName = "tutorial-4"
cppFlags.addAll(["-I${file("src/main/jni/Common/native_app_glue")}".toString(),
"-I${file("src/main/jni/Common/cpufeatures")}".toString(),
"-I${file("src/main/jni/Common/ndk_helper")}".toString()])
ldLibs.addAll(["android", "EGL", "GLESv2", "dl", "log", "atomic"])
stl = "c++_static"
}
// jni is the default dir; config this if yours is in different directory
android.sources {
main {
jni {
source {
srcDirs 'src/main/jni'
}
}
}
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles.add(file('proguard-rules.txt'))
}
}
// Turn on hard float support in armeabi-v7a
android.abis {
create("armeabi-v7a") {
cppFlags.addAll(["-mhard-float", "-D_NDK_MATH_NO_SOFTFP=1", "-mfloat-abi=hard"])
ldLibs.add("m_hard")
ldFlags.add("-Wl,--no-warn-mismatch")
}
}
android.productFlavors {
create ("arm7") {
ndk.abiFilters.add("armeabi-v7a")
}
create ("arm8") {
ndk.abiFilters.add("arm64-v8a")
}
create ("x86-32") {
ndk.abiFilters.add("x86")
}
// for detailed abiFilter descriptions, refer to "Supported ABIs" #
// https://developer.android.com/ndk/guides/abis.html#sa
// build one including all productFlavors
create("fat")
}
}
dependencies {
compile 'com.android.support:support-v4:23.3.0'
compile files('libs/javacpp.jar')
compile files('libs/javacv.jar')
}
local.properties:
ndk.dir=C\:\\Users\\wiz\\Downloads\\android-ndk-r9d
sdk.dir=D\:\\sdk
.c file:(not complete due to character limit)
#include <string.h>
#include <jni.h>
#include <android/log.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include <gst/gst.h>
#include <gst/interfaces/xoverlay.h>
#include <gst/video/video.h>
#include <pthread.h>
GST_DEBUG_CATEGORY_STATIC (debug_category);
#define GST_CAT_DEFAULT debug_category
/*
* These macros provide a way to store the native pointer to CustomData, which might be 32 or 64 bits, into
* a jlong, which is always 64 bits, without warnings.
*/
#if GLIB_SIZEOF_VOID_P == 8
# define GET_CUSTOM_DATA(env, thiz, fieldID) (CustomData *)(*env)->GetLongField (env, thiz, fieldID)
# define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)data)
#else
# define GET_CUSTOM_DATA(env, thiz, fieldID) (CustomData *)(jint)(*env)->GetLongField (env, thiz, fieldID)
# define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(jint)data)
#endif
/* Do not allow seeks to be performed closer than this distance. It is visually useless, and will probably
* confuse some demuxers. */
#define SEEK_MIN_DELAY (500 * GST_MSECOND)
/* Structure to contain all our information, so we can pass it to callbacks */
typedef struct _CustomData {
jobject app; /* Application instance, used to call its methods. A global reference is kept. */
GstElement *pipeline; /* The running pipeline */
GMainContext *context; /* GLib context used to run the main loop */
GMainLoop *main_loop; /* GLib main loop */
gboolean initialized; /* To avoid informing the UI multiple times about the initialization */
ANativeWindow *native_window; /* The Android native window where video will be rendered */
GstState state; /* Current pipeline state */
GstState target_state; /* Desired pipeline state, to be set once buffering is complete */
gint64 duration; /* Cached clip duration */
gint64 desired_position; /* Position to seek to, once the pipeline is running */
GstClockTime last_seek_time; /* For seeking overflow prevention (throttling) */
gboolean is_live; /* Live streams do not use buffering */
} CustomData;
/* playbin2 flags */
typedef enum {
GST_PLAY_FLAG_TEXT = (1 << 2) /* We want subtitle output */
} GstPlayFlags;
/* These global variables cache values which are not changing during execution */
static pthread_t gst_app_thread;
static pthread_key_t current_jni_env;
static JavaVM *java_vm;
static jfieldID custom_data_field_id;
static jmethodID set_message_method_id;
static jmethodID set_current_position_method_id;
static jmethodID on_gstreamer_initialized_method_id;
static jmethodID on_media_size_changed_method_id;
/*
* Private methods
*/
/* Register this thread with the VM */
static JNIEnv *attach_current_thread (void) {
JNIEnv *env;
JavaVMAttachArgs args;
GST_DEBUG ("Attaching thread %p", g_thread_self ());
args.version = JNI_VERSION_1_4;
args.name = NULL;
args.group = NULL;
if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) {
GST_ERROR ("Failed to attach current thread");
return NULL;
}
return env;
}
/* Unregister this thread from the VM */
static void detach_current_thread (void *env) {
GST_DEBUG ("Detaching thread %p", g_thread_self ());
(*java_vm)->DetachCurrentThread (java_vm);
}
/* Retrieve the JNI environment for this thread */
static JNIEnv *get_jni_env (void) {
JNIEnv *env;
if ((env = pthread_getspecific (current_jni_env)) == NULL) {
env = attach_current_thread ();
pthread_setspecific (current_jni_env, env);
}
return env;
}
android.mk before import:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := tutorial-4
LOCAL_SRC_FILES := tutorial-4.c
LOCAL_SHARED_LIBRARIES := gstreamer_android
LOCAL_LDLIBS := -llog -landroid
include $(BUILD_SHARED_LIBRARY)
ifndef GSTREAMER_SDK_ROOT
ifndef GSTREAMER_SDK_ROOT_ANDROID
$(error GSTREAMER_SDK_ROOT_ANDROID is not defined!)
endif
GSTREAMER_SDK_ROOT := $(GSTREAMER_SDK_ROOT_ANDROID)
endif
GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_SDK_ROOT)/share/gst-android/ndk-build/
include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk
GSTREAMER_PLUGINS := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_PLAYBACK) $(GSTREAMER_PLUGINS_CODECS) $(GSTREAMER_PLUGINS_NET) $(GSTREAMER_PLUGINS_SYS) $(GSTREAMER_PLUGINS_NET_RESTRICTED)
GSTREAMER_EXTRA_DEPS := gstreamer-interfaces-0.10 gstreamer-video-0.10
include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer.mk
I suggest to move to AS but keep the NDK build "the traditional way". My main argument to defend this approach is that the experimental plugin is still a "moving target": the DSL changes all the time, and its limitations require workarounds that change with every release of the experimental plugin. The second reason is that 3rd party tools like Fabric will not work with the experimental plugin.
For the non-experimental plugin, you can use the following piece in build.gradle:
def ndkBuild = android.ndkDirectory
import org.apache.tools.ant.taskdefs.condition.Os
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
ndkBuild += '.cmd'
}
task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
commandLine '$ndkBuild', 'NDK_PROJECT_PATH="$jniSrc/..'
}
task cleanNative(type: Exec, description: 'Clean JNI object files') {
commandLine '$ndkBuild', 'clean', 'NDK_PROJECT_PATH="$jniSrc/..'
}
clean.dependsOn 'cleanNative'
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn buildNative
}
tasks.all {
task -> if (task.name.contains('compileDebugNdk') || task.name.contains('compileReleaseNdk')) task.enabled = false
}
in JNI folder:
//File foo.h
#ifndef FOO_H_
#define FOO_H_
class Foo {
public:
Foo();
void Funny();
};
#endif /* FOO_H_ */
//File foo.cpp
#include "foo.h"
cv::string bar[1] = {"FOO"};
Foo::Foo() {
}
void Foo::Funny() {
}
Then, when I call:
Foo foo;
foo.Funny();
ndk-build complains:
error: undefined reference to 'Foo::Foo()
error: undefined reference to 'Foo::Funny()
However, if I put the function implementation in the header file like this:
#ifndef FOO_H_
#define FOO_H_
class Foo {
public:
Foo();
void Funny();
};
Foo::Foo() {
}
void Foo::Funny() {
}
#endif /* FOO_H_ */
The compiler then happily compiles my code.
How could I separate function prototypes and their implementation in JNI?
UPDATE: Here's my Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCV_LIB_TYPE:=STATIC
OPENCV_INSTALL_MODULES:=on
include ../../sdk/native/jni/OpenCV.mk
LOCAL_SRC_FILES := native.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_LDLIBS += -llog -ldl
LOCAL_MODULE := native
include $(BUILD_SHARED_LIBRARY)
The undefined reference is outputted by the linker, not by the Compiler. This means there is no translation unit containing the functions you have used in your code. Telling by the Android.mk file I'd say foo.cpp is missing in your LOCAL_SRC_FILES Statement.