今天开始写android的jni,其实这个部分应该昨天就开始的,但是昨天一天都纠结在环境的配置上面了,先讲一下昨天的内容吧,
昨天主要是配置环境:
我的系统:ubuntu12.04
android sdk 最新r20
android ndk 最新r8
eclipse juno mobile版本
jdk 1.7
昨天一开始的时候首先下载了myeclipse10.05,但是不知道是不是网络的原因(公司网络很卡)还是qiang的原因,一直都安装不了adt弄了半天都没有成功,只好放弃,删除后开始下载eclipsejuno版本。
原来下载的是classic版本,结果下载下来以后,在安装adt的步骤上面又卡住了,為什麼呢?原来现在下的adt版本是adt20,需要用到cdt(ndk用到)和swt(adt用到)这两个包,昨天又不知道什么原因,利用eclipse竟然下不下来,我尝试了很多个下载地址可都失败了,个人猜测是下载地址又把中国的ip给封了,谁知道呢????后来仔细的查找了eclipse的各个版本,发现里面有个版本是给mobile开发准备的http://www.eclipse.org/downloads/packages/eclipse-mobile-developers/junor
仔细看了里面的组件,发现里面两个包都有,然后下载,安装adt无错通过。这个是feature列表
org.eclipse.cdt | |
org.eclipse.egit | |
org.eclipse.egit.import | |
org.eclipse.epp.package.common.feature | |
org.eclipse.equinox.p2.user.ui | |
org.eclipse.help | |
org.eclipse.jdt | |
org.eclipse.mylyn.context_feature | |
org.eclipse.mylyn.ide_feature | |
org.eclipse.mylyn.java_feature | |
org.eclipse.mylyn_feature | |
org.eclipse.platform | |
org.eclipse.rcp | |
org.eclipse.wst.xml_ui.feature |
第一个和最后一个就是一开始提示出错的根源啊。
然后开始今天的步骤,
今天准备写jni动态库调用自己的静态库
步骤如下:
首先创建一个android工程,我的avd是16也就是android4.1
然后在MainActivity里面写入:
packagecom.syd.twolib;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;
import android.support.v4.app.NavUtils;
public class MainActivity extendsActivity {
static {
System.loadLibrary("JNITest");
}
privatenative String getReply();
@Override
public void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public booleanonCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
注意上面的加粗的语句,一个是我的包结构,一个是我添加的语句。
注意上面loadLibrary的名字实际上是JNITest。So这里需要将so除掉
接下来我按照网上的方法
进入工程路径
~/workspace/Twolib$javah -classpath bin -d jni com.syd.twolib.MainActivity
Error: Could not find class file for'com.syd.twolib.MainActivity'.
结果报了个不能找到类的错,
然后又试了
~/workspace/Twolib$ javah -classpathbin/classes -d jni com.syd.twolib.MainActivity
Error: cannot accessandroid.app.Activity
class file for android.app.Activitynot found
发现又报了一个新的错误,只好又从网上查找资料,然后找到一个方法:
:~/workspace/Twolib$ javah -classpath/opt/android-sdk-linux/platforms/android-16/android.jar:bin/classes-d jni com.syd.twolib.MainActivity
发现这句语句的要点了吗??不错 就是classpath中加入了一个android.jar包,这个包的路径是androidsdk目录的platforms下面,看你自己的工程版本喽,一般都选择android-8版本,
执行语句,成功通过,
接下来在jni文件夹中创建一个c文件:com_syd_twolib_MainActivity.c:
#include <jni.h>
#define LOG_TAG "JNITest"
#include <utils/Log.h>
jint JNI_OnLoad(JavaVM* vm, void*reserved)
{
void *venv;
LOGI("JNI_OnLoad!");
if ((*vm)->GetEnv(vm,(void**)&venv, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnvfailed");
return -1;
}
return JNI_VERSION_1_4;
}
/*
* Class: com_syd_twolib_MainActivity
* Method: getReply
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALLJava_com_syd_twolib_MainActivity_getReply(JNIEnv *, jobject)
{
LOGI("Hello world fromJNITest.so");
return(*env)->NewStrngUTF(env,"Hello World");
}
这里面要注意 JNI_OnLoad和JNI_OnUnLoad这两个函数分别在加载和释放so的时候被调用。
但是这里為什麼会没有JNI_OnUnLoad呢?具体的原因我也不知道
/home/yxt/workspace/Twolib/jni/com_syd_twolib_MainActivity.c:19:error: conflicting types for 'JNI_OnUnload'
/opt/android-ndk-linux/platforms/android-14/arch-arm/usr/include/jni.h:1130:note: previous declaration of 'JNI_OnUnload' was here
这里提示说JNI_OnUnLoad已经有了 ,那我就删掉了这个函数
但是在编译的时候又遇到另外一个问题error:utils/Log.h: No such file or directory
意思是utils/Log.h无法找到,所以只好把log的那几句先给注释掉,这里再需要注意的是:注意代码中loadlibrary里面的名字必须和android。mk文件里面的名字一模一样,就算生成的。so文件里面加了前缀lib也不用去管他,于是再编译,通过!
先说解决方法:
在JNI的c文件中如果用到了#include<utils/Log.h>
然后用NDK编译的时候会提示error:utils/Log.h: No such file ordirectory
如果想要他的LOG功能的话
1-----修改Android.mk文件配置,添加如下语句
LOCAL_LDLIBS+= -L$(SYSROOT)/usr/lib-llog
2-----在.c文件中修改为如下语句
#include<android/log.h>
3-----使用方法
#defineLOG_TAG "debug"
#define LOGI(fmt, args...)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
#defineLOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,fmt, ##args)
#define LOGE(fmt, args...)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt,##args)
4----打印语句
LOGI("testlog!!!!")
LOGI("the string is: %s\n",buff);
5----错误输出到日志
LOGI(strerror(errno))
转自:http://blog.csdn.net/dspeeding/article/details/6924745
原因要追溯到jni的两种编译环境之间的区别:ndk和源码环境编译。
关于测试时使用Log。调用JNI进行NativeCode的开发有两种环境,完整源码环境以及NDK。两种环境对应的Log输出方式也并不相同,差异则主要体现在需要包含的头文件中。如果是在完整源码编译环境下,只要include<utils/Log.h>头文件(位于Android-src/system/core/include/cutils),就可以使用对应的LOGI、LOGD等方法了,当然LOG_TAG,LOG_NDEBUG等宏值需要自定义。如果是在NDK环境下编译,则需要include<android/log.h>头文件(位于ndk/android-ndk-r4/platforms/android-8/arch-arm/usr/include/android/),另外自己定义宏映射,
来源:http://www.kunli.info/2011/08/21/android-native-code-study-note/