Android之JNI开发

最近看了个领导给的小项目,里面有使用到JNI,就学习了一下,在这里对我的学习过程做一个总结和记录。

 

demo的运行效果如下:

 

 

首先是安装NDK和一些其他的插件,由于我使用的Android Studio版本为3.0.1(3.2版本以上不存在此问题),所以需要下载一个ndk16的包,tool-chain目录下将报错信息里面缺少的部分放进去。

ndk下载地址

 

在MainActivity的同级下建立cpp文件夹用以存放相应的Java类:

 

 

 

 

之后先写类中的方法:

public static native String stringFromNDK();

 

通过Android自带的Terminal进入build文件夹的debug目录下,并输入命令,进行编译

 

 

 

 

 

 之后就会在目录下看到生成的.h文件

 

 

 

在Java目录的同级下建立jni目录,用以存放.h头文件和.mk文件,将上面生成的.h文件剪切到此文件夹下

 

 

 

在jni目录下,创建和.h文件名称相同的.c文件 

 

之后在.c文件中写入相应的代码

//
// Created by zhang.qiongwen on 2019/11/26.
//
//这里的include的内容即为你生成的同名.h文件
#include "com_example_zhangqiongwen_jni_demo_cpp_HelloJNI.h"

//这里的方法会写在.h文件中,只是没有方法体,也没有声明传入的参数,只是指定了传入的类型,可以直接拿过来用,需要将传入的JNIEnv的几个参数补上 JNIEXPORT void JNICALL Java_com_example_zhangqiongwen_jni_1demo_cpp_HelloJNI_HelloJNIFromNDK (JNIEnv *env, jobject job, jobject jobject1){ jclass jclass1 = (*env)->FindClass(env,"com/example/zhangqiongwen/jni_demo/TestClassOfJNI"); jmethodID jmethod = (*env)->GetMethodID(env, jclass1, "makeToastInContext","()V"); (*env)->CallVoidMethod(env, jobject1, jmethod); };

 

再在jni目录中创建两个.mk文件

 

 

 

Android.mk文件内容如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

//这是编译生成的文件名字 LOCAL_MODULE :
= jni-test
//这里我编译了两个文件,中间以空格隔开 LOCAL_SRC_FILES :
= com_example_zhangqiongwen_jni_demo_cpp_HelloNDK.c com_example_zhangqiongwen_jni_demo_cpp_HelloJNI.c include $(BUILD_SHARED_LIBRARY)

 

Application.mk文件内容如下:

APP_ABI := all

 

 

 

 还需要在build.gradle文件中添加依赖(ndkbuild指定.mk文件的路径,sourceSets指定的是生成的so库的路径)

 

 

 

以及在gradle.properties中添加一行

Android.useDeprecatedNdk=true

 

然后rebuild以下项目,如果能在响应的目录下找到so库文件,就说明大功告成了

 

 

 

在src文件夹的同级下建立lib文件夹,将so库放进去

 

 

 就可以在java文件中调用so库了

 

以上就是如何使用JNI来从Java调用C中的方法,那么当C需要调用Java中的方法时,该如何做呢

其他步骤基本与以上的一致,只是在编写.c文件时候需要多一个查询方法签名的步骤。

 

通过Terminal进入debug目录中,输入javap -s +需要查询的类  来对签名进行查询

 

再编写.c文件:

//
// Created by zhang.qiongwen on 2019/11/26.
//

#include "com_example_zhangqiongwen_jni_demo_cpp_HelloJNI.h"
JNIEXPORT void JNICALL Java_com_example_zhangqiongwen_jni_1demo_cpp_HelloJNI_HelloJNIFromNDK
        (JNIEnv *env, jobject job, jobject jobject1){
  
  //获取类名 jclass jclass1
= (*env)->FindClass(env,"com/example/zhangqiongwen/jni_demo/TestClassOfJNI");   
  //获取方法名
  //这里就需要填入之前查询到的方法的签名 jmethodID jmethod
= (*env)->GetMethodID(env, jclass1, "makeToastInContext","()V");
  //调用函数 (
*env)->CallVoidMethod(env, jobject1, jmethod); };

 

工程所有代码如下:

结构目录:

 

 

 

activity_mian.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.zhangqiongwen.jni_demo.MainActivity">


    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        app:layout_constraintTop_toBottomOf="@+id/blacksheepwar"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"

        app:layout_constraintVertical_bias="1"

        android:text="somethingfornothing"

        android:id="@+id/somthingfornothing"

        />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toTopOf="@id/somthingfornothing"
        app:layout_constraintVertical_chainStyle="packed"

        android:text="blacksheepwar"

        android:id="@+id/blacksheepwar"

        />

</android.support.constraint.ConstraintLayout>

 

MainActivity.java:

package com.example.zhangqiongwen.jni_demo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.example.zhangqiongwen.jni_demo.cpp.HelloJNI;
import com.example.zhangqiongwen.jni_demo.cpp.HelloNDK;

public class MainActivity extends AppCompatActivity {

    static HelloJNI mHelloJni = new HelloJNI();
    Button mButtonTest;
    Button mButtonTest2;
    TestClassOfJNI mTestClassOfJNI = new TestClassOfJNI(this, MainActivity.this);

    static{
        System.loadLibrary("jni-test");
//        System.loadLibrary("jni-");
    }

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


        mButtonTest = findViewById(R.id.somthingfornothing);
        mButtonTest2 = findViewById(R.id.blacksheepwar);

        mButtonTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                mHelloJni.HelloJNIFromNDK(mTestClassOfJNI);
            }
        });


        mButtonTest2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                   Toast.makeText(getBaseContext(), HelloNDK.stringFromNDK(), Toast.LENGTH_LONG).show();
            }
        });
    }

    public void makeToast(){
        Toast.makeText(this, "this has been used by C", Toast.LENGTH_LONG).show();
    }

}

 

TestClassOfJNI:

public class TestClassOfJNI {

    Context mMainContext;
    MainActivity mMainActivity;

    public TestClassOfJNI(Context mContext, MainActivity mMainActivity){
        this.mMainContext = mContext;
        this.mMainActivity = mMainActivity;
    }

    public void makeToastInContext(){

        mMainActivity.makeToast();

    }

}

 

HelloJNI:

public class HelloJNI {

    public HelloJNI(){
    }

    public native void HelloJNIFromNDK(TestClassOfJNI a);

}

 

HelloNDK:

public class HelloNDK {
    public HelloNDK(){

    }
    public static native String stringFromNDK();
}

 

HelloJNI.c:

#include "com_example_zhangqiongwen_jni_demo_cpp_HelloJNI.h"
JNIEXPORT void JNICALL Java_com_example_zhangqiongwen_jni_1demo_cpp_HelloJNI_HelloJNIFromNDK
        (JNIEnv *env, jobject job, jobject jobject1){

    jclass jclass1 = (*env)->FindClass(env,"com/example/zhangqiongwen/jni_demo/TestClassOfJNI");

    jmethodID jmethod = (*env)->GetMethodID(env, jclass1, "makeToastInContext","()V");

    (*env)->CallVoidMethod(env, jobject1, jmethod);
};

 

 HelloNDK.c:

#include "com_example_zhangqiongwen_jni_demo_cpp_HelloNDK.h"

jstring Java_com_example_zhangqiongwen_jni_1demo_cpp_HelloNDK_stringFromNDK(JNIEnv *env,jobject thiz){
    return (*env)->NewStringUTF(env,"I am Str from jni libs!");
}

 

posted @ 2019-11-27 16:03  FrauleinEule  阅读(294)  评论(0编辑  收藏  举报