JNI——调用C或C++代码

本文介绍了在Android开发中使用JNI与C/C++代码交互的基本概念和步骤。从创建Native C++ Project开始,分析JNI调用过程,包括如何在C/C++文件中定义与Java方法对应的函数,以及在JNI中处理不同类型的数据。文中还强调了JNIEnv在cpp和c文件中的区别,并通过示例展示了对象参数的传递和修改。最后,文章总结了JNI在Android应用开发中的作用,为后续的C/C++编程打下基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JNI——调用C或C++代码

JNI即JavaNativeInterface,其实就只是一个用于与C/C++代码交互的一个接口,在实际使用过程中只需要在方法名前加上native关键字修饰。本文将从Android开发的角度阐述JNI的一些基本概念和使用。

创建第一个C/C++的App

在AndroidStudio中创建应用时选择Native C++ Project
外链图片转存失败(img-sVmTRYZ2-1563629265341)
待Project初始化完成后会自动生成一个JNI调用例子。

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

两个关键的地方,System.loadLibrary()表示加载对应的c/c++文件,native关键字修饰的方法stringFromJNI(),修饰后会通过loadLibrary的C文件中寻找同名的函数。生成的cpp文件如下:

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_grcen_blogdemonative_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

分析JNI调用过程

在native-lib.cpp文件中有一个与前面JNI的方法stringFromJNI()相同的函数,首先JNIEXPORTJNICALL都表示该函数和Java方法stringFromJNI()对应,其中jstring是返回值类型,函数名的格式一般为Java_类的完整路径_native方法名。参数env是ndk内置的一个指针/结构体,jobject表示当前对象。

这里需要明确一个概念,在c语言中的char、int等数据类型和Java中不是相同的,这里用jchar、jint等做区分。所以说当前函数虽然返回值类型是string,但我不能直接return字符串,只能使用env结构体(在C文件中为指针)下一系列的函数替我们完成从C到Java这层的转换。比如上面返回Hello from C++这一字符串,则用NewStringUTF()函数来完成,返回类型是jstring。下面来看个对对象参数操作的例子。

注意在cpp和c文件中JNIEnv有着不同的实现,在cpp文件中为结构体,在c文件中为指针。

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Event event = new Event("MyEvent!");
        Log.i("jni", "onCreate: " + event.toString());
        stringFromJNI(event);
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(event.getMessage());
        Log.i("jni", "onCreate: " + event.toString());
    }

    public native void stringFromJNI(Event event);
}
extern "C" JNIEXPORT void JNICALL
Java_com_grcen_blogdemonative_MainActivity_stringFromJNI(JNIEnv *env,jobject instance, jobject m_event) {
    // 找到参数的类
    jclass event_clazz = env->GetObjectClass(m_event);
    // 利用找到的类找到属性
    jfieldID message_fid = env->GetFieldID(event_clazz, "message", "java/lang/String"); //有的地方这里要改成"Ljava/lang/String"
    // 利用找到的属性找到值
    jstring message_value = (jstring)(env->GetObjectField(m_event, message_fid));
    // 拼接字符串
    const char *new_value = env->GetStringUTFChars(message_value, JNI_FALSE);
    char newMessage[125] = "Oh!";
    strcat(newMessage, new_value);
    // 修改event对象中Message的值
    jstring newMessageStr = env->NewStringUTF(newMessage);
    // 修改对象的属性
    env->SetObjectField(m_event, message_fid, newMessageStr);
}

在Activity中,Event对象只有一个String类型的Message对象,作为参数传入native方法。在native函数中先找到类再找到对应属性,再找其值,然后拼接字符串再修改对象中属性的值。最后在Activity中显示修改后的属性。

注意:这里与IO流中读写对象不同,这里修改完后的对象还是同一个。在将对象进行本地写操作时,再读回来,只是两个内容相同的对象但其对象已经不是同一个。在AIDL中跨进程通信时就会经常利用IO传输对象,但不能简单判断两者是否相等。

015A184081BCD4976F7B1B477A3E6B46.png

总结

总而言之我们现在可以用C/C++代码来写我们的程序了,而中间的交互由JNI完成,具体还是有JNIEnv完成。关于.so文件和其他操作的讲解待续。

参考文章

  1. Android NDK开发之旅(3): 详解JNI数据类型与C/C++、Java之间的互调
  2. Java Native Interface(JNI)从零开始详细教程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值