ndk-build配置、Android Studio jni的配置以及jni常见问题的解决

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qwe0754444/article/details/78373093

           最近项目用到了jni比较频繁,android studio 配置jni也是必须的。但不知道是不是运气问题,我在自己电脑使用jni一点问题都没有,可以说是无障碍。

但是,一使用公司电脑配置就出现了一大片编译报错,编译不通过的问题。

          抱着不怕搞事情的态度,我要将android studio jni配置出现的问题给解决掉。哈哈,不然有问题留着会非常不爽。也可以算帮有问题的小伙伴扫除障碍,

避免掉坑。好啦,现在我们就开始搞事情......

        1. 首先我们创建一个项目,然后创建一个JniUtils.java文件

       

        2.点击build重构一下代码,在app/build/intermediates下生成了一个classes文件夹

        


       

        

        


      3.接下来一步是要编译我们刚在创建的JniUtils.java,生成c的头文件。我们需要在Terminal板块中,跳到指的文件夹目录,做一些常规操作


      


     


    

   cd app/build/intermediates/classes/debug  //跳到指定的文件夹下

   javah -jni com.andy.testjni.JniUtils    //编译c的头文件

      编译完成后,我们将会看到生成了一个头文件

     


      4.在app目录下右键创建jni文件夹

      

    


   

    接下来将我们刚才生成的头文件复制到我们刚创建的jni文件夹里面,我们再创建一个JniUtils.c文件

  

    


   


   5.创建JniUtils.c文件后,我们需要引用头文件,我们先看一下有文件的方法名,然后我们c中引用该头文件方法

    

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

#ifndef _Included_com_andy_testjni_JniUtils
#define _Included_com_andy_testjni_JniUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_andy_testjni_JniUtils
 * Method:    getStringFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_andy_testjni_JniUtils_getStringFromC
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif
JniUtils.c文件
//
// Created by andy on 2017/10/28.
//
#include "com_andy_testjni_JniUtils.h"

/*
 * Class:     com_andy_testjni_JniUtils
 * Method:    getStringFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_andy_testjni_JniUtils_getStringFromC
  (JNIEnv * env, jclass object){
    return (*env)->NewStringUTF(env,"这里是来自c的string");

  }

切记方法名字要保持一致,Java_com_andy_testjni_JniUtils_getStringFromC


    6.文件都有了,接下来我们需要重新编译一下代码,问题开始来了

    

   

     Error:Execution failed for task ':app:compileDebugNdk'.
     > 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:
    http://tools.android.com/tech-docs/new-build-system/gradle-experimental.

    编译之后会出现两个问题,一是你还没有关联ndk,二是你没开启

     A.配置ndk,你需要关联你下载好的ndk路径

    


   B.开启ndk

  

  

  android.useDeprecatedNdk=true

    注意看,#是注释


    7.接下来我们继续配置我们的ndk模块,在build.gradle继续配置

    

     注意moudleName很重要,名字我们自己定义,这是我们java调用c关键的一步

    

 ndk{
            moduleName "jniGetFromC"
            abiFilters "armeabi", "armeabi-v7a", "x86"
        }

     我们编译成so文件,我们需要将so库打到APP中,如果不这样做,就不能调用,会报错。所以,在gradle.build里做些工作,在app的gradle.build里的android节点下加入如下代码,表示将该so库打包到APP。

    

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

    没有做此操作,将会出现引用不到路径

   {NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=F:\workspace\TestJni\app\build\intermediates\ndk\debug\Android.mk APP_PLATFORM=android-25 NDK_OUT=F:\workspace\TestJni\app\build\intermediates\ndk\debug\obj NDK_LIBS_OUT=F:\workspace\TestJni\app\build\intermediates\ndk\debug\lib APP_ABI=all}

    8.接下来我们java文件需要载入到jni library我们才可以调用,所以我们需要在JniUtils.java增加载入库

    


   

  static {
        System.loadLibrary("jniGetFromC");
    }

 注意moudleName,这是我们在gradle文件中一样的,必须保持一致才能找到

     

    9.现在我们已经完成过了大部分工作,我们build一下项目,现在开始用java调用c

    

     当项目跑起来的时候,肯定会出现异常问题

   

     只是因为我们还没有build-ndk,生成so库,所以jvm找不到library,所以就找不到c中的方法。所以,这时候我们就要去配置ndk-build,手动生成so库。


  10.配置ndk-build

     点击file--setting我们就可以看到

   


    具体可以参考我的图进行配置

    Program:C:\Users\AppData\Local\Android\sdk\ndk-bundle\ndk-build.cmd

    Working directory: $ModuleFileDir$\src\main\

    点击ok,我们将配置完成External Tools,接下来我们测试一下是否配置成功,右键我们项目中的jni文件夹,然后执行ndk-build

  

   将会肯定又有一个异常问题,慢慢来,我们快成功了,很明显,我们看错误日志,缺少.mk文件。

  

   

   11.在jni文件夹创建.mk文件,让ndk-build动态生成so库

   


  


 


  注意注意moduleName哦

  我讲解一下.mk文件语法

1>   LOCAL_PATH := $(call my-dir)
每个Android.mk文件必须以定义LOCAL_PATH为开始,它用于在开发tree中查找源文件,宏my-dir 则由Build System提供,返回包含Android.mk的目录路径。


2>   include $(CLEAR_VARS)
CLEAR_VARS 变量由Build System提供。并指向一个指定的GNU Makefile,由它负责清理很多LOCAL_xxx.


3>   LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块。名字必须唯一且不包含空格


4>  LOCAL_SRC_FILES变量必须包含将要打包如模块的C/C++ 源码,不必列出头文件,build System 会自动帮我们找出依赖文件。


application.mk文件代码

APP_ABI := armeabi armeabi-v7a x86

Android.mk文件代码

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
TARGET_PLATFORM := android-23
LOCAL_MODULE := jniGetFromC
LOCAL_SRC_FILES := JniUtils.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)


12.mk文件创建好后,我们重新ndk-build一下,我们将会成功编译好so库,将会自动生成一个obj文件夹

 



   13.走到这一步,操作基本就完成了,因为我们也编译生成到我们需要的so库了,但是最后一步切记不能少,我们还需要手动创建一个jniLibs文件夹,将我们手动编译完成的so库复制

到jniLibs文件下,不然还是会报找不到liabrary的异常

   

   重构项目,开启运行我们将会成功跑起来和调用到c的方法

  


    小节:通过解决异常和配置,希望能够帮助到你。

猜你喜欢

转载自blog.csdn.net/qwe0754444/article/details/78373093