Android 源码下利用jni编译自己的项目(参考系统development/samples/SimpleJNI)

本文介绍如何在Android项目中使用JNI技术编译C/C++代码,并生成.so库文件。详细解析了Android.mk文件配置及JNI_OnLoad函数的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

               记于正文前:环境是ubuntu10.10,android 源码是2.0的,在第一次编译源码的时候遇到不少问题,第二次一次make通过。

               1)可能用到的文件或库全部安装(sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev);

               2)建议用jdk1.5编译android源码,1.6也是可以编译通过的,不过需要修改一个文件(这里以2.0为例,要修改文件/build/core/main.mk,将文件中的javac_version := $(shell javac -version 2>&1 | head -n 1 | grep '[ "]1\.5[\. "$$]') 全部改为javac_version := $(shell javac -version 2>&1 | head -n 1 | grep '[ "]1\.6[\. "$$]'),总共两处)


             Android 源码下利用jni编译自己的项目

              我的练习项目实现了一个简单的四则运算,项目的目录层次如下:

              AndroidManifest.xml  Android.mk  jni  res   src

                   资源文件简简单单,一个布局文件,稍后会有demo的下载地址

                    主要记录备忘的内容如下:

                     MainActivity.java

    public native int add(int x, int y);
    public native int substraction(int x, int y);
    public native float multiplication(int x, int y);
    public native float division(int x, int y);
    
    static{
    	System.loadLibrary("arithmetic");
    }

            生成lib的名称为libarithmetic.so.注意load的时候写"arithmetic"

         jni 目录下有两个文件,一个是Android.mk,一个是c++源文件long.cpp

         jni/Android.mk如下:


LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_MODULE:= libarithmetic

LOCAL_SRC_FILES:= \
  long.cpp

LOCAL_SHARED_LIBRARIES := \
	libutils

LOCAL_STATIC_LIBRARIES :=

LOCAL_C_INCLUDES +=	\
	$(JNI_H_INCLUDE)

LOCAL_CFLAGS +=

LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)

注释:

LOCAL_PATH(必须定义,而且要第一个定义),宏函数‘my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录);

include $( CLEAR_VARS),
CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的;

LOCAL_MODULE_TAGS :=user eng tests optional

user: 指该模块只在user版本下才编译

eng: 指该模块只在eng版本下才编译

tests: 指该模块只在tests版本下才编译

optional:指该模块在所有版本下都编译


LOCAL_MODULE(必须定义),标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。Note:编译系统会自动产生合适的前缀和后缀,例如:arithmetic编译成功后将生成libarithmetic.so库文件

LOCAL_SRC_FILES 变量必须包含将要编译打包进模块中源代码文件。不用在这里列出头文件和包含文件。

LOCAL_SHARED_LIBRARIES中加入所需要链接的动态库(*.so)的名称

  LOCAL_STATIC_LIBRARIES加入所需要链接的静态库(*.a)的名称

LOCAL_CFLAG可选的编译器选项,用法之一是定义宏,例如LOCAL_CFLAGS    := -Werror作用是编译警告也作为错误信息

LOCAL_PRELINK_MODULE:=false,不作prelink处理,默认是要prelink操作的,有可能造成地址空间冲突(这地方目前还不明白)              long.cpp源代码如下:

#define LOG_TAG "LongTest2 long.cpp"
#include <utils/Log.h>
#include <stdio.h>
#include "jni.h"

jint add(JNIEnv *env, jobject thiz, jint x, jint y){
	return x + y;
}

jint substraction(JNIEnv *env, jobject thiz, jint x, jint y){

	return x - y;
}

jfloat multiplication(JNIEnv *env, jobject thiz, jint x, jint y){

	return (float)x * (float)y;
}

jfloat division(JNIEnv *env, jobject thiz, jint x, jint y){
	return (float)x/(float)y;
}

static const char *classPathName = "com/inspur/test2/MainActivity";

static JNINativeMethod methods[]= {
	
	{"add", "(II)I", (void*)add},
	{"substraction", "(II)I", (void*)substraction},
	{"multiplication", "(II)F", (void*)multiplication},
	{"division", "(II)F", (void*)division},
};


typedef union{
	JNIEnv* env;
	void* venv;
}UnionJNIEnvToVoid;



static int registerNativeMethods(JNIEnv* env, const char* className,
	JNINativeMethod* gMethods, int numMethods){

	jclass clazz;
	clazz = env->FindClass(className);

	if (clazz == NULL)
		return JNI_FALSE;
	if (env->RegisterNatives(clazz, gMethods, numMethods)<0)
		return JNI_FALSE;
	return JNI_TRUE;

}


static int registerNatives(JNIEnv *env){

	if (!registerNativeMethods(env, classPathName,
		methods, sizeof(methods)/sizeof(methods[0])))
	{
		return JNI_FALSE;
	}

	return JNI_TRUE;

}



