Android NDK JNI C++ <4> 文件结构分析和组织
这一篇文章主要熟悉NDK开发的jni文件目录结构分析和组织,当然开发一个小的小项目,当然不需要太注重文件结构结构和如何组织好文件结构.
开始分析:
<1> : 首先新建一个Android项目:SwigSimpleMk,由于这里不介绍Android的java程序,也不是将Android app如何调用jni,所以只给出最终文件结构和android主程序代码.
package com.example.swigsimplemk; import org.swig.simple.MathOperation; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.widget.Toast; public class MainActivity extends Activity { static{ System.loadLibrary("example"); } private MathOperation maths; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); maths=new MathOperation(1); Toast.makeText(this, "maths 1+2 = "+maths.Add(1, 2), Toast.LENGTH_SHORT).show(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
文件结构大致如下:

由于展开太多了,可能不是很完整,但是这个不是重点.因为我把头文件,源文件,swg脚本,提供基本信息的help全部单独分开了.
/header文件夹下的example.h:
#ifndef _EXAMPLE_DEMO_HEADER_H_ #define _EXAMPLE_DEMO_HEADER_H_ class mathe{ public: mathe(){ ; } virtual ~mathe(){ ; } virtual int Add(int,int)=0; virtual int Subl(int,int)=0; virtual double Dulp(double,double)=0; virtual double Cdux(double,double)=0; }; class MathOperation : public mathe{ public : MathOperation(int x){ ; } virtual int Add(int,int); virtual int Subl(int,int); virtual double Dulp(double,double); virtual double Cdux(double,double); }; #endif
/src文件夹下的example.cpp:这个文件有两个地方有,一个是在这里,一个直接放在jni文件夹下,不过内容是一样的,只是做个测试而已.
#include"../header/example.h" /* MathOperation::MathOperation() { cout << "MathOperation Init..." << endl; } MathOperation::~MathOperation() { cout << "MathOperation Release..." << endl; } */ int MathOperation::Add(int x, int y) { return x + y; } int MathOperation::Subl(int x, int y) { return x > y ? (x - y) : (y - x); } double MathOperation::Dulp(double x, double y) { return x * y; } double MathOperation::Cdux(double x, double y) { return y == 0 ? 0 : (x / y); }
/swig文件夹下的example.i
%module example %{ #include "header/example.h" %} %include "../header/example.h"
第一个include将会直接加载到等下生成的example_wrap.cpp文件中,所以这个地方路径一定要正确,由于等下example_wrap.cpp路径是设置在jni文件夹下,所以example.h相对jni的目录应该是header/example.h才是正确的.
/help文件夹下的help.txt文件是运行example.i的命令行:
swig -c++ -java -package org.swig.simple -outdir ../../src/org/swig/simple -o ../example_wrap.cpp example.i
<3> : 准备上面的,现在主要介绍Android.mk的文件写法和路径:
如果要在jni文件夹下添加一个Android.mk,并且不打算在其他地方设置子目录下新建Android.mk,那么需要这样写:
# LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := example LOCAL_SRC_FILES := example_wrap.cpp src/example.cpp LOCAL_CFLAGS :=-frtti $(warning $(LOCAL_PATH)) #include $(BUILD_SHARED_LIBRARY)
这里面要注意LOCAL_SRC_FILES := 后面的example.cpp文件路径设置法,这个路径是相对jni下的路径,准确的说是相对当前Android.mk文件的路径,而src是jni下文件夹,而Android.mk和jni文件是同级的,所以写法就是 : src/example.cpp.
这里面还需要注意一个地方,Android.mk也是可以打印调试信息:
语法:
$(warning $(~))或者$(error $(~))
这个里面打印LOCAL_PATH路径信息,实际就是jni的路径.
<4> : 这里面不在介绍shell脚本了,虽然我写了执行上面的,就可以生成了.so文件了.
<5> : 但是一个项目往往很大,分了很多一个子目录,那么都写在一个Android.mk,那将会多么的庞大,简直就是坑爹的难维护,所以经常会各个src下都会新建一个Android.mk
比如,我就在上面项目的src文件夹下新建一个Android.mk,但是jni下的还需要吗?需要,jni的Android.mk作为总入口,运行还是从Android.mk开始,然后通过这个总入口一次进入子目录下的各个Android.mk.
我这里总入口Android.mk :
# LOCAL_PATH := $(call my-dir) #LOCAL_PATH := $(call all-subdir-makefile) include $(CLEAR_VARS) #LOCAL_MODULE := example #LOCAL_SRC_FILES := example_wrap.cpp src/example.cpp #LOCAL_CFLAGS :=-frtti $(warning $(LOCAL_PATH)) #include $(BUILD_SHARED_LIBRARY) include $(call all-makefiles-under,$(LOCAL_PATH))
上面的内容要用#注释掉,不要和子目录下的Android.mk功能重复.
然后再src文件夹下新建一个Android.mk:
# LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := example LOCAL_SRC_FILES := ../example_wrap.cpp ../example.cpp #LOCAL_SRC_FILES := example.cpp LOCAL_CFLAGS :=-frtti $(warning $(LOCAL_PATH)) include $(BUILD_SHARED_LIBRARY)
<6> : 然后在jni中同样输入ndk-build,得到同样的效果.
今天晚上太晚了,其他的明天再看看....

浙公网安备 33010602011771号