AS2.2使用CMake方式进行JNI/NDK开发

之前写过一篇比较水的文章Android手机控制电脑撸出HelloWorld
里面用到了JNI/NDK技术。

这篇文章给大家介绍下JNI/NDK开发。采用的是Android Studio2.2开发环境,使用CMake方式进行开发。

JNI(Java Native Interface)是java与C/C++进行通信的一种技术,使用JNI技术,可以java调用C/C++的函数对象等等,Android中的Framework层与Native层就是采用的JNI技术。

我们知道,Android系统是基于linux开发,采用的是linux内核 ,Android APP开发大部分也要和系统打交道,只是Android FrameWork 帮我们处理了和系统相关的操作, 我们从Android 系统的分成结构可以看出,Android FrameWork是通过JNI与底层的C/C++库交互,例如:FreeType,OpenGL,SQLite,音视频等等。


如果我们程序也需要调用自己的C/C++函数库,就必须用到JNI/NDK开发。

NDK配置(最新的CMake方式)

Android Studio2.2版本已经完全支持ndk开发了。而且默认采用CMake方式。(传统方式不过多介绍了)

CMake的优势

  1. 可以直接的在C/C++代码中加入断点,进行调试
  2. java引用的C/C++中的方法,可以直接ctrl+左键进入
  3. 对于include的头文件,或者库,也可以直接的进入
  4. 不需要配置命令行操作,手动的生成头文件,不需要配置android.useDeprecatedNdk=true 属性

下载

首先需要下载NDK,来到设置界面点击下载NDK


安装完NDK,还可以选择配置一些工具。

  1. CMake: 外部构建工具。如果你准备只使用 ndk-build 的话,可以不使用它。(Android Studio2.2默认采用CMake)
  2. LLDB: Android Studio上面调试本地代码的工具。

创建项目

Android Studio升级到2.2版本之后,在创建新的project时,界面上多了一个Include C++ Support的选项。勾选它之后将会创建一个默认的C++与JAVA混编的Demo程序。



然后一路 Next,直到 Finish 为止即可。


上面图的这三个文件都是默认生成的NDK项目的一部分:

  1. .externalNativeBuild文件夹:cmake编译好的文件, 显示支持的各种硬件等信息。系统生成。
  2. cpp文件夹:存放C/C++代码文件,native-lib.cpp文件是默认生成的,可更改。需要自己编写。
  3. CMakeLists.txt文件:CMake脚本配置的文件。需要自己配置编写。

app/build.gradle也有所不同


如果你在创建工程选择C++11的标准,则使用cppFlags "-std=c++11"

externalNativeBuild {
     cmake {
         cppFlags "-std=c++11"
     }
 }

来看一下,CMakeLists.txt文件中的具体配置

这个文件#开头的全是注释,里面不是注释的只有下面的内容。

cmake_minimum_required(VERSION 3.4.1) #指定cmake版本
          
          
add_library( #生成函数库的名字
             native-lib  
             SHARED  #生成动态函数看
             src/main/cpp/native-lib.cpp ) #依赖的cpp文件
                       
find_library( #设置path变量的名称
              log-lib
              #指定要查询库的名字
              log ) #在ndk开发包中查询liblog.so函数库(默认省略lib和.so),路径赋值给log-lib
                   
target_link_libraries( #目标库,和上面生成的函数库名字一至
                       native-lib
             #连接的库,根据log-lib变量对应liblog.so函数库
                       ${log-lib} )

java代码

public class MainActivity extends AppCompatActivity {
   
    // 加载函数库
    static {
        System.loadLibrary("native-lib");
    }
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
   
        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }
   
    /**本地方法, 当前方法是通过C/C++代码实现*/
    public native String stringFromJNI();
}

上面java代码中的 stringFromJNI()方法用native关键字修饰,这个方法是通过C/C++代码实现的。

native-lib.cpp 代码

#include <jni.h>  
#include <string>
  
extern "C"
jstring
Java_com_a520wcf_jniproject_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

上面的C++代码,定义的函数名是固定写法,Java_包名_类名_Java中方法名 ,通过这种命名方式就可以唯一对应到java中具体的方法,从而具体实现java中的native方法。

运行项目

修改完C/C++代码需要点击“锤子”图标进行编译,然后运行项目。



运行代码,就能看到效果,调用了C++方法在界面上显示了Hello from C++字符串。

如果你不是使用CMake而是使用传统方式进行开发,这时候就会使用了ndk -build来编译C/C++文件为so文件。

那么,我们安装运行的apk中,有对应的so文件吗?

如果想验证一下apk是否有so文件,我们可以使用 APK Analyzer查看。
选择 Build > Analyze APK。

选择 apk,并点击 OK。
当前项目debug阶段的apk默认路径为 app/build/outputs/apk/app-debug.apk



如下图,在 APK Analyzer 窗口中,选择 lib/x86/,可以看见 libnative-lib.so 。

.so文件是动态函数库,写好的c/c++代码默认打包成函数库,就没法看到代码,只能使用了。

如果我们想在工程中使用其他人编译好的函数库,只需要根据不同的cpu架构把函数库在src/main/jniLibs目录下。



在java代码中也需要引入相应的函数库,编写一样的native方法。

手动添加native方法

上面我们主要介绍程序自动生成的代码,接下来我们自己动手写写。
我们也可以在MainActivity中写一个native方法。



有红色警告,因为当前方法并没有找到对应的底层代码的实现。我们可以在报错的地方按下万能的快捷键alt+回车。



选择第一项,就会自动生成对应的底层方法。

参考之前的方法,照着葫芦画瓢,把错误先修复下。

修改MainActivity代码,调用我们写的native方法。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  
    TextView tv = (TextView) findViewById(R.id.sample_text);
    tv.setText(stringFromJNI2());//调用新写的native方法
}

编译运行当前程序。
运行结果:



可以看到我们成功调用了我们自己创建的native方法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容