参考了网上各种教程,跌跌撞撞最终才把流程走通,特此记录一下:

有必要先交代下开发环境:

操作系统:Win7

Android Studio 3.0.1

gradle 3.0.1


首先,新建一个Android项目,然后在MainActivity的布局文件activity_main.xml文件中新增一个测试按钮,按钮id是btnTest
,效果如下所示:



然后在新增一个java类,包名是:package com.ctrip.ndktest(具体的名称以你的为主),类名是Java2CJNI,并在类中新增一个实例方法Java2C,代码如下:

package com.ctrip.ndktest;/** * Created by yuanlongzhang on 2018/4/17. */public class Java2CJNI {       //这个就是我们将来需要调用的方法    public native String java2C();}

文件目录图如下:



生成.h文件

然后使用菜单【Build】-【Rebuild Project】将Java2CJNI.java文件变成Java2CJNI.class文件。这些文件一般位于:你的项目目录\app\build\intermediates\classes\debug\下,打开cmd窗口或者在Android Studio中的Terminal窗口(如果该窗口不可见,可以通过菜单【View】-【Tool Windows】-【Terminal】打开),进入该目录使用javah命令为Java2CJNI.class生成对应的头文件,该命令的帮助如下:

用法:
  javah [options]
其中, [options] 包括:
  -o                 输出文件 (只能使用 -d 或 -o 之一)
  -d

                 输出目录
  -v  -verbose             启用详细输出
  -h  --help  -?           输出此消息
  -version                 输出版本信息
  -jni                     生成 JNI 样式的标头文件 (默认值)
  -force                   始终写入输出文件
  -classpath         从中加载类的路径
  -bootclasspath     从中加载引导类的路径
是使用其全限定名称指定的

(例如, java.lang.Object)。


我们使用如下指令生成对应的.h文件:

javah -classpath D:\androidstudy\app\build\intermediates\classes\debug -jni com.ctrip.ndktest.Java2CJNI 

其中D:\androidstudy\app\build\intermediates\classes\debug是我机器android studio生成的java .class文件所在的目录(根据情况改成你的),com.ctrip.ndktest.Java2CJNI 是需要生成对应头文件所在的包名+类名,生成成功后,会在D:\androidstudy\app\build\intermediates\classes\debug位置生成一个com_ctrip_ndktest_Java2CJNI.h文件,我们将这个文件放到 安卓项目路径\app\src\main\jni\文件夹下,如果main目录下没有jni目录,可以新建一个,注意一定是在main目录下的jni,这个时候的com_ctrip_ndktest_Java2CJNI.h的内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */#include /* Header for class com_ctrip_ndktest_Java2CJNI */#ifndef _Included_com_ctrip_ndktest_Java2CJNI#define _Included_com_ctrip_ndktest_Java2CJNI#ifdef __cplusplusextern "C" {#endif/* * Class:     com_ctrip_ndktest_Java2CJNI * Method:    java2C * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_ctrip_ndktest_Java2CJNI_java2C  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif

然后我们在该jni目录下再新建一个.c文件Java2C.c,并将com_ctrip_ndktest_Java2CJNI.h中的Java_com_ctrip_ndktest_Java2CJNI_java2C函数前面拷贝过去并实现,不知道你有没有注意到,这个函数在com_ctrip_ndktest_Java2CJNI.h中的申明时,函数参数只有类型没有参数名,我们在Java2C.c需要将其补全,并在Java2C.c中包含头文件com_ctrip_ndktest_Java2CJNI.h,Java2C.c内容如下:

//// Created by yuanlongzhang on 2018/4/17.//#include "com_ctrip_ndktest_Java2CJNI.h"JNIEXPORT jstring JNICALL Java_com_ctrip_ndktest_Java2CJNI_java2C(JNIEnv* env, jobject instance){    return (*env)->NewStringUTF(env, "I am From Native C");}

此时项目目录层次如下:



这些C代码最终会生成*.so文件,为了说明生成的*.so文件的类型和名称,我们需要修改app目录下的build.gradle,注意是app目录下的,不是项目目录下的build.gradle(图中蓝色箭头指向的文件):


这个build.gradle内容如下:

apply plugin: 'com.android.application'android {    compileSdkVersion 26    defaultConfig {        applicationId "com.ctrip.ndktest"        minSdkVersion 15        targetSdkVersion 26        versionCode 1        versionName "1.0"        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"        /*            Error:Execution failed for task ':libtermexec:compileReleaseNdk'.            > Error: Your project contains C++ files but it is not using a supported native build system.            Consider using CMake or ndk-build integration with the stable Android Gradle plugin:            https://developer.android.com/studio/projects/add-native-code.html            or use the experimental plugin:            https://developer.android.com/studio/build/experimental-plugin.html.         */        ndk {            moduleName "Java2C"                 //生成的库名            abiFilters  "armeabi-v7a", "x86"    //指定的平台类型,如果不写,则默认会生成全平台的        }    }    /*    
sourceSets {        main {            jni.srcDirs = []        }    }
    */
buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'}

网上很多文章说要加如下节点:

sourceSets {        main {            jni.srcDirs = []        }    }

在新版的android studio中是不需要添加的,如果添加了可能会导致无法生成*.so文件。另外如果不指定平台编译时会有如下的错误提示:

Information:Gradle tasks [clean, :app:assembleDebug]
Warning:Deprecated NDK integration enabled by android.deprecatedNdkCompileLease flag in gradle.properties will be removed from Android Gradle plugin in the next version.
D:\Users\zxf\AppData\Local\Android\Sdk\ndk-bundle\build\core\setup-app.mk
Error:(81) Android NDK: Application targets deprecated ABI(s): armeabi    
Error:(82) Android NDK: Support for these ABIs will be removed in a future NDK release.    
Information:BUILD SUCCESSFUL in 8s
Information:2 errors
Information:1 warning

Information:See complete output in console

这是因为armeabi这个平台,已经被废弃了,所以我们需要将它去掉,所以只好显式地指定生成的平台类型,在上文说的build.gradle文件中将armeabi去掉,由

ndk {            moduleName "Java2C"                 //生成的库名            abiFilters  "armeabi", "armeabi-v7a", "x86"    //指定的平台类型,如果不写,则默认会生成全平台的        }

变成:


ndk {            moduleName "Java2C"                 //生成的库名            abiFilters  "armeabi-v7a", "x86"    //指定的平台类型,如果不写,则默认会生成全平台的        }

另外,为了支持NDK,我们还需要在项目目录的gradle.properties文件中增加如下一行android.useDeprecatedNdk=true,如下图所示:


这在早些版本的android studio中确实可以,但是新版本的android studio也不行了,再次Rebuild Project时会提示如下错误:

Information:Gradle tasks [clean, :app:assembleDebug]
Error:Execution failed for task ':app:compileDebugNdk'.
> Error: Flag android.useDeprecatedNdk is no longer supported and will be removed in the next version of Android Studio.  Please switch to a supported build system.
  Consider using CMake or ndk-build integration. For more information, go to:
   https://d.android.com/r/studio-ui/add-native-code.html#ndkCompile
   To get started, you can use the sample ndk-build script the Android
   plugin generated for you at:
   D:\androidstudy\app\build\intermediates\ndk\debug\Android.mk
  Alternatively, you can use the experimental plugin:
   https://developer.android.com/r/tools/experimental-plugin.html
  To continue using the deprecated NDK compile for another 60 days, set 
  android.deprecatedNdkCompileLease=1523965196208 in gradle.properties
Information:BUILD FAILED in 5s
Information:1 error
Information:0 warnings
Information:See complete output in console

按照错误提示,我们去掉android.useDeprecatedNdk=true,用另外一行代替android.deprecatedNdkCompileLease=1523965196208,如下图所示:


接下来我们再次Rebuild Project,就可以生成对应的*.so文件了,这些so文件的位置在:项目路径\app\build\intermediates\ndk\debug\目录下,每个平台对应一个文件夹,而这些so的名字就是我们在上面配置的名称Java2C,只不过linux系统(Android是一种linux系统)对这种库文件的格式命名按如下规则来:

lib+库名.so

这样Java2C就变成了libJava2C.so文件。如下图所示:



如何使用这些库呢?我们需要在上文中说的Java2CJNI.java文件中加载这些库,代码如下:

package com.ctrip.ndktest;/** * Created by yuanlongzhang on 2018/4/17. */public class Java2CJNI {    static {        //System的S是大写        System.loadLibrary("Java2C");    }    public native String java2C();}
其中
static {        //System的S是大写,loadLibrary的L也是大写!        System.loadLibrary("Java2C");    }

就是我们新增的代码。

最后我们在MainActivity中使用这个Java2CJNI类和它的Java2C()方法:

package com.ctrip.ndktest;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.Toast;public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ((Button)findViewById(R.id.btnTest)).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                String result = new Java2CJNI().java2C();                Toast.makeText(MainActivity.this, "click test button", Toast.LENGTH_SHORT).show();            }        });    }}

String result = new Java2CJNI().java2C();这一行就是我们添加的,这样一来,我们就可以使用了。程序运行效果如下:


点击TEST按钮就会有提示了。注意第一次调试这个apk可能需要加载很多其他文件,会比较慢,需要耐心等待一下。另外,检测一个NDK程序是否正常,你不仅需要看下对应的so文件是否生成了,你可以将生成的apk文件解压,看下是否在根目录下的lib目录下有对应的so文件,如果没有lib目录或者无对应的so文件,你的生成的apk文件也会有问题。无法运行,运行的时会提示如下错误:


如果正确的话,apk解压后会有个lib目录,目录中有各个平台的so文件:





文章配套源码下载地址:https://download.csdn.net/download/analogous_love/10355768

更多相关文章

  1. 一键升级 ME860 CWM recovery
  2. (转)Android生成heap dump文件(.hprof)
  3. sdcard相关的adb命令
  4. android 编译出来的执行文件 not executable: magic 7F45
  5. Android课程---Android(安卓)Studio的一些小技巧
  6. Android(安卓)java.lang.StackOverflowError at android.view.Vi
  7. android 解压缩zip包
  8. Android(安卓)线刷小白教程
  9. 高级组件之选项卡

随机推荐

  1. 在PC电脑上玩Android(安卓)1.x 2.x 3.x
  2. ADB使用小结
  3. App列表之下拉刷新
  4. Android(安卓)MVP 模式 项目初体验(一)
  5. 控制android弹出框不消失(用到反射的方法
  6. 木瓜(Papaya) Android开发者创业大赛即将
  7. Android(安卓)GPRS的自动打开与关闭
  8. Android之在ubuntu上用aapt查看apk的名字
  9. Android信息推送—AndroidPN的学习(上)
  10. 给Android新手的一些学习建议