android JNI学习七

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

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

2framework中的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)

*/


//jstringjnijavastring相对应,可以看出函数名的前面部分是包名和类名,最后面就是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 操作,也不是坏事。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值