How to use native string in Retrofit header? - android

I'm a newbie in the NDK world. I have a key placed in the C/C++ layer and I want to use it when I do a GET with Retrofit.
Here is my code
I have 2 .mk files but they are not relevant to my question and I have a keys.c file where I store the key:
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_hello_world_PlacesListActivity_getNativeKey(JNIEnv *env, jobject instance) {
return (*env)-> NewStringUTF(env, "my_key");
}
I'm able to read the key with this code in my PlacesListActivity:
static {
System.loadLibrary("keys");
}
public static native String getNativeKey();
and now I want to use the native String in the auth header of a GET request in a interface:
public interface TestService {
#Headers({
"client_id:" + PlacesListActivity.getNativeKey()
})
#GET("/some_end_point/")
}
The issue I'm getting is this:
Any ideas on how to fix this? Thank you in advance.

Have you tried implementing the interface and calling the C++ function from there. Interfaces are usually used to declare the function but not actually implement the function.

Ended up modifying the way I pass the auth header
#GET("/some_end_point/")
Observable<PlaceLocations> getPlaces(#Header("client_id") String authKey,#Path("name") String name);

Related

How to wrap List<int[]> with C++Builder 11?

I'm struggling to access the data returned by camera_parameters->getSupportedPreviewFpsRange() with C++Builder 11.
The getSupportedPreviewFpsRange() function is described here: https://developer.android.com/reference/android/hardware/Camera.Parameters#getSupportedPreviewFpsRange()
I don't have any issue with wrapping data which is not an array returned by other functions, but I could not find a way to wrap the List<int[]> data type.
The Delphi way to handle this seems to be:
camera_parameters: JCamera_Parameters;
pointer: Pointer;
jobject: JObject;
list_fps_ranges: JList;
currentFpsRange, suitableFPSRange: TJavaArray<Integer>;
...
list_fps_ranges := camera_parameters.getSupportedPreviewFpsRange();
jobject := list_fps_ranges.get(I);
pointer := (jobject as ILocalObject).GetObjectID;
fpsRange := TJavaArray<Integer> (WrapJNIArray(pointer, TypeInfo(TJavaArray<Integer>)));
Unfortunately, I could not find a way to properly translate:
fpsRange := TJavaArray<Integer> (WrapJNIArray(pointer, TypeInfo(TJavaArray<Integer>)));
into C++.
I tried with:
TJavaObjectArray__1<_di_JInteger>
without any luck, as there is no WrapJNIArray() function.
How could it be done?
Unfortunately, I could not find a way to properly translate:
fpsRange := TJavaArray<Integer> (WrapJNIArray(pointer, TypeInfo(TJavaArray<Integer>)));
into C++.
Try something like this:
_di_JCamera_Parameters camera_parameters;
TJavaArray__1<int> *currentFpsRange;
TJavaArray__1<int> *suitableFPSRange;
...
_di_JList list_fps_ranges = camera_parameters->getSupportedPreviewFpsRange();
_di_JObject jobject = list_fps_ranges->get(I);
void *objID = ((_di_ILocalObject)jobject)->GetObjectID();
// alternatively:
//
// #include <Androidapi.Helpers.hpp>
// void *objID = TAndroidHelper::JObjectToID(jobject);
TJavaArray__1<int> *fpsRange = (TJavaArray__1<int>*) WrapJNIArray(objID, __typeinfo(TJavaArray__1<int>));
I tried with:
TJavaObjectArray__1<_di_JInteger>
without any luck, as there is no WrapJNIArray() function.
First, TJavaArray<Integer> translates to TJavaArray__1<int>, not to TJavaObjectArray__1<_di_JInteger>.
Second, WrapJNIArray() is a helper function declared in <Androidapi.JNIBridge.hpp>.
The List<int[] list_fps_ranges example you posted works fine but I'm still confused about how to use WrapJNIArray properly in the case of a simple List<Integer>
I tried to replicate your solution with the getZoomRatios() function which is also part of Camera.Parameters
The getZoomRatios() function returns a List<Integer>
int n_zoomratios;
void *pointer;
_di_JList list_zoomratios;
list_zoomratios= jcamera_parameters->getZoomRatios(); // return List<Integer>
_di_JObject jobject= list_zoomratios; //fishy...
pointer= TAndroidHelper::JObjectToID(jobject);
TJavaArray__1<int> *zoomratios = (TJavaArray__1<int>*) WrapJNIArray(pointer, __typeinfo(TJavaArray__1<int>));
Unfortunately I can not figure which parameters of list_zoomratio should be used by jobject.
In the fps ranges example, the list_preview_fps->get() function returns a JObject which is attributed to jobject but in the case of the list_zoomratios there is no obvious JObject parameter I could use. I tried many different ways but without any success.
What is the proper way to wrap the integer array?
By the way, is there a book/document which describes these wrapping mechanisms? I could not find any information online on this subject.
Thank you for your help
Problem solved this way:
int n_zoomratios;
int i;
void *pointer;
_di_JList list_zoomratios;
_di_JInteger zoomratio;
list_zoomratios= jcamera_parameters->getZoomRatios(); // List<Integer>
n_zoomratios=list_zoomratios->size();
for(i=0;i<n_zoomratios;i++)
{
_di_JObject jobject=list_zoomratios->get(i);
pointer= TAndroidHelper::JObjectToID(jobject);
zoomratio = TJInteger::Wrap(pointer);
sprintf(txt,"%d %d",i,zoomratio->intValue());
log(txt);
}
However I can not figure why I can not convert a full array with WrapJNIArray and I have to convert each element one by one instead.

How to convert const char* to KString in Kotlin/Native?

In a C++ file, I want to convert a const char* to KString, so that I can then pass the KString to a Kotlin file using Kotlin/Native.
I believe the answer lies in the function
OBJ_GETTER(utf8ToUtf16, const char* rawString, size_t rawStringLength)
that I found in KString.cpp. But even though I discovered the used define statements in Memory.h, I have not yet managed to properly call the function utf8ToUtf16 from my own C++ file to get a KString. Any help is appreciated.
It depends on how you want to interact with Kotlin code. If you produce dynamic library with -produce dynamic, then string are converted automatically, see for example https://github.com/JetBrains/kotlin-native/blob/adf8614889e8cf5038a79960aa9651ca7d45e409/samples/python_extension/src/main/c/kotlin_bridge.c#L72.
So no additional magic is required at all. Same with Objective-C strings and -produce framework. And for other cases, there shall be no need to pass strings C -> Kotlin (callbacks produced with staticCFunction also do autoconversion).
I ended up taking the pieces to write my own function:
KString getKString(const char* rawString) {
size_t rawStringLength = strlen(rawString);
ObjHeader** OBJ_RESULT;
uint32_t charCount = utf8::unchecked::distance(rawString, rawString + rawStringLength);
ArrayHeader* result = AllocArrayInstance(theStringTypeInfo, charCount, OBJ_RESULT)->array();
KChar* rawResult = CharArrayAddressOfElementAt(result, 0);
auto convertResult =
utf8::unchecked::utf8to16(rawString, rawString + rawStringLength, rawResult);
ObjHeader* obj = result->obj();
UpdateReturnRef(OBJ_RESULT, obj);
return (const ArrayHeader*)obj;
}
In my test code (C++), I use it like this:
...
RuntimeState* state = InitRuntime();
KString inMessage;
{
ObjHolder args;
inMessage = getKString("Hello from C++");
}
...
DeinitRuntime(state);
and include Memory.h, Natives.h, Runtime.h, KString.h, utf8.h, stdlib.h, and string. You may be able to get rid of some of these.
As a side remark, you may realize how AllocArrayInstance is used in the function. It would be nice, if one simply could do the same thing for getting a KString, something like:
ObjHeader** OBJ_RESULT;
KString kstr = utf8ToUtf16(rawString, rawStringLength, OBJ_RESULT);
This did not work from my function, since utf8ToUtf16 was not found. I believe the reason is, that (at the time of writing) the respective function in KString.cpp is inside a namespace {...} block, such that it cannot be used from another file. That's why I ended up mimicking the function as shown above.

Android JNI: pass std::string to Java and back to C++

I have a relative large size std::string. And I want to pass it to Java without copying. And then pass back to another JNI lib. What is the best approach?
jlong some_jni_call() {
string str = createLargeString(); // say this is from 3rd lib only returns string
string* strInHeap = new string(str); // this should just increase the reference count?
jlong handle = (long)strInHeap;
return handle;
}
Then I can pass back to JNI:
void use_string(jlong handle) {
string* str = (string*)handle;
// use the str...
delete str; // doesn't look so nice, since people can forget to delete
}
Is this a good approach?
This is surely a feasible approach; you can even use similar trick to pass function pointers back and forth.

Calling simple java static method via JNI does not work, though c++ compiles and run it

Considering this Java class with the static method:
public class TestClass{
public string str;
public TestClass() {
str = "Test From Java";
}
public static String staticMethod() {
return "Test From Java";
}
}
I have written these lines of code in c++ file:
QAndroidJniObject str = QAndroidJniObject::callStaticObjectMethod(
"org/.../TestClass"
,"staticMethod"
,"(V)Ljava/lang/String;");
It seems everything is working but I don't know how can I use the str Object. I tried to convert it to a QString object using str.tostring() method but it always returns an empty string.
Why it does not work as expected? I've also tested ()Ljava/lang/String; for method signature but no success!
Thanks in advance.
You should specify the returned JNI type in <...> when calling the method :
QAndroidJniObject str = QAndroidJniObject::callStaticObjectMethod<jstring>(
"org/.../TestClass"
,"staticMethod");
QString string = str.toString();
Here there is no need to define the signature since your function has no argument.

Qt Android Extras Call Class

Say I have a Java class,
public static String helloWorld() {
return "hello world!";
}
How, in Qt, do I get what this function returned? The example for notifications has the following:
QAndroidJniObject javaNotification = QAndroidJniObject::fromString(m_notification);
QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/notification/NotificationClient",
"notify",
"(Ljava/lang/String;)V",
javaNotification.object<jstring>());
Should by method descriptor be ()Ljava/lang/String;? What should be in the chevrons after callStaticMethod?
Edit. Fixed and I don't know how. I didn't have the chevrons, and the descriptor was correct.
QAndroidJniObject string = QAndroidJniObject::callStaticObjectMethod<jstring>("com/your/project/YourClass", "helloWorld");
Is equivalent to:
QAndroidJniObject string = QAndroidJniObject::callStaticObjectMethod("com/your/project/YourClass", "helloWorld", "()Ljava/lang/String;");
For trivial signatures, that is, signatures that takes no arguments and returns one of the know jni types, you can write the short version by supplying the template type.

Categories

Resources