依旧是Android,NDK,JNI相关的问题。
照着ndk帮助的说明,运行<ndk>/samples目录下的hello-jni工程后,你一定想知道如何在自己的项目里调用别人已经编译好的.so库文件。于是新建一个Android工程,将hello-jni例子中ndk-build后的结果:libs文件夹(包括其下所有内容)拷贝到新建工程的根目录下,仿照hello-jni的代码,调用native方法:
1: package com.my.SoTest;
2:
3: import android.app.Activity;
4: import android.os.Bundle;
5: import android.widget.TextView;
6:
7: public class SoTestActivity extends Activity {
8: /** Called when the activity is first created. */
9: @Override
10: public void onCreate(Bundle savedInstanceState) {
11: super.onCreate(savedInstanceState);
12:
13: TextView tv=new TextView(this);
14: tv.setText(stringFromJNI());
15: setContentView(tv);
16: }
17: public native String stringFromJNI();
18: static {
19: System.loadLibrary("hello-jni");
20: }
21: }
运行后,logcat记录以下错误:
No implementation found for native Lcom/my/SoTest/SoTestActivity;.stringFromJNI ()Ljava/lang/String;
…
java.lang.UnsatisfiedLinkError: stringFromJNI
在hello-jni的代码注释里明确说明,UnsatisfiedLinkError错误是由于native代码中没有该方法的实现而引起的,但stringFromJNI这个方法,在c代码中是有的;前一个错误就比较明确了,是在Lcom/my/SoTest/SoTestActivity中去找这个方法实现的,打开hello-jni.c文件看看该函数头,其中有这样的字样:Java_com_example_hellojni_HelloJni_stringFromJNI,而com.example.hellojni恰好是例子工程的package name,HelloJni则是class的名称。也就是说,我们.so中函数声明涉及到的package name和class name与调用它的package name和class name不符。google一下印证了这个猜测,但提供现成解决办法的不多,总不能自己工程的package name必须和.so里的一样吧。
搜索看到了一篇NDK的教程,Using NDK to Call C code from Android Apps(需翻墙),里面写明了在一个普通Android工程中,如何从零开始组装自己的native代码。大致的步骤是,首先写一个java类,里面声明一些需要实现native方法(函数签名即可),然后用javah命令来生成对应的header文件,里面的内容是自动生成的native函数声明,然后照着这个声明实现各个函数,最后编译,用最初的java类调用。
受此启发,我们在拿到别人已经编译好的.so文件后,可首先新建一个java类,所在package的名称和class名称都与.so文件中函数签名提示的一致,在这个类中加入native方法的声明。这样在别处就可以用这个wrapper调用so库中的函数了。
我从新浪微博3.0.5beta1版本中反编译出libutility.so,然后根据里面的函数定义,使用相同的包名和类名,本地未安装NDK环境,为什么还是不能调用里面的方法?一调用getDecryptionString方法应用程序就会强制退出,求解。