侧边栏壁纸
博主头像
Eoser's page! 博主等级

@学习@生活@自己

  • 累计撰写 114 篇文章
  • 累计创建 29 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Android JNI笔记第三弹:C/C++调用Java

eoser
2023-04-17 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

其实第一弹已经实现了,不过第一弹重点是为了引入外部so库文件,导致写得有些杂乱,这里转专门开一弹写Cmake引入的方法

  • 创建Android Studio项目,省略
  • MainActivity内容,提供了调用的可视化方法
package org.eu.uiai.jnilearn;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
    static {
        //加载写的 C 库
        System.loadLibrary("my_lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        JniApi jApi=new JniApi();
        //将本Activity传给JniApi,方便静态方法的调用
        jApi.setsActivity(this);
        //实现c代码调用java的入口方法
        jApi.updateTextView();
    }
    //更新界面方法,共JniApi调用更新界面
    public void updateTextView(){
        int a=9,b=10;
        TextView ss=findViewById(R.id.show_string);
        TextView st=findViewById(R.id.show_text);
        ss.setText("你好 C to Java");
        st.setText(a+"+"+b+"="+(a+b));
    }
}
  • 写API接口类JniApi
package org.eu.uiai.jnilearn;
public class JniApi {
    //C要实现的方法
    public native void updateTextView();
    //静态变量,需要传入
    private static MainActivity sActivity;
    //设置静态变量的方法
    public void setsActivity(MainActivity activity){
        sActivity=activity;
    }
    //静态方法,C中会调用该方法,调用后会更新Activity界面
    public static int update(){
        if(sActivity!=null){
            sActivity.updateTextView();
            return 1;
        }
        return 0;
    }
}
  • 通过指令生产jni头文件
javac ./app/src/main/java/org/eu/uiai/jnilearn/JniApi.java -h ./app/src/main/jni
  • 生成的头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class org_eu_uiai_jnilearn_JniApi */

#ifndef _Included_org_eu_uiai_jnilearn_JniApi
#define _Included_org_eu_uiai_jnilearn_JniApi
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     org_eu_uiai_jnilearn_JniApi
 * Method:    updateTextView
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_org_eu_uiai_jnilearn_JniApi_updateTextView
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
  • 根据头文件写Cpp的实现
#include "org_eu_uiai_jnilearn_JniApi.h"

// log 输出相关部分
#include 
#define LOG_TAG "MyLibTag"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

JNIEXPORT void JNICALL Java_org_eu_uiai_jnilearn_JniApi_updateTextView
        (JNIEnv *env, jobject api){
    //获取JinApi的class
    jclass cls = env->GetObjectClass(api);
    //根据Class,方法名,传入和返回参数;通过获取静态方法的函数获取方法ID
    jmethodID id = env->GetStaticMethodID(cls,"update", "()I");
    //通过Call执行方法,在通过static_cast获取结果
    jint res = static_cast(env->CallStaticIntMethod(cls,id));
    //从log输出执行结果
    LOGE("执行结果Code:%d", (int)res);
}
  • 修改build.gradle文件
......
android {
    ......
    defaultConfig {
        ......
        //{添加内容开始
        externalNativeBuild {
            cmake {
                arguments "-DANDROID_STL=c++_shared"
            }
        }
        //添加内容结束}
        ......
    }
    //{添加内容开始
    externalNativeBuild {
        cmake {
            path "src/main/jni/CMakeLists.txt"
        }
    }
    //添加内容结束}
    ......
}
dependencies {
    ......
}
  • CMakeList.txt文件内容
add_library(my_lib SHARED my_lib.cpp)
# 链接log库必须加的,由于是连接到my_lib,所不能放在my_lib的add_library前
target_link_libraries(my_lib log)
效果与第一弹相同,这是我测试后比较简洁的配置,复杂的代码可能还有其他配置

效果展示 Log输出

0

评论区