🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 14.2 NDK的开发流程 NDK的开发是基于JNI的,其主要由如下几个步骤。 * 1.下载并配置NDK 首先要从Android官网上下载NDK,下载地址为https://developer.android.com/ndk/downloads/index.html,本章中采用的NDK的版本是android-ndk-r10d。下载完成以后,将NDK解压到一个目录,然后为NDK配置环境变量,步骤如下所示。 首先打开当前用户的环境变量配置文件: vim ~/.bashrc 然后在文件后面添加如下信息:export PATH=~/Android/android-ndk-r10d:$PATH,其中~/Android/android-ndk-r10d是本地的NDK的存放路径。 添加完毕后,执行source ~/.bashrc来立刻刷新刚刚设置的环境变量。设置完环境变量后,ndk-build命令就可以使用了,通过ndk-build命令就可以编译产生so库。 * 2.创建一个Android项目,并声明所需的native方法 package com.ryg.JniTestApp; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; public class MainActivity extends ActionBarActivity { static { System.loadLibrary("jni-test"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = (TextView)findViewById(R.id.msg); textView.setText(get()); set("hello world from JniTestApp"); } public native String get(); public native void set(String str); } 3.实现Android项目中所声明的native方法 在外部创建一个名为jni的目录,然后在jni目录下创建3个文件:test.cpp、Android.mk和Application.mk,它们的实现如下所示。 // test.cpp #include <jni.h> #include <stdio.h> #ifdef __cplusplus extern "C" { #endif jstring Java_com_ryg_JniTestApp_MainActivity_get(JNIEnv *env, jobject thiz){ printf("invoke get in c++\n"); return env->NewStringUTF("Hello from JNI in libjni-test.so ! "); } void Java_com_ryg_JniTestApp_MainActivity_set(JNIEnv *env, jobject thiz, jstring string) { printf("invoke set from C++\n"); char* str = (char*)env->GetStringUTFChars(string, NULL); printf("%s\n", str); env->ReleaseStringUTFChars(string, str); } #ifdef __cplusplus } #endif // Android.mk # 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) LOCAL_MODULE := jni-test LOCAL_SRC_FILES := test.cpp include $(BUILD_SHARED_LIBRARY) // Application.mk APP_ABI := armeabi 这里对Android.mk和Application.mk做一下简单的介绍。在Android.mk中,LOCAL_MODULE表示模块的名称,LOCAL_SRC_FILES表示需要参与编译的源文件。Application.mk中常用的配置项是APP_ABI,它表示CPU的架构平台的类型,目前市面上常见的架构平台有armeabi、x86和mips,其中在移动设备中占据主要地位的是armeabi,这也是大部分apk中只包含armeabi类型的so库的原因。默认情况下NDK会编译产生各个CPU平台的so库,通过APP_ABI选项即可指定so库的CPU平台的类型,比如armeabi,这样NDK就只会编译armeabi平台下的so库了,而all则表示编译所有CPU平台的so库。 4.切换到jni目录的父目录,然后通过ndk-buiId命令编译产生so库 这个时候NDK会创建一个和jni目录平级的目录libs, libs下面存放的就是so库的目录,如图14-1所示。需要注意的是,ndk-build命令会默认指定jni目录为本地源码的目录,如果源码存放的目录名不是jni,那么ndk-build则无法成功编译。 [插图] 图14-1 通过NDK编译产生的so库 然后在app/src/main中创建一个名为jniLibs的目录,将生成的so库复制到jniLibs目录中,然后通过AndroidStudio编译运行即可,运行效果如图14-2所示。这说明从Android中调用so库中的方法已经成功了。 [插图] 图14-2 Android中调用so库中的方法示例 在上面的步骤中,需要将NDK编译的so库放置到jniLibs目录下,这个是AndroidStudio所识别的默认目录,如果想使用其他目录,可以按照如下方式修改App的build.gradle文件,其中jniLibs.srcDir选项指定了新的存放so库的目录。 android { ... sourceSets.main { jniLibs.srcDir 'src/main/jni_libs' } } 除了手动使用ndk-build命令创建so库,还可以通过AndroidStudio来自动编译产生so库,这个操作过程要稍微复杂一些。为了能够让AndroidStudio自动编译JNI代码,首先需要在App的build.gradle的defaultConfig区域内添加NDK选项,其中moduleName指定了模块的名称,这个名称指定了打包后的so库的文件名,如下所示。 android { ... defaultConfig { applicationId "com.ryg.JniTestApp" minSdkVersion 8 targetSdkVersion 22 versionCode 1 versionName "1.0" ndk { moduleName "jni-test" } } } 接着需要将JNI的代码放在app/src/main/jni目录下,注意存放JNI代码的目录名必须为jni,如果不想采用jni这个名称,可以通过如下方式来指定JNI的代码路径,其中jni.srcDirs指定了JNI代码的路径: android { ... sourceSets.main { jni.srcDirs 'src/main/jni_src' } } 经过了上面的步骤,AndroidStudio就可以自动编译JNI代码了,但是这个时候AndroidStudio会把所有CPU平台的so库都打包到apk中,一般来说实际开发中只需要打包armeabi平台的so库即可。要解决这个问题也很简单,按照如下方式修改build.gradle的配置,然后在Build Variants面板中选择armDebug选项进行编辑就可以了。 android { ... productFlavors { arm { ndk { abiFilter "armeabi" } } x86 { ndk { abiFilter "x86" } } } } 如图14-3所示,可以看到apk中就只有armeabi平台的so库了。 :-: ![](https://img.kancloud.cn/ea/48/ea48bd30d4ad7f270227739602ce91ea_708x601.png) 图14-3 AndroidStudio打包后的apk