Android JNI学习-基础篇

  • 简介
    JNI(Java Native Interface)顾名思义java本地接口,说白了就是javac/c++ 通过JNI接口的规范实现通信,本文将实现最基本的 java调c的函数,c调java的函数
  • 相关知识
    C/C++基础

编写JAVA代码

创建java文件 → 加载动态库 → 定义本地函数 → 调用本地方法

package com.example.test;

public class MainActivity extends AppCompatActivity {

    //加载动态库
    static {
        System.loadLibrary("test");
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //调用本地方法
        String str = javaCallNative("hello jni");
        Log.i("xxxMainActivity", str + " --> javaCallNative");
    }

    /**
     * 定义本地函数
     */
    public native String javaCallNative(String str);

    /**
     * 定义被本地调用的函数
     */
    public static void nativeCallJava(String str) {
        Log.i("xxxMainActivity", str + " --> nativeCallJava");
    }
}

编写C代码

根据jni规范,实现Java 中定义的函数

  • 在main目录下面,创建jni文件夹

  • 在jni下面 , 创建 test.h 文件

    
    /**
     * 是否已经引用了test.h这个文件了,防止多次引用
     * 一般是
     * #ifndef XXX_H
     * #define XXX_H
     *
     * ...
     *
     * #endif
     *
     */
    #ifndef TEST_H
    #define TEST_H
    
    #include <jni.h>//引用jni.h
    
    /**
     * 声明方法,具体在同名.cpp里面实现,
     * 注意函数名规范 -->Java_对应java方法的绝对路径(JNIEnv *env , jobject p0 , 对应java方法的参数)
     */
    extern "C"
    JNIEXPORT jstring JNICALL
    Java_com_example_test_MainActivity_javaCallNative(JNIEnv *env, jobject p0, jstring p1);
    
    
    #endif
    
    
  • 在jni下面 , 创建 test.cpp文件

    #include "test.h"
    
    /**
     * 定义c++函数  注意函数名规范 -->Java_对应java方法的绝对路径(JNIEnv *env , jobject p0 , 对应java方法的参数)
     */
    extern "C"
    JNIEXPORT jstring JNICALL
    Java_com_example_test_MainActivity_javaCallNative(JNIEnv *env, jobject jobj, jstring p1) {
        //通过反射调用java中的方法
        //找class 使用FindClass方法,参数就是要调用的函数的类的完全限定名,但是需要把点换成/
        jclass clazz = env->FindClass("com/example/test/MainActivity");
        //获取对应的函数: 参数1:类class,参数2:方法名,参数3:方法签名
        jmethodID method = env->GetStaticMethodID(clazz, "nativeCallJava", "(Ljava/lang/String;)V");
        //调用返回空的静态方法
        env->CallStaticVoidMethod(clazz, method, p1);
        return p1;
    }
    

建立Android.mk文件

在jni下面 , 创建 Android.mk 文件,将本地C代码编译成.so的动态库

#LOCAL_PATH定义本地路径,  $(call my-dir)是一个函数,意思是获取当前函数
LOCAL_PATH := $(call my-dir)
#CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。
include $(CLEAR_VARS)
#LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'foo'的共享库模块,将会生成'libfoo.so'文件。
LOCAL_MODULE := test
#LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。
LOCAL_SRC_FILES := test.cpp
#BUILD_SHARED_LIBRARY 由编译系统提供,表示编译一个分享库(动态库.so)
include $(BUILD_SHARED_LIBRARY)

Android.mk官方文档

建立Application.mk文件

指定 ndk-build 的项目范围设置。默认情况下,它位于应用项目目录中的 jni下
注意: Gradle 的 externalNativeBuild会忽略APP_ABI
注意: 使用 externalNativeBuild 进行编译时,Android Studio 将根据您的编译风格适当地设置此标记。

#Application Binary Interface编译CPU架构
APP_ABI := armeabi
#指定目标Android API版本
APP_PLATFORM := android-14
#指定要使用的stl库,默认为system
APP_STL := system
#优化选项,默认值为release。可选值为debug和release。release模式下文件体积更小,debug模式下提供更多的调试信息
APP_OPTIM := release

Application.mk 官方介绍

在build.gradle 文件增加执行函数

build.gradle文件下增加执行函数,通过gradle自动编译

android {
...

	defaultConfig {
   ...

        //设置编译所支持的CPU架构
        ndk {
            abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
        }

    }
...
    externalNativeBuild {
    	//编译的Android.mk文件地址
        ndkBuild {
            path file("src/main/jni/Android.mk")
        }
    }
...

}

点击sync now

当你修改了build.gradle文件,右上角就会出现sync now ,点击就可以了

如果报没有ndk,就需要添加ndk

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值