14 JNI与NDK编程

Java的跨平台特性导致其本地交互的能力不够强大,一些和操作系统相关的特性Java无法完成,于是Java提供了JNI专门用于和本地代码交互。通过Java JNI,用户可以调用C、C++所编写的本地代码。

NDK是Android所提供的一个工具集合,通过NDK可以再Android中更加方便地通过JNI来访问本地代码(C/C++)。NDK还提供了交叉编译器,开发人员只需要简单修改mk文件就可以生成特定CPU平台的动态库。NDK的用途和优点:

  1. 代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
  2. 可以方便地使用C/C++开源库。
  3. 便于移植,用C/C++写的库可以方便在其他平台上再次使用
  4. 提供程序在某些特定情形下的执行效率,但是并不能明显提升Android程序的性能。

14.1 JNI的开发流程

  1. 在Java中声明natvie方法
  2. 用C/C++实现natvie方法
  3. 编译运行

14.2 NDK的开发流程

1 下载并配置NDK

下载好NDK开发包,并且配置好NDK的全局变量。

2 创建一个Android项目,并声明所需的native方法

public static native String getStringFromC();

3 实现Android项目中所声明的native方法

  1. 生成C/C++的头文件

    1. 打开控制台,用cd命令切换到当前项目当前目录
    2. 使用javah命令生成头文件

      javah -classpath bin\classes;C:\MOX\AndroidSDK\platforms\android-23\android.jar -d jni cn.hudp.hellondk.MainActivity
      

      说明:bin\classes 为项目的class文件的相对路径 ; C:\MOX\AndroidSDK\platforms\android-23\android.jar 为android.jar的全路径,因为我们的的Activity使用到了Android SDK,所以生成头文件时需要他; -d jni就是生成的头文件输出到项目的jni文件夹下; 最后跟的cn.hudp.hellondk.MainActivity是native方法所在的类的包名和类名。

  2. 编写修改对应的android.mk文件(mk文件是NDK开发所用到的配置文件

     # Copyright (C) 2009 The Android Open Source Project
     #
     # Licensed under the Apache License, Version 2.0 (the "License");
     # you may not use this file except in compliance with the License.
     # You may obtain a copy of the License at
     #
     #      http://www.apache.org/licenses/LICENSE-2.0
     #
     # Unless required by applicable law or agreed to in writing, software
     # distributed under the License is distributed on an "AS IS" BASIS,
     # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     # See the License for the specific language governing permissions and
     # limitations under the License.
     #
     LOCAL_PATH := $(call my-dir)
     include $(CLEAR_VARS)
     ## **看这里看这里** 对应Java部分 System.loadLibrary(String libName) 的libname
     LOCAL_MODULE    := hello
     ## **看这里看这里** 对应c/c++的实现文件名,请看图2
     LOCAL_SRC_FILES := hello.c
     include $(BUILD_SHARED_LIBRARY)
    
  3. 编写Application.mk,来指定需生成的平台对应的动态库,这里是全平台支持,也可以特殊指定。 APP_ABI := all

4 切换到jni目录的父目录,然后通过ndk-build命令编译产生so库

  1. ndk-build命令会默认指定jni目录为本地源码的目录
  2. 将编译好的so库放到Android项目中的app/src/main/jniLbis目录下,或者通过如下app的gradle设置新的存放so库的目录

     android{
         ……
         sourceSets.main{
             jniLibs.srcDir 'src/main/jni_libs'
         }
     }
    

    还可以通过defaultConfig区域添加NDK选项

     android{
         ……
         defaultConfig{
             ……
             ndk{
                 moduleName "jni-test"
             }
         }
     }
    

还可以在productFlavors设置动态打包不同平台CPU对应的so库进apk(缩小APK体积

```gradle
android{
    ……
    productFlavors{
        arm{
            ndk{
                adiFilter "armeabi"
            }
        }
        x86{
            ndk{
                adiFilter "x86"
            }
        }
    }
}
```

5 在Android中调用

public class MainActivity extends Activity {
    public static native String getStringFromC();
    static{//在静态代码块中调用所需要的so文件,参数对应.so文件所对应的LOCAL_MODULE;
        System.loadLibrary("hello");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //在需要的地方调用native方法
        Toast.makeText(getApplicationContext(), get(), Toast.LENGTH_LONG).show();
    }
}

results matching ""

    No results matching ""