Android NDK 开发总结

一.安装配置环境

1.安装Android Studio,下载路径https://developer.android.com/studio/index.html?hl=zh-cn。我下载的是Windows 64位集成Android SDK版本https://dl.google.com/dl/android/studio/install/2.3.2.0/android-studio-bundle-162.3934792-windows.exe?hl=zh-cn,不用单独安装Android SDK。因为公司支持访问Google,所以下载很方便。

2.安装完毕,下载CMake,LLDB和NDK工具

3.如果要使用Git版本控制,需要单独下载安装包,官网地址https://git-scm.com/,安装好后在Android Studio里设置路径

然后可以指定下载路径获取代码,比如kotlin的代码仓库

二.分析新建NDK工程

首先创建一个新工程,选择Include C++Support

打开工程,里面有一个C++输出字符串的例子

路径在D:\Project\MyApplication\app\src\main\cpp\native-lib.cpp,代码如下

#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

调用的文件是MainActivity.java,路径是D:\Project\MyApplication\app\src\main\java\com\example\myapplication\MainActivity.java,内容如下

package com.example.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the ‘native-lib‘ library on application startup.
    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());
    }

    /**
     * A native method that is implemented by the ‘native-lib‘ native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

按Shift+F9,调试运行,选择真机

在手机端输出如下

默认对这个C++代码是用CMake编译的,CMakeLists.txt的路径在D:\Project\MyApplication\app\CMakeLists.txt,内容精简如下:

cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
             native-lib
             # Sets the library as a shared library.
             SHARED
             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp )
find_library( # Sets the name of the path variable.
              log-lib
              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )
target_link_libraries( # Specifies the target library.
                       native-lib
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

其中,#代表行注释。大概意思是设置要编译的库名称是native-lib,源代码路径是src/main/cpp/native-lib.cpp

在模块的gradle文件(注意不是项目的gradle文件,前者的路径是D:\Project\MyApplication\app\build.gradle,后者路径是D:\Project\MyApplication\build.gradle)里默认配置使用cmake文件编译

三.按照CMake+gradle的方式编写NDK程序

接下来我尝试自己模仿用NDK写一个C++的例子

编写一个包含native方法的java类,如TestNative.java,路径在D:\Project\MyApplication\app\src\main\java\com\example\myapplication\TestNative.java

代码如下:

package com.example.myapplication;

public class TestNative {
    static {
        System.loadLibrary("NativeLib");
    }
    public static native String GetStr();
}

其中,NativeLib指定的是这个类要加载的库的名称,稍后我会生成这个库,方法一定要用native修饰,而且为了不定义对象,把这个方法声明为static类型,这样可以直接用TestNative.GetStr()这样的方式访问。

接下来需要生成对应的库,首先要编写C++文件,有两种方式,一种是使用Javah,生成头文件,对应头文件件编写源代码;另一种是根据jni生成函数的格式手动写一个cpp即可,不用头文件,先在实现第一种:

输入CMD使用控制台或者在Android Studio下方的Terminal终端,先cd找到当前TestNative.java文件的位置

D:\Project\MyApplication>cd D:\Project\MyApplication\app\src\main\java\com\example\myapplication

D:\Project\MyApplication\app\src\main\java\com\example\myapplication>

然后输入javac TestNative.java编译生成class文件

D:\Project\MyApplication\app\src\main\java\com\example\myapplication>javac TestNative.java

D:\Project\MyApplication\app\src\main\java\com\example\myapplication>

在D:\Project\MyApplication\app\src\main\java\com\example\myapplication下会生成一个TestNative.class文件

然后cd到最上层包的路径上,这点非常重要,是我反复尝试带包名的类执行java或javah的方法

执行javah,参数是带包名的类

D:\Project\MyApplication\app\src\main\java\com\example\myapplication>cd D:\Project\MyApplication\app\src\main\java

D:\Project\MyApplication\app\src\main\java>javah com.example.myapplication.TestNative

D:\Project\MyApplication\app\src\main\java>

会在D:\Project\MyApplication\app\src\main\java路径下生成com_example_myapplication_TestNative.h文件,内容如下

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_myapplication_TestNative */

#ifndef _Included_com_example_myapplication_TestNative
#define _Included_com_example_myapplication_TestNative
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_myapplication_TestNative
 * Method:    GetStr
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_myapplication_TestNative_GetStr
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

