快速上手ndk开发! Mac/Win下配置和使用!(2018.4重编版)
目录 前言 ndk环境配置 下载ndk 配置ndk路径 配置ndk环境路径 ndk上手 实现c函数, 并编译生成.so 其他项目使用.so 最后 前言 说下我的AndroidStudio版本是2.3.3, 还没有更新到3.x(手动委屈), 主要还是想把手头项目搞定了再跳坑. 然后这次添加了mac平台的配置, 其实没多大区别, 当然, linux也是大同小异, 毕竟android studio是通用的. 为什么要使用.so?从我自己的理解出发, 有几点非常主要: 你往往不是一个人在开发, 而且你的合作伙伴不可能把所有源码给你编译. 所以一个解决方案就是他编译生成.so给你, 再给你个.h文件, 告诉你有哪些函数.对于这些函数, 你只需要知道功能而不需要知道实现细节. .so文件是依靠c/cpp编译而成的, c/cpp语言的重要性不言而喻, 历史地位也是不可撼动的, 而且一些本来已经写好的库, 没必要说因为要写Android就换成java重新实现一遍. 所以需要让Android去支持那些已有的库. java源码反编译一下很容易拿到的, 当然可以加固apk, 会好一点. 而编译生成.so之后, c的源码就很难看到了. ndk环境配置 有个比较头痛的事情叫做配环境 下载ndk mac下下载ndk win下下载ndk 配置ndk路径 mac下配置ndk路径 win下配置ndk路径 配置ndk环境变量 mac: 用vim打开.bash_profile, 在最后加入ndk所在路径. vim .bash_profile mac下添加ndk路径 更新配置文件并测试ndk-build指令 更新配置并测试 win: win下配置ndk环境变量 加入到PATH大家庭 打开PowerShell测试一下 打开PowerShell测试一下 终于可以开始使用NDK了, 或者你可以管它叫JNI ndk上手 在包目录下创建HellJNI类, 并写入必要代码 mac下 win下 public class HelloJNI { //一个加法函数, 用c实现 public native int AddC (int a, int b); static { //加载库, 注意库名的一致性 System.loadLibrary("HelloC"); } } 使用javah命令生成头文件, 注意! 这是重点, 要背!(滑稽脸)然后新建一个同名c/cpp. mac: mac下生成头文件 生成后目录一栏 生成后目录一栏 win: 使用javah命令生成头文件 一览 实现c函数, 并编译生成.so 拷贝.h文件中生成的函数, 在c/cpp中实现它. /* * Class: com_so_myapplication_HelloJNI * Method: AddC * Signature: (II)I */ JNIEXPORT jint JNICALL Java_com_so_myapplication_HelloJNI_AddC (JNIEnv *, jobject, jint, jint); #include "com_so_myapplication_HelloJNI.h" JNIEXPORT jint JNICALL Java_com_so_myapplication_HelloJNI_AddC (JNIEnv * env, jobject obj, jint a, jint b){ return a + b; } 在jni目录下创建Android.mk和Application.mk文件并写入内容, 重点! Android.mk内容如下: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := HelloC LOCAL_SRC_FILES := com_so_myapplication_HelloJNI.c LOCAL_SRC_FILES += util.c include $(BUILD_SHARED_LIBRARY) 有2个要点: LOCAL_MODULE的名称要和之前System.loadLibrary("HelloC");中的名称一致; Win下需要再加一个空的util.c文件进行编译, 否则会报错, 不信可以试试(手动滑稽), mac/linux下无需. Application.mk内容如下: APP_ABI := all #APP_ABI := armeabi armeabi-v7a x86 mips arm64-v8a mips64 x86_64 有2个要点: 我知道这样不太专业, 不过这个ABI问题牵扯太多, 暂不细说, 主要是和不同cpu有关. armeabi似乎已被淘汰. 配置build.gradle, 重中之重! 先是build.gradle一览: android { compileSdkVersion 26 buildToolsVersion "26.0.3" sourceSets { main { jniLibs.srcDirs = ['libs'] } } defaultConfig { applicationId "com.so.myapplication" minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk { moduleName "HelloC" //System.loadLibrary("HelloC"); } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } ndk需要配置, 注意名字匹配! ndk { moduleName "HelloC" //System.loadLibrary("HelloC"); } sourceSets配置 sourceSets { main { jniLibs.srcDirs = ['libs'] } } 在gradle.properties中加上一句 android.useDeprecatedNdk=true 然后就是ndk-build了, 再查看是否生成成功! mac下ndk-build win下ndk-build 一览 你可以在这个项目中使用这个由c实现的加法函数了, 但是我们有更酷的事情要做, 那就是在另外的项目中用这个函数. 其他项目使用.so 这件事其实没有很难, 基本靠两步. 第一步就是将前一个项目生成的libs目录下的全部内容拷贝到AndroidStudio自带的libs目录下 一览 第二步就是创建一个和前一个生成libs目录的项目相同的包和类, 类中写入的内容也是一样的.顺带加下build.gradle中的sourceSets, 不记得位置, 参考之前的build.gradle一览. 一览 public class HelloJNI { public native int AddC (int a, int b); static { System.loadLibrary("HelloC"); } } sourceSets { main { jniLibs.srcDirs = ['libs'] } } 最后测试下效果, 这段代码我就不解释了, 这看不懂也就告别手表了! public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv_testc = (TextView) findViewById(R.id.tv_testc); tv_testc.setText("add: " + new HelloJNI().AddC(1, 2)); } } 测试结果 最后 完结散花! 喜欢记得点赞或者关注我哦, 有问题和意见可以评论区~~