安卓JAVA JNI NDK 基础使用样例 附实现的详细步骤

安卓JAVA JNI NDK 基础使用样例 附实现的详细步骤

最近做安卓项目需要使用到JNI的知识调用C文件,在网上搜寻了近两天的资料踩了很坑,总结了一套在安卓中使用JNI的步骤,记录在这里顺便提供给像我一样刚接触的朋友们做一个参考。

JNI的用途就是实现在Java代码中调用c/c++语言的方法,具体的原理之类的我就不说了百度说的很多,先介绍下环境

开发环境

Android Studio 4.2.2
SDK:API 30
SDK Build-Tools:30.0.3
NDK :21.4.7075529(下载于Android Studio )

项目:minSdk 24,targetSdk 30

环境基本不会影响最终结果,但还是列出来以防万一,下面直接上步骤

实现步骤

  1. 在AS中的项目右键创建文件夹jni,选择下方自动弹出的src/main/jni(蓝色文件夹)

  2. 在java源码目录下创建一个工具类用来保存native方法,如

    package com.example.testaidl;
    
    public class JNIHelper {
        static {
            // 加载库文件
            System.loadLibrary("JNIHelper");
        }
        public static native String getName();
    }
    

    这时AS会说找到不对应的本地方法的实现,先不管,接着往下走

  3. 到工具类文件的所在目录使用javac命令编译出class文件

  4. 在当前目录新建一个文件夹,把class文件放进去,再在新建出来的文件夹下运行javah -classpath 绝对路径 packagename.classname

    1. packagename为包名,使用点号隔开
    2. javah -classpath D:\WorkSpace\MyFirstApp\testaidl\src\main\java com.example.testaidl.JNIHelper

      注意包名前有一个空格

  5. 在新建的文件夹中即会生成 .h头文件

  6. (非必须) 将头文件中的#include <jni.h> 改成#include "jni.h"

  7. 到jdk目录中找到jni.h和jni_md.h文件,拷贝到项目jni目录中,第五步自动生成的.h文件及c/c++源码也一起拷贝到jni目录中

    需要使用对应系统版本的jdk(win对win,linux对linux),不同系统的jdk里面的jni.h和jni_md.h文件不同,会导致编译失败

  8. 在jni目录中编写两个mk文件(直接New File创建)

    1. Android.mk

      LOCAL_PATH:= $(call my-dir)
      
      include $(CLEAR_VARS)
      
      #指定生成的so库文件名称
      LOCAL_MODULE:= JNIHelper
      #指定对应的c源码,多个源码间用空格分隔
      LOCAL_SRC_FILES:= JNIHelper.c
      LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
      
      include $(BUILD_SHARED_LIBRARY)
      
    2. Application.mk

      #需要与Android.mk文件中的LOCAL_MODULE一致
      APP_MODULES = JNIHelper
      APP_PLATFORM := android-24
      APP_ABI    := armeabi-v7a arm64-v8a x86 x86_64
      APP_STL    := c++_shared
       
      ifeq ($(NDK_DEBUG), 1)
          APP_OPTIM = debug
          APP_CFLAGS = -g -O0
      else
          APP_OPTIM = release
          APP_CFLAGS = -O3
      endif
      
  9. 在项目AndroidManifest.xml中添加 <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="30"/>

  10. 在module的build.gradle文件中添加

     defaultConfig{
        #注意这个ndk节点是写到AndroidManifest对应的defaultConfig节点中
    	ndk{
            //设置so库文件名称
            moduleName "JNIHelper"
            // 声明创建指定cpu架构的so库
            abiFilters "arm64-v8a", "armeabi-v7a", "x86"
        }
        
    }
        
    android{
        #注意这个externalNativeBuild节点是写到AndroidManifest对应的android节点中
    	externalNativeBuild{
            ndkBuild{
                path "src/main/jni/Android.mk"
            }
        }
    }
    
  11. 在AndroidStudio中下载NDK,随后重新build module,build通过后直接到项目jni目录运行ndk-build命令(需要提前为NDK配置环境变量或直接使用绝对路径),成功后就会在项目src/main目录下生成libs文件夹,其中有对应不同架构的so库文件

    1. 可能会遇到include的头文件不存在报错的问题,这是因为新版本的ndk不再附带platforms/android-xx(api版本)/arch-xx(架构)/usr/include文件夹,头文件本应当根据不同的架构放置在不同架构文件夹中的此处。
      1. 解决可以通过下载ndk12b(谷歌官网下载地址:https://developer.android.google.cn/ndk/downloads/older_releases?hl=de),解压/android-ndk-r12b/platforms/android-24/目录下各个架构的include文件夹进新版ndk,具体拷贝到新版ndk的哪个api文件夹则取决于你项目的targetSdk的api版本
      2. 或将/android-ndk-r12b/platforms/android-24/arch-x86_64/usr/中的include文件单独拷贝出来,然后在Android.mk文件中添加LOCAL_C_INCLUDES属性指定include文件夹位置,如LOCAL_C_INCLUDES := /home/local/Android/include,但此方法能否适配不同架构的系统还未能验证,建议使用第一种解决方式
  12. 在JNIHelper类中的本地方法已可使用

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值