按照这个声明编写一个cpp,如如TestNative.cpp,路径是在D:\Project\MyApplication\app\src\main\cpp\TestNative.cpp,包含该头文件,实现即可

#include <string>#include "../java/com_example_myapplication_TestNative.h"

extern "C" {JNIEXPORT jstring JNICALL Java_com_example_myapplication_TestNative_GetStr        (JNIEnv * env, jclass) {    std::string str = "My First Native Test";    return env->NewStringUTF(str.c_str());}}

第二种就是根据这样的声明特征,直接写一个TestNative.cpp,注意函数命名方式一定要和用Javah生成的头文件的方法一致,仔细观察记住就行了。这样不用使用javac和javah手动生成class文件和头文件,但要包含jni.h头文件,代码如下

#include <string>#include <jni.h>

extern "C" {JNIEXPORT jstring JNICALL Java_com_example_myapplication_TestNative_GetStr        (JNIEnv * env, jclass) {    std::string str = "My First Native Test";    return env->NewStringUTF(str.c_str());}}

然后修改CMakeLists.txt文件,如下

cmake_minimum_required(VERSION 3.4.1)
add_library( NativeLib
             SHARED
             src/main/cpp/TestNative.cpp )
find_library( log-lib
              log )
target_link_libraries( NativeLib
                       ${log-lib} )

修改调用JNI的文件,如下

package com.example.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    @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(TestNative.GetStr());
    }
}

运行程序,在手机输出

用CMake方式,会在路径D:\Project\MyApplication\app\build\intermediates\cmake\debug\obj下生成各种平台版本的so文件,如armeabi中的libNativeLib.so,注意生成库的名称是在设定库名称前加了lib

三.按照ndk-build+gradle的方式编写NDK程序

按照ndk-build的方式编译,需要生成.mk文件

在之前建立工程的基础上

1.首先,要在D:\Project\MyApplication\app\src\main下新建jni文件夹,在里面新建Android.mk文件,内容如下

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE = NativeLib

LOCAL_SRC_FILES := ../cpp/TestNative.cpp

LOCAL_LDLIBS := -landroid -llog -latomic

include $(BUILD_SHARED_LIBRARY)

大体意思是指定目标库的名称,源代码的路径,可以对比CMakeLists.txt。

2.接在,在Android.mk的同级目录下,建立Application.mk文件,内容如下

APP_STL := c++_static

即说明使用C++的版本,具体可以参考https://developer.android.com/ndk/guides/cpp-support.html#runtimes

注意在使用C++时要新建Application.mk文件,写上C++版本,直接写在Android.mk不行,否则会提示STL的库找不到

3.修改gradle的编译方式为ndkBuild,内容如下

用ndk-build的方式,会在路径D:\Project\MyApplication\app\build\intermediates\ndkBuild\debug\obj\local\下生成各种平台版本的so文件

四.设置指定平台版本的库

1.清理掉D:\Project\MyApplication\app\build下的文件夹

2.在模块的build.gradle文件中添加如下:

就只会生成libNativeLib.so了。

时间: 2024-08-26 07:55:38

Android NDK 开发总结的相关文章

Android NDK开发篇(五):Java与原生代码通信(数据操作)

尽管说使用NDK能够提高Android程序的运行效率,可是调用起来还是略微有点麻烦.NDK能够直接使用Java的原生数据类型,而引用类型,由于Java的引用类型的实如今NDK被屏蔽了,所以在NDK使用Java的引用类型则要做对应的处理. 一.对引用数据类型的操作 尽管Java的引用类型的实如今NDK被屏蔽了,JNI还是提供了一组API,通过JNIEnv接口指针提供原生方法改动和使用Java的引用类型. 1.字符串操作 JNI把Java的字符串当作引用来处理,在NDK中使用Java的字符串,须要相

Android NDK 开发(三)--常见错误锦集合Log的使用【转】

转载请注明出处:http://blog.csdn.net/allen315410/article/details/41826511  Android NDK开发经常因某些因素会出现一些意想不到的错误,很多时候调试这些错误的时候,显得比调试Java代码要复杂,一方面是导致错误的原因很多很杂,另一方面NDK开发涉及到C/C++代码的编写,很多程序员对此不熟悉.那么这篇博客就总结一下,在NDK开发中经常出现的一些问题,并且尝试提供一些正确的解决方案,方便在开发时能够快速定位到错误,更改错误,当然了,错

