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
Related
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)
I have created a cc_library in my bazel Build file and added the deps in android_binary rule
Bazel BUILD:
cc_library(
name = "native_libs",
srcs = glob([
"app/src/main/jni/**/*.cc",
"app/src/main/jni/**/*.h",
]),
)
android_binary(
name = "buildlib",
srcs = glob([
"app/src/main/java/**/*.java",
]),
manifest = "app/src/main/AndroidManifest.xml",
deps = ":native_libs",
)
And loaded the library in the specified package as
static{
System.loadLibrary("buildlib");}
And declares and calls the native function as :
Declaration:
private static native String foo(String code);
Function Call
foo("Code");
JNI FILE FUNCTION DECLARATION AND DEFINITION:
JNIEXPORT jstring JNICALL
Java_com_example_android_(foo)( JNIEnv* env, jobject thiz, jstring code );
JNIEXPORT jstring JNICALL
Java_com_example_android_(foo)( JNIEnv* env, jobject thiz, jstring code )
{
//some code
return code;
}
The library gets loaded successfully but while function call throws an error of java.lang.UnsatisfiedLinkError
How can i called the native foo() from my java file?
I have an Android app needs to reference and use some native C++ code. I'm an experienced Java dev, but my C++ is lacking. I'm struggling to get it to run. I'm getting the error below. If I change the name inside of loadLibrary, it crashes immediately, so I'm assuming that the load works fine. How do I fix this?
No implementation found for boolean com.example.myapplication.BamBridge.test() (tried Java_com_example_myapplication_BamBridge_test and Java_com_example_myapplication_BamBridge_test__)
public class BamBridge implements IBamBridge {
static {
System.loadLibrary("native-lib");
}
private native boolean test();
}
BAM.h:
#ifndef BAM_H
#define BAM_H
#define JNIIMPORT
#define JNIEXPORT __attribute__ ((visibility ("default")))
#define JNICALL
#include <set>
#include <vector>
#include <string>
extern "C" JNIEXPORT JNICALL bool test();
#endif
BAM.cpp
#include <cstdio>
#include <stdint.h>
#include <iostream>
#include <map>
#include "BAM.h"
#define SWAP_UINT16(val) ((val << 8) | (val >> 8))
JNIEXPORT JNICALL bool test()
{
return true;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.6.0)
add_library( # Specifies 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/BAM.cpp )
On the C side change your function name to
Java_com_example_myapplication_BamBridge_test
As java searches for the function in the specific format.
In your Header file:
extern "C"
{
JNIEXPORT jboolean JNICALL Java_com_example_myapplication_BamBridge_test(JNIEnv *, jobject);
}
In your CPP file:
extern "C"
{
jboolean Java_com_example_myapplication_BamBridge_test(JNIEnv * env, jobject this)
{
return true;
}
}
I am doing development in Android using C/C++. I have a C++ function, that needs to be called from a C file. Here is what I am doing right now, but I get the error
undefined reference to __check_expiry
The C++ function is defined in "a.h" and implemented in "a.cpp". I am including "a.h" in"b.c" file and calling the method "__check_expiry" from "b.c" file.
a.h :
#ifdef __cplusplus
extern "C" {
#endif
static int __check_expiry(void);
#ifdef __cplusplus
}
#endif
a.cpp:
extern "C" {
static int __check_expiry() {
vz::lock_guard<std::mutex> guard(mutex_check, lock_hooker_check);
JNIEnv *env = NULL;
static bool __is_attached_1 = false;
if ((env = __getEnv(&__is_attached_1)) == NULL) {
//log_info("getEnv fail\r\n");
}
assert(!__is_attached_1);
int obj = env->CallStaticIntMethod((jclass) g_class, g_methodID);
log_info("Returned value from JAVA %d", obj);
__releaseEnv(__is_attached_1);
guard.~lock_guard();
return obj;
}
}
b.c:
#ifdef __cplusplus
extern "C" {
#endif
#include "a.h"
#ifdef __cplusplus
}
#endif
static int tunnel_to()
{
int value = __check_expiry();
}
Static functions are not exported. Remove the static qualifier.
(Unrelated: as long as you #include "a.h" from a.cpp, you don't need the extern "C" in your source file.)
I have already tried NDK simple examples such as displaying data from a native code to android's java code such as this:
#include <jni.h>
extern "C" {
JNIEXPORT jstring JNICALL
Java_com_example_JNIActivity_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return env->NewStringUTF("I'm C++! What the hell am I doing here in android?!");
}
}
However, I want an application wherein user will have to enter data from a textfield and have this data be pass from it's java code to the native code where calculations will be done. How will I do this?
In your Java native method, include a formal String argument that accepts the textfield value.
In C/C++, access the characters from the jstring with JNI methods like these:
jsize GetStringLength(JNIEnv *env, jstring string);
const jchar * GetStringChars(JNIEnv *env, jstring string, jboolean *isCopy);
const char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy);
When you're done with the characters, be sure to release them.
void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);
void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf);
See the documentation for these methods in the Java Native Interface Specification.