jint JNI_OnLoad(JavaVM* vm, void* reserved){

	UnionJNIEnvToVoid uenv;
	uenv.venv = NULL;
	jint result = -1;
	JNIEnv *env = NULL;

	if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK){
		goto bail;
	}
	
	env = uenv.env;

	env = uenv.env;

	if (registerNatives(env) != JNI_TRUE){

		goto bail;
	}

	result = JNI_VERSION_1_4;

bail:
	return result;
}
除了利用     编写native   JAVA类,通过javah生成.h文件,根据.h文件编写.c/cpp文件 方法外(名字像老太太的裹脚步,又臭又长,而且不灵活),Android还可以通过引用JNI_Onload方式实现。jint JNI_onLoad(JavaVM* vm, void* reverced),改方法在so文件被加载时调用。

JNI_OnLoad()有两个重要的作用:

  指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),如果要使用新版本的JNI,例如JNI 1.4版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_4(该常量定义在jni.h中) 来告知VM。

  初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_OnLoad()方法,因此在该方法中进行各种资源的初始化操作最为恰当。

  JNI_OnUnload()的作用与JNI_OnLoad()对应,当VM释放JNI组件时会呼叫它,因此在该方法中进行善后清理,资源释放的动作最为合适。

更多更详细内容请参考 使用RegisterNatives方法传递和使用Java自定义类 




项目根目录下Android.mk文件:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional 

LOCAL_SRC_FILES := $(call all-java-files-under, src)


LOCAL_JNI_SHARED_LIBRARIES := libarithmetic


LOCAL_PACKAGE_NAME := LongTest

LOCAL_SHARED_LIBRARIES := \
		libutils\
		liblog

include $(BUILD_PACKAGE)
include $(LOCAL_PATH)/jni/Android.mk 

# Also build all of the sub-targets under this one: the shared library.
include $(call all-makefiles-under,$(LOCAL_PATH))

LOCAL_PACKAGE_NAME:项目名称,即最终生成apk的名字

LOCAL_JNI_SHARED_LIBRARIES := libxxx就是把so文件放到apk文件里的libs/armeabi里

执行BUILD_PACKAGE。它的定义也是在config.mk中定义如下:BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk

$(call all-java-files-under, src)编译的源代码文件列表添加src目录下所有的java 源文件

$(call all-makefiles-under, $(LOCAL_PATH))编译器会在编译完当前目录下的文件后再深入子目录编译



如果make过android源码,可以在项目根目录下执行mm命令进行编译。前提是执行过source androidSRC/build/envsetup.sh

或者直接把source androidSRC/build/envsetup.sh添加到~/.bashrc中,会更加方便


示例代码下载

List of Sample Apps The list below provides a summary of the sample applications that are available with the Android SDK. Using the links on this page, you can view the source files of the sample applications in your browser. You can also download the source of these samples into your SDK, then modify and reuse it as you need. For more information, see Getting the Samples. API Demos A variety of small applications that demonstrate an extensive collection of framework topics. Backup and Restore A simple example that illustrates a few different ways for an application to implement support for the Android data backup and restore mechanism. Bluetooth Chat An application for two-way text messaging over Bluetooth. BusinessCard An application that demonstrates how to launch the built-in contact picker from within an activity. This sample also uses reflection to ensure that the correct version of the contacts API is used, depending on which API level the application is running under. Contact Manager An application that demonstrates how to query the system contacts provider using the ContactsContract API, as well as insert contacts into a specific account. Home A home screen replacement application. JetBoy A game that demonstrates the SONiVOX JET interactive music technology, with JetPlayer. Live Wallpaper An application that demonstrates how to create a live wallpaper and bundle it in an application that users can install on their devices. Lunar Lander A classic Lunar Lander game. Multiple Resolutions A sample application that shows how to use resource directory qualifiers to provide different resources for different screen configurations. Note Pad An application for saving notes. Similar (but not identical) to the Notepad tutorial. SampleSyncAdapter Demonstrates how an application can communicate with a cloud-based service and synchronize its data with data stored locally in a content provider. The sample uses two related parts of the Android framework — the account manager and the synchronization manager (through a sync adapter). Searchable Dictionary A sample application that demonstrates Android's search framework, including how to provide search suggestions for Quick Search Box. Snake An implementation of the classic game "Snake." Soft Keyboard An example of writing an input method for a software keyboard. Spinner A simple application that serves as an application-under-test for the SpinnerTest sample application. SpinnerTest An example test application that contains test cases run against the Spinner sample application. To learn more about the application and how to run it, please read the Activity Testing tutorial. TicTacToeLib An example of an Android library project that provides a game-play Activity to any dependent application project. For an example of how an application can use the code and resources in an Android library project, see the TicTacToeMain sample application. TicTacToeMain An example of an Android application that makes use of code and resources provided in an Android library project. Specifically, this application uses code and resources provided in the TicTacToeLib library project. Wiktionary An example of creating interactive widgets for display on the Android home screen. Wiktionary (Simplified) A simple Android home screen widgets example.
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值