Android NDK 开发

NDK全称:Native Development Kit. 1.NDK是一系列工具的集合. * NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk.这些工具对开发者的帮助是巨大的. * NDK集成了交叉编译器,并提供了相应的mk文件隔离平台.CPU.API等差异,开发人员只需要简单修改mk文件(指出"哪些文件需要编译"."编译特性要求"等),就可以创建出so. * NDK可以自动地将so和Java应用一起

C++开发安卓、windows下搭建Android NDK开发环境

1. NDK(Native Development Kit) 1.1 NDK简介 Android NDK是一套允许开发人员使用本地代码(如C/C++)进行Android APP功能开发的工具,通过这个工具,我们可以把用C/C++代码编译成可以直接运行在Android平台上的本地代码,这些本地代码以动态链接库( *.so )的形式存在,也正因为这样,我们可以通过复用这些动态链接库从而复用本地代码. 那么,通过NDK这个开发工具包,那么我们是否可以将一个APK完全使用C/C++来编写呢? 答案是不可

Android NDK 开发(四)java传递数据到C【转】

转载请注明出处:http://blog.csdn.net/allen315410/article/details/41845701 前面几篇文章介绍了Android NDK开发的简单概念.常见错误及处理和从第一个Hello World开始实际做一个简单的JNI开发示例,相信看完之后,大家对NDK开发有了一个概念上的认识了,那么接下来我们需要再深入一下NDK的开发,我们知道NDK开发就是使用JNI这层“协议”在Java和C之间起个“桥梁”的作用,将Java和Native C之间联立起来,让Java

跟我学Android NDK开发(一)

Android NDK 开发跟其它开发一样,首先需要配置好开发环境,本文以 Ubuntu系统为例介绍如何进行 Android NDK 开发环境的配置. 1. 简介 什么是 Android NDK 呢? NDK(Native Development Kit) 是一个允许开发者用一些本地语言(C/C++)编写 Android App 的部分功能的工具集.对于一些特定的 App,NDK 非常有利于我们直接使用现成的用 C/C++ 编写的代码库(但对于大多数 App 来说,NDK 是没有必要的).使用

Android NDK开发(八)——应用监听自身卸载,弹出用户反馈调查

转载请注明出处:http://blog.csdn.net/allen315410/article/details/42521251 监听卸载情景和原理分析 1,情景分析 在上上篇博客中我写了一下NDK开发实践项目,使用开源的LAME库转码MP3,作为前面几篇基础博客的加深理解使用的,但是这样的项目用处不大,除了练练NDK功底.这篇博客,我将讲述一下一个各大应用中很常见的一个功能,同样也是基于JNI开发的Android应用小Demo,看完这个之后,不仅可以加深对NDK开发的理解,而且该Demo也可

Android NDK开发常见错误

错误一: make: *** No rule to make target `/cygdrive/d/1-workspace/showmap-android-opengles/jni/showmap_opengles_OpenGLESRenderer.c', needed by `/cygdrive/d/1-workspace/showmap-android-opengles/obj/local/armeabi/objs/OpenGLESMap/showmap_opengles_OpenGLES

Android NDK开发(二)——从Hello World学起

转载请注明出处:http://blog.csdn.net/allen315410/article/details/41805719  上篇文章讲述了Android NDK开发的一些基本概念,以及NDK的环境搭建,相信看过的朋友NDK开发环境搭建应该是没有问题了,还没有搭建或者不知道怎么搭建的朋友请点击这里.那么这篇文章,我们跟刚学Java编程语言一样,从世界知名程序"Hello World!"开始,开发出我们的第一个NDK程序. NDK目录简单介绍 在进行NDK开发之前,我们有必须熟悉

Android ndk开发swig编译jni接口配置文件(二)

之前写过一篇Android ndk开发swig编译jni接口.看这篇看不懂,看以去看看.c++与Java有些语言结构还是有一定区别,比如c++结构体,一些函数的返回值等都是有所不同,进行swig编译要进行一些预处理,也就是配置一下就行.下面说说几种情况. 一.一般情况下string,数组,枚举类型等配置Unix.i %module Survey %include "std_string.i" %include "arrays_java.i" %include &qu