1. 使用环境Android Studio
注1:language 选择java(另一个选择kotlin 语法完全不熟);
注2:SDK根据你的实际安卓设备选择;
2. 配置gradle(默认gradle 地址下载速度慢)
2.1)gradle-wrapper.properties;
–替换distributionUrl:https://mirrors.cloud.tencent.com/gradle/gradle-8.0-bin.zip
2.2)选择配置文件setting.gradle
–插件pluginManagement仓库添加下载路径
maven { url ‘https://maven.aliyun.com/repository/gradle-plugin’ }
maven { url ‘https://maven.aliyun.com/repository/google’ }
3. 工程结构
3.1 java端是MainActivity.java 需要调用接口;
3.2 cpp端是native-lib.cpp 实现接口。
4. java端代码
package com.example.helloworld;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.util.Log;
import java.util.logging.*;
import com.example.helloworld.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "RenSichao";
Logger logger = Logger.getLogger("Rensichao");
// Used to load the 'helloworld' library on application startup.
static {
System.loadLibrary("helloworld");
}
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// Example of a call to a native method
TextView tv = binding.sampleText;
tv.setText(stringFromJNI());
boolean flag = boolfromJNI();
logger.log(Level.INFO, String.format("boolfromJNI return %b",flag));
byte[] array={1,2,3,4,5};
byte[] recv = arrayfromJNI(array);
for(int i=0;i<5;i++)
{
logger.log(Level.INFO, String.format("arr return %d",array[i]));
}
}
/**
* A native method that is implemented by the 'helloworld' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
public native boolean boolfromJNI();
public native byte[] arrayfromJNI(byte[] arr);
}
注:其实就3个接口,在OnCreate中调用
public native String stringFromJNI(); //工程自带
public native boolean boolfromJNI();
public native byte[] arrayfromJNI(byte[] arr);
5. cpp端代码
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_helloworld_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_example_helloworld_MainActivity_boolfromJNI(
JNIEnv* env,
jobject /* this */) {
bool flag = true;
return flag;
}
extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_example_helloworld_MainActivity_arrayfromJNI(
JNIEnv* env,
jobject /* this */,jbyteArray arr)
{
jbyte *add = env->GetByteArrayElements(arr, nullptr);
for(int i=0;i<5;i++)
{
add[i]=add[i]+1;
}
env->SetByteArrayRegion(arr,0,5,(jbyte*)add);
env->ReleaseByteArrayElements(arr, add, 0);
return arr;
}
注1:可以看到java调用c++的接口,是通过jni实现的。有特定的函数名:
extern "C" JNIEXPORT xxx Java_com_example_helloworld_MainActivity_xxx()
注2:传递的参数都是jni中的类型。
6. 调试中遇到的问题:
6.1)实现格式化参数打印log;
无论使用Log.i()还是Logger对象,打印对象都是string字符串,没有像C/C++直接设置格式化参数方式。需要通过Sting.format(“hello world %d”,i)的方法转成字符串,间接有log接口输出。
具体的格式说明参考:https://blog.csdn.net/anita9999/article/details/82346552
6.2)构造数组需要选用byte[]而不是Byte[],后者是类不是java的基础类型;
6.3)C++接口实现有输入参数,处理时需要调用env->Getxxx,不能直接处理;
6.4)通常env->Getxxx 与 env->Releasexxx 一起使用释放资源。