欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android Studio JNI 流程

程序员文章站 2022-06-12 20:44:49
...


1. 在Android code中,加载so库,添加native方法

package com.stone.jni;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

/**
 * author : stone
 * email  : [email protected]
 * time   : 16/2/16 23 45
 */
public class MainActivity extends Activity {


    static {
        System.loadLibrary("stonelib_test");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        TextView tv = new TextView(this);
        setContentView(tv);

//        tv.setText(hello("admin"));
        tv.setText(hello("中华小子"));

    }

    public native String hello(String username);
}


2. 利用javah命令,生成当前native方法所在类的对应的 .h 头文件

先build一下工程,生成源文件对应的.class文件。通过菜单栏中的Build>Make Project 或 Make Module 选项

在 <project>/<module>/build/intermediates/classes/debug/ 目录下生成相应的.class文件

$ cd <project>/<module>/src/main

$ javah-d jni -classpath <android.jar-path>:<project>/<module>/build/intermediates/classes/debug/ com.stone.jni.MainActivity

会在studio中的module/src/main 下生成一个jni目录,并生成一个.h头文件

生成的.h文件:

#ifndef _Included_com_stone_jni_MainActivity
#define _Included_com_stone_jni_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_stone_jni_MainActivity
 * Method:    hello
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT jstring JNICALL Java_com_stone_jni_MainActivity_hello
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

在extern "C" { … } 中 按C语言进入编译,而不是C++

在{}之外就是按C++ 编译了

note:

JNIEXPORT、JNICALL 为jni关键字 ,表示jni调用将调用后面的方法
Java_com_stone_jni_MainActivity_hell 方法名,以Java_ 开头,后跟完全限定类名和方法名
关于方法的参数:

第一个是 JNIEnv *类型。第二个jobject类型表示该方法是一个实例方法;

若方法本身是一个static修饰的静态方法,那么第二个参数会是jclass类型。

再之后的才是java方法中的参数对应的在jni中的数据类型
JNIEXPORT jstring JNICALL Java_com_stone_jni_MainActivity_hell(JNIEnv *, jobject, jstring);


3. 编写.c 或 .cpp/.cc 文件 (前者对应C语言,后者对应C++语言)

这里在C中调用String类的相关方法;需要通过命令拿到java类的 所有方法签名
$javap -s java.lang.String


/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <stdlib.h>
/* Header for class com_stone_jni_MainActivity */

#ifndef _Included_com_stone_jni_MainActivity
#define _Included_com_stone_jni_MainActivity
#ifdef __cplusplus
extern "C" {
#endif

/*
 * Class:     com_stone_jni_MainActivity
 * Method:    hello
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT jstring JNICALL Java_com_stone_jni_MainActivity_hello
        (JNIEnv *env, jobject obj, jstring jstr)
{
    jstring hel = (*env)->NewStringUTF(env, "hello,");

    jclass cls = (*env)->FindClass(env, "java/lang/String");
    jmethodID initId = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;)V");
    jobject object = (*env)->NewObject(env, cls, initId, hel);

    jmethodID concatM = (*env)->GetMethodID(env, cls, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
    jstring ss = (*env)->CallObjectMethod(env, object, concatM, jstr);

    return ss;
}

#ifdef __cplusplus
}
#endif
#endif

4. 在build.gradle中配置NDK

> 在local.properties文件中
添加ndk.dir=ndk-path //指定ndk路径

>修改module下的build.gradle配置

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.stone.jni"
        minSdkVersion 8
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        ndk {
            moduleName "stonelib_test"  //库的名字
            ldLibs "log", "z", "m"  //附加系统库
            abiFilters "armeabi", "armeabi-v7a", "x86", "mips"  //cpu架构
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
}

然后运行工程,生成的so文件目录<Project>/app/build/intermediates/ndk/

mk文件,也会自动生成于该目录下