02_JNI-Eclipse上的开发环境

开发步骤

  • 确认eclipse安装了CDT , eclipse中查看:Hlep--->Install New Software ---> 点击右下角already installed --->Plug-ins ---> 查看CDT是否安装* 新建Android项目* 在MainActivity.java文件中声明本地方法
public native String  helloFromC();

  • 在项目根目录下新建jni的Folder
  • 在jni目录下新建hello.c
  • 在hello.c文件写与java文件中对应的native方法的函数,c中本地函数命名规则:Java_包名(.需要换成_)类名本地方法名函数中有两个参数:
    1,jobject obj:调用本地函数的Java对象,在本例中就是MainActivity实例
    2,JNIEnv* env:是结构体JNINativeInterface 的二级指针,JNIEnv是结构体 JNINativeInterface 的一级指针,JNINativeInterface结构体中定义了大量的函数指针,这些函数指针在JNI开发中会经常使用
    3,(*env)->:调用结构体中的函数指针
#include 
#include 
#include 

jstring Java_com_huachao_jnihelloworld_MainActivity_helloFromC(JNIEnv* env , jobject thiz){

    char* cstr = "hello from c";

    return (*env)->NewStringUTF(env,cstr);
} 
  • 配置ndk环境变量(path中添加ndk路径)
  • 在命令行cd到项目目录下:F:\as\Eclipse\personal\JNI\01-JNIHelloWorld>
  • 执行ndk-build命令,提示
Android NDK: WARNING: APP_PLATFORM android-21 is larger than android:minSdkVers
on 8 in ./AndroidManifest.xml
Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk

  • 在jni目录下,新建Android.mk文件
LOCAL_PATH := $(call my-dir)//设置为当前目录
include $(CLEAR_VARS)                //清空变量

LOCAL_MODULE    := hello//编译生成的文件名称
LOCAL_SRC_FILES := hello.c//.c源文件名称

include $(BUILD_SHARED_LIBRARY)

注意:
1,LOCAL_MODULE := hello,编译后,编译器会给文件添加lib前缀和.so后缀,例如本例生成libhello.so
2,若新建的文件夹名不是jni,或者修改了jni的文件夹名称,则在ndk-build的时候,不能在项目目录下build,要cd到这个目录下,再执行ndk-build

  • 再次在命令行中在项目目录下执行ndk-build命令,提示Install,生成.so文件,表示成功
  • 在MainActivity.java中调用
public class MainActivity extends Activity {
    static{
        System.loadLibrary("hello");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public native String  helloFromC();
    public void onClick(View v) {
        String c = helloFromC();
        Toast.makeText(this, c, Toast.LENGTH_LONG).show();
    }
}  

开发中常见错误

方法名

  • native方法名不能包含_,因为c语言的函数命名规范也是使用的_,会产生冲突,最后会报Native method not found错误
  • 如果本地方法一定要有_,那么c函数_后加1区分,例如:
public native String  hello_FromC(); 
jstring Java_com_huachao_jnihelloworld_MainActivity_hello_1FromC(JNIEnv* env , jobject thiz){
} 
  • 如果native名字太复杂,下划线太多,可以使用javah命令自动生成c的函数名
    1,如果是jdk1.6,cd到:项目根目录\bin\classes>
    2,如果是1.7及以上,cd到:项目根目录\src>
    3,执行命令:javah -jni 包名.类名
    在本例中如下:

F:\as\Eclipse\personal\JNI\01-JNIHelloWorld\src>javah -jni com.huachao.jnihelloworld.MainActivity

  • 如果没有System.loadLibrary("hello");,也会报Native method not found错误
  • 注意:System.loadLibrary("hello");加载的库名称是Android.mk中LOCAL_MODULE := hello的名称,而不是生成的.so文件的名称

Application.mk配置

多平台

  • 如果Application.mk没有文件,或者在Application.mk文件中不指定APP_ABI,在NDK默认只编译armeabi的平台的库
  • 在jni目录下新建Application.mk文件
    1, APP_ABI := all //所有平台
    2, APP_ABI := armeabi-v7a
    3, APP_ABI := x86
    4, APP_ABI := mips
    5, APP_ABI := armeabi armeabi-v7a x86 mips //也是所有平台

SDK版本配置

