I compiled this library using NDK into an .so. I can successfully load it with System.LoadLibary() but when I try the example code for the library, it throws an UnsatisfiedLinkError. I checked the source code for the library and it indeed has the functions I'm using with the same parameters (except JNIEnv and jobject) along with the same returns. Plus, surely the creator of the library would share working example code. So what am I doing wrong? I copied the exact code from the page, and changed the variable names accordingly.
Without more detail it's difficult to say. Having looked at the library on that site, it's possible that you've named your class differently. You need to call your Java class Giffle and it has to be in the package org.jiggawatt.giffle. This isn't a naming convention that you would stumble upon by accident ;-)
package org.jiggawatt.giffle;
public class Giffle {
static {
System.loadLibrary("gifflen");
}
public native int Init(String gifName, int w, int h,
int numColors, int quality,
int frameDelay);
public native void Close();
public native int AddFrame(int[] inArray);
}
To use it, you would either make the calls in the Giffle class, or probably a cleaner way is to use an instance:
Giffle giffle = new Giffle();
giffle.Init(...);
giffle.AddFrame(...);
giffle.Close();
Does seem a bit odd that the Java part wasn't in the zip, especially as the class name is hardcoded into the C symbol. Maybe the guy who wrote it had a whole bunch of extra code in the Java part that he didn't want anyone to see.
As far as I can tell, the C and C++ code is complete. You shouldn't need to modify it at all. The implementations of the native methods are in gifflen.cpp, and have names like Java_org_jiggawatt_giffle_Giffle_Init. They have the correct native-side arguments for the JNI calling convention.
How are you building this? I found that I had to do Project->Clean… in Eclipse every time after running ndk-build to let Eclipse pick up the .so file and copy it to the apk.
Try this method. http://mpigulski.blogspot.com/2010/09/debugging-dlopen-unsatisfiedlinkerror.html it helps me.
Related
I have a library which I use in several projects.
In this library I have a function like:
public boolean update(Context context, String name,
UpdateResponseCallback callback)
throws firstException {
Now I want to change this firstException to secondException (or to the general Exception or whatever). The build of the library works okay. And also the generated files appears to be okay.
When I move to the App which includes this library things go wrong.
The compiler does not recognise the new/updated format. Also the quick help (mouse over) give the old interface.
I have already performed CLEAN and also File:InvalideChache but nothing helps.
I've successfully written a go mobile library and used it from an Android Java app.
I've also successfully called a c function from JNI. This one has the JNIEnv pointer.
I'd like to pass the context/JNIEnv from Java to Go.
Here's where it seems to get complicated:
Go Mobile does not seem to use JNIEnv at all.
LoadJNI.java does have a context object and claims to pass it to the Go side. But there it isn't visible.
I've been able to include jni.h using the "C" directive
I can transfer the JNIEnv from JNI/C or store it there as a global variable but that's an ugly kludge.
https://github.com/golang/go/issues/16876 talks about a proposal to do reverse binding but it's unclear what the status is.
https://godoc.org/golang.org/x/mobile/cmd/gobind also talks about it but the following code snippet
import "Java/java/lang/System"
t := System.CurrentTimeMillis()
returns
cannot find package "Java/java/lang/System" in any of:
/usr/local/go/src/Java/java/lang/System (from $GOROOT)
/Users/----/go/src/Java/java/lang/System (from $GOPATH)
In C I solved it with a compiler directive: #cgo CFLAGS: -I...
But I'm not sure how to do it for Java
In short, I'm now stuck and would appreciate help. Ideally, I'd just like to pass the object as a parameter, if possible. However, I'd settle for any reverse binding to call Java from Go.
I hate to answer my own question, but I'd hate someone to go through this as well too. I'll update this answer as I go along.
Basic Setup
Edit build.gradle and add GOPATH and GO to gobind (additions in bold):
gobind {
pkg = ".../reverse/reverse"
GOPATH = "/Users/johndoe/go"
GO = "/usr/local/go/bin"
}
How to develop
Start from the reverse example. Get it to compile and run.
Make one modification and recompile.
Missing gobind
It turns out the installation process neglected to build gobind. Run go install golang.org/x/mobile/cmd/gobind
I'm Stuck
Trying to modify the reverse project to do anything other than what it's already doing is failing. Even stuff like passing an object and calling toString will fail.
More to come...
i am making an Android Shapefile reader app on Android with the use of NDK. I want to use C++ to parse shape files. I found library "Shapefile C Library". Github: https://github.com/sw897/shapelib.
I am using Android studio and have no idea how to import it to my Android project so i could use functions described in: http://shapelib.maptools.org/shp_api.html
Any tips?
First, start hacking away at the Hello-JNI example from Google:
https://github.com/googlesamples/android-ndk/tree/master/hello-jni
Use that as a test bed.
Then, create a Java Class with public native methods that let you interact with your library. Something of a high level API, probably to pass a file name or buffer to SHPOpenLL and return a pointer to the ShapeFile context (ShapeHandle). Looks like your library is written in C, so you should be able to write a similar interface to query the shapefile passing a (jint) c-style cast of your ShapeHandle pointer.
Next, you need to play around with javah to generate the header for your shapefile interface. Once the header is generated, you can use it to implement your interface in a .cc file. From there you will basically make Java calls to your C interface and it will return jobjects. (jint, jbool, jstring, etc...)
I'm looking at the ShapeLib that you want to use and while it's easy enough, there will be some gotchas.
You will need to implement SAHooks for file I/O. I suggest looking at NVFile for an example how to access APK files (or downloaded files). You will need to init it using activity.context.assetmanager. Then use nv_file to wrap FRead/FSeek/etc...
Passing info back to java is going to be tough. Personally, I would build a Java class to hold the shape information and fill it out on the C side. However, you might be tempted to query these parameters from the SHPObject one at a time. Will be slow, but less error prone.
E.g.
// Java
MyJavaShapeObject obj = new MyJavaShapeObject();
_c_retrieveShapeObj((jint)pShapeFile, obj);
// C
java_blah_blah_c_retrieveShapeObj(JNIEnv* env, jclass activity, jint theShapeFile, jobject theObj){
ShapeHandle pShapeFileHandle = (ShapeHandle)theShapeFile; // c style conversion
// http://stackoverflow.com/questions/11647646/how-to-use-the-jni-to-change-the-fields-of-a-java-class
// http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp16613
// http://stackoverflow.com/a/36759159/7949696
}
I have a functionality to achieve, which is a difficult one. But someone else already achieved it in their app. So i decompiled the apk file to find out what he did.
And i found that he has lib like libs/armabi/XXXX.so
Then in the code, he is loading the the lib like this
static
{
System.loadLibrary("XXXX");
}
Then he call the native method like
public native int addTwoNumbes(int a, int b);
So i copied the lib to my libs/armabi/XXX.so
When i call , System.loadLibrary(XXXX) , no error was thown.
But when i call the addTwoNumbers method, it gives me UnsatisfiedLinkError.
Can anyone point me in the right direction , if its not a huge problem for you a quick fix code really helps me as im in kinda hurry (as everyone :) )
the java class name should be exactly the same name, same package as frim where you took the code, for more details read about jni
I'm just messing around with a Ndk tutorial I found. The native code uses one "package", while the activity is in another. When this mismatch occurs, I can't call the native function without getting an unsatisfied link exception. I know the "why's" I just don't know the resolution.
Here is the sample .c code that I've placed in my jni folder:
#include <string.h>
#include <jni.h>
jstring Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
return (*env)->NewStringUTF(env, "Hello from native code!");
}
Notice that this .c code's package translates to com.mindtherobot.samples.ndkfoo.NdkFooActivity.
If I create a new activity that matches that Package/Class, I can call the invokeNativeFunction just fine. However, what if I can't match it? What if instead I need to run it from com.mydomain.activity?
I figured I could maybe change things around, such that my native declaration looked like this:
package com.mydomain;
public class Activity {
private native String com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction();
}
But that's a no-go. Just to be clear, I know how to make this work if I change my package to match what is compiled in the .c code; however, I need to be able to call a method from a different package... is this possible?
You need to make a basic class with the sole functionality of talking to C, not an activity. Then activities can instantiate this class, or possibly even statically call it, whenever they need to talk to C.
Your question is pretty scrambled, but the package declaration in the Java source code has to agree with what is encoded into the native method name, i.e. it must agree with what is generated by javah. If you change the package in the Java code, you must regenerate the .h file, and adjust the .c file to suit. There is no other way to fudge around this.