您的位置:首页 > 移动开发 > Android开发

android JNI学习七

2014-03-08 10:29 169 查看
这次尝试做 android 系统 API 的接口,就是生成一个 framework 的 jar 包让 eclipse 导入,然后像普通接口一样 import 包名即可使用的接口。当然,程序要用这个接口运行起来,就需要专门运行这个 framework 的机器了。

我在网上下载一个 word 文档中如下写:

2在framework中的JNI

第一步:编写java类,其并不完整,有部分方法需要用到C++,先建立java,在回到底层的C++部分
在文件android-1.6_r2下:frameworks/base/core/java/下建立自己的Java类。
例如建立android/myTest/helloJNI.java,代码如下:
packageandroid.myTest;
publicclass helloJNI{
publichelloJNI(){
System.out.println("TesthelloJNI: "+getString());
}
publicnative String getString();
}
其中getString是用C++编写的部分。

第二步:编写自己的C++函数体:
frameworks/base/core/jni/android_myTest_helloJNI.cpp,注意文件名是java类的包名和类名的结合。代码如下:
#defineLOG_TAG "DebugJNI"
#include"jni.h"
#include"nativehelper/JNIHelp.h"
#include"utils/Log.h"
#include"utils/misc.h"
//#include"android_runtime/AndroidRuntime.h"
namespaceandroid {
/*
*Implements:
* native int part1(int intArg, double doubleArg, String stringArg,
* int[] arrayArg)
*/

//jstring是jni与java中string相对应,可以看出函数名的前面部分是包名和类名,最后面就是Java中定义的方法,
//参数:JNIEnv*env,
jobject object是必须的,如果有别的参数,在添加到后面
staticjstring android_myTest_helloJNI_getString(JNIEnv* env, jobjectobject)
{
LOGI("helloJNI\thelloJNI\thelloJNI");

returnenv->NewStringUTF("Hello JNI");
}

//参考下面就好,JNINativeMethod后面有详解
staticJNINativeMethod gMethods[] = {
/*name, signature, funcPtr */
{"getString", "()Ljava/lang/String;",
(void*)android_myTest_helloJNI_getString}
};

//注册
intregister_android_myTest_helloJNI(JNIEnv* env)
{
returnjniRegisterNativeMethods(env, "android/myTest/helloJNI",
gMethods,NELEM(gMethods));
}

#if0
/*trampoline into C++ */
extern"C"
intregister_android_debug_JNITest_C(JNIEnv* env)
{
returnandroid::register_android_debug_JNITest(env);
}
#endif

};// namespace android

此时并没有完,需要在当前目录下找到Android.mk,这是编译jni的文件,只有加进去才能编译自己建立的cpp文件:
LOCAL_SRC_FILES:=\下添加如下一行android_myTest_helloJNI.cpp\
在当前目录下找到AndroidRuntime.cpp下添加一些东西:
staticconst RegJNIRecgRegJNI[]数组下添加REG_JNI(register_android_myTest_helloJNI),
添加externint register_android_myTest_helloJNI
(JNIEnv* env);
进行注册。
在android-1.6_r2下执行make或者makeframework
在此时,我们建立的类就可以作为系统的API用了,例如:android.myTest.helloJNIhellojni=new………………

第三步:在外面有eclips建立一个helloJNITest工程,放在package/apps/目录下,
并直流系src目录和res目录,其余目录删掉,在该目录下建立Android.mk文件,如下:
LOCAL_PATH:=$(call my-dir)
include$(CLEAR_VARS)
LOCAL_MODULE_TAGS:= user
LOCAL_SRC_FILES:= $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME:= HelloJNITest
include$(BUILD_PACKAGE)
建立java文件类HelloJNITest:
packagecom.android.helloJNI;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.widget.TextView;
importandroid.myTest.helloJNI;
publicclass HelloJNITest extends Activity {
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
helloJNI hj=newhelloJNI();
String s=hj.getString();
TextViewtv=(TextView) this.findViewById(R.id.tv);
tv.setText(s);
android.util.Log.d("ddddd","-------------"+s);
}
}
本人也按照这个方法进行代码添加,但在编译 mmm frameworks/base/core/jni/ 时报错:
frameworks/base/core/jni/android_myTest_helloJNI.cpp: In function 'int android::register_android_debug_JNITest_C(JNIEnv*)':

frameworks/base/core/jni/android_myTest_helloJNI.cpp:22:12: error: 'register_android_debug_JNITest' is not a member of 'android'

make: *** [out/target/product/msm8625/obj/SHARED_LIBRARIES/libandroid_runtime_intermediates/android_myTest_helloJNI.o] Error 1

发现是android_myTest_helloJNI.cpp 文件里的

extern"C"
intregister_android_debug_JNITest_C(JNIEnv* env)
{
returnandroid::register_android_debug_JNITest(env);
}
这几段出问题,尝试把这几段注释掉,就可以编译通过了。搜索了一下,这段函数跟 /frameworks/base/core/jni/android_debug_JNITest.cpp 里的最后一段一样,而我的 android 版本里已经把这段代码注释掉了,所以我也把这段注释掉。
这时编译通过:

target Strip: libandroid_runtime (out/target/product/msm8625/obj/lib/libandroid_runtime.so)

Install: out/target/product/msm8625/system/lib/libqrdinside.so

Install: out/target/product/msm8625/system/lib/libandroid_runtime.so

把生成的两个 libqrdinside.so 和 libandroid_runtime.so  push 进机器 /system/lib/ 里面。

如果有时在执行编译指令 mmm frameworks/base/core/jni/ 时出错,没编译完,可改成执行强制编译 mmm frameworks/base/core/jni/ -B 这个后面加 -B 就是强制重新编译。

注意修改 AndroidRuntime.cpp 文件添加 extern int register_android_myTest_helloJNI(JNIEnv* env); 这段代码时,其实是在 namespace android {    这个花括号内,因为在这个上面还有一个 using namespace android;  是不带括号的,如果在不带括号的后面添加,是编译不通过的。至少我自己是这样。当时我的错误如下:

error: undefined reference to 'register_android_myTest_helloJNI(_JNIEnv*)'

collect2: ld returned 1 exit status

只有把 extern int register_android_myTest_helloJNI(JNIEnv* env);  放到 namespace android {  里面才编译通过。

再编译 framework :

Install: out/target/product/msm8625/system/framework/framework.jar

Install: out/target/product/msm8625/system/framework/ext.jar

Install: out/target/product/msm8625/system/framework/framework_ext.jar

生成三个文件都 push 到机器 system/framewoek/ 目录下。机器正常启动。

建立一个apk工程,在 onCreate 下 

helloJNI hj=new helloJNI();

String s = hj.getString();

然后用 log 把 s 打印出来,发现可以打印出 s = Hello JNI

因此证明实验成功。可以添加 framework 层的 api 了,而且可正常使用,不过程序一定要运行在相应 framework 的机器里。如果要跑虚拟机,可自行百度。

有些在网上说如果添加 api,需要执行 make update-api 来更新 api,但我尝试好像这种不需要,当然如果先执行一下这个更新 api 操作,也不是坏事。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android jni