  • 在Application.mk添加 APP_PLATFORM := android-11
  • 版本对应
android-3 -> Official Android 1.5 system imagesandroid-4 -> Official Android 1.6 system imagesandroid-5 -> Official Android 2.0 system imagesandroid-6 -> Official Android 2.0.1 system imagesandroid-7 -> Official Android 2.1 system imagesandroid-8 -> Official Android 2.2 system imagesandroid-9 -> Official Android 2.3 system imagesandroid-14 -> Official Android 4.0 system imagesandroid-18 -> Official Android 4.3 system images

简单开发流程

  • 新建Android项目
  • 如上所述,在MainActivity中添加native方法
  • 指定项目的NDK目录:Eclipse视图中Window --> Preferences -->Android --> NDK --> 选择NDK目录(本例中目录F:\as\plugin\android-ndk-r9d) --> 点击 apply,然后点击OK
  • 在Eclipse视图中,在项目目录上右键点击-->Android Tools -->Add Native Support --> 输入自定义名称(本例中hello) --> 点击Finish
    注意:
    1,如果Finish点不了,那么可能是上一个步骤没做
    2,如果Android Tools中没有Add Native Support这个菜单:将资料中的
    com.android.ide.eclipse.ndk_23.0.2.1259578.jar文件拷贝到eclipse的安装目录的plugin目录下,然后重启Eclipse
  • 将hello.cpp重命名为hello.c,并在Android.mk文件中做相应修改
  • 用javah命令生成头文件
  • 在项目目录上右键点击 --> Properties -->C/C++ General --> Paths and Symbols --> 选中Includes选项卡 --> Add --> 添加NDK的include目录(本例F:\as\plugin\android-ndk-r9d\platforms\android-14\arch-arm\usr\include)--> 点击Apply(会提示是否rebuild,点击YES) --> 点击OK
    1, platforms的版本最好选择Application.mk设置的最低版本
    2,
    02_JNI-Eclipse上的开发环境_第1张图片
    Paste_Image.png
  • 编译
    1,切换到C/C++视图
    2,点击那个类似锤子的按钮,进行编译,


    Paste_Image.png
  • 在Java中调用和上面一样
  • 提示:运行项目最好切换到Java视图,不然可能会报错

注意:在eclipse的jni开发中,包名不能包含下划线,否则在运行时运行不了,但是却不报错

在JNI开发中,指定NDK目录,是更换workspace的时候才要做,其他的都是每次新建项目都是要做的

  • 设置编译时不编译C/C++代码,也不生成.so库(当so库已经生成完毕时,只是修改了java代码可以这样设置)
    02_JNI-Eclipse上的开发环境_第2张图片
    Paste_Image.png

取消上面两个红色箭头的勾选

绕过JNI调用C代码

  • 广泛使用的地方:
    1,自定制平板,机顶盒
    2,Android手机病毒
    3,黑客操作

  • 纯c语言开发程序 ,步骤如下:

  • 1.下载编译器和链接器软件.Sourcery G++ Lite Edition for ARM.

arm-none-linux-gnueabi-gcc.exe是编译命令
bin/arm-none-linux-gnueabi-ld.exe是链接命令

  • 2.编写c源文件
 #include 
 int main()
 {
 printf("Hello, Android!\n");
 return 0;
 }
  • 3.编译hello.c源文件
    进入cmd
    执行 arm-none-linux-gnueabi-gcc HelloWorld.c -static -o hellostatic

  • 4.将hellostatic文件传输手机
    adb push hellostatic /data/data/

  • 5.改变文件的授权
    adb shell chmod 777 /data/data/hellostatic

  • 6.运行程序
    adb shell
    cd /data/data
    ./hellostatic

  • 上面的实质就是把.c文件编译成静态库,然后在命令行执行,其实系统里面已经有很多这种可执行的文件

    02_JNI-Eclipse上的开发环境_第3张图片
    Paste_Image.png

  • 在java中执行可执行文件
public void binExce(View v) {//点击事件
     try {
//     Process process = Runtime.getRuntime().exec("/data/data/hello");//hello是我们自己编译并且放入的库文件
 Process process = Runtime.getRuntime().exec("ps");
 InputStream is = process.getInputStream();
 DataInputStream dis = new DataInputStream(is);
 String res ;
 StringBuilder sb = new StringBuilder();
 while ((res = dis.readLine()) !=null) {
 sb.append(res);
 sb.append("\n");
 }
 System.out.println("--->"+sb.toString());
 } catch (IOException e) {
 e.printStackTrace();
 }
 }

注意:上述步骤只在Android 4.x下测试生效,高版本没有测试

你可能感兴趣的:(02_JNI-Eclipse上的开发环境)