关闭

Android Jni之Helloworld

标签: androidhelloworldjniandroid studio
140人阅读 评论(0) 收藏 举报
分类:

一、搭建NDK环境

NDK可以自己下载好,然后布置一下环境变量。不过我这里有个更加简便的方法。在Android studio2.2及更高版本中可以像插件那样安装NDK了。
设置流程如下:
点开File->Setting,弹出Setting窗口。
NDK环境搭建
如图所示,在setting -> Appearance&Behavior -> System Setting -> Android SDK -> SDK Tools(视图右边),选择CMake、LLDB、NDK这三个下载。然后一边静静地等它下载安装。

如果你是建好工程再下载NDK,你还要在File ->Project Structure里面设置一下NDK地址。这里直接按“Select default NDK”就可以了。
selectNDK
它会自己生成路径:D:\Android\Sdk\ndk-bundle(这是我电脑NDK的地址)
并且会在local.properties里自动生成一行ndk目录地址。
生成NDK地址

在gradle.properties里面添加
android.useDeprecatedNdk=true

gradle.properties配置
至此,你可以愉快地编写Jni了。

二、Jni编写

1)编写Java接口

在项目里新建一个Java类。

public class Jni {

   public native String say(String str);

}

注意这里用到的是“native”修饰。

2)编写c/c++接口及代码

Android studio有个Terminal工具,对应Windows系统的cmd窗口。
在cmd里面cd进入项目的Java文件夹里面,因为Java文件夹里面的是对应包名
package com.example.jnitest;
输入javah -jni com.example.jnitest.Hello然后生成.h文件。
这里写图片描述

项目目录下就多了一个com_example_jnitest_Jni.h文件。
这里写图片描述

这个就是c/c++的头文件

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

#ifndef _Included_com_example_jnitest_Jni
#define _Included_com_example_jnitest_Jni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_jnitest_Jni
 * Method:    say
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_jnitest_Jni_say
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

新建JNI文件夹
新建JNI文件夹

然后把com_example_jnitest_Jni.h文件拉进去
这里写图片描述

在jni目录里新建c/c++源码文件

#include <stdio.h>
#include <stdlib.h>
#define TAG "JNI" //自定义的变量
#include <android/log.h>
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, TAG ,__VA_ARGS__)
#include "com_example_jnitest_Jni.h"
JNIEXPORT jstring JNICALL Java_com_example_jnitest_Jni_say
        (JNIEnv *env, jobject, jstring str) {
           LOGD("This is JNI");
    return str;
}

上面的c/c++源码#include "com_example_jnitest_Jni.h" 就是引入刚刚生成的.h文件。Java_com_example_jnitest_Jni_say是对应Java类里的say方法。这个名字是要固定的格式写的,文件目录-文件名-方法名,如果你取其他名称也需准守起名规则。
总体的目录结构如下:
目录结构

3)生成so文件

打开app Module的build.gradle文件,在defaultConfig节点加入NDK的配置信息。

      ndk {
            moduleName "HelloWorld"     //so文件名
            ldLibs "log", "z", "m"      //添加系统库文件
            abiFilters "armeabi", "armeabi-v7a", "x86"   //d对应芯片结构
        }

moduleName是你的so文件名,lbLibs附加系统库文件,abIlity添加你要生成的库对应的芯片架构。
这里添加了log,在这个项目代码对应是

#define TAG "JNI" //自定义的变量
#include <android/log.h>
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, TAG ,__VA_ARGS__)
LOGD("This is JNI");

这个是在c/c++源码里添加log日记。

NDK配置信息

布置好了就可以编译了。
编译Jni
在工具来点击编译按钮,或者在Build -> Make Project来执行。
编译好了后,你会在你的项目module里面的build -> intermediates ->ndk ->发现对应的so文件。
注意你的项目所在的目录文件夹名字不能有空格,否则编译不通过了。
jnilib

上面的配置在运行时候,每次都会编译一下的,你程序有对应的调用代码会调用到这个文件的,如果你不想每次都编译一下so库,你也可以把对应的so库拿出来用。
把刚刚生成的so文件连同文件夹复制到项目的libs文件夹里面,当然了,你也可以放到项目的其他位置。
注意要连同上面的“armeabli”,“armeabi-v7a”,”x86”文件夹一起复制,系统调用时候会根据不同的芯片架构来调用不同的so库。
这放到libs文件夹里面
然后在app的build.gradle指引一下配置目录,并设置不自动ndk编译。

android {
  ......
    sourceSets.main {
        jniLibs.srcDir 'libs'//放so文件的目录
        jni.srcDirs = [] //disable automatic ndk-build call
    }
}

好了上面几步你已经生成对应的so库了,下面就是调用。

4)调用so库

先需要加载动态库,动态库的名称是编译时候在build.gradle设置的名称。
然后像普通的方法一样调用即可。

public class MainActivity extends AppCompatActivity {

    static {        // 加载动态库
        System.loadLibrary("TestJNI");
    }

    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.text_hello);
        Jni jni = new Jni();
        tv.setText(jni.say("Hello world. This message is from Jni."));

    }
}

app显示的jni

logcat显示的jni

源码下载地址:https://github.com/loongX/AndroidJniDemo/tree/master

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:32785次
    • 积分:641
    • 等级:
    • 排名:千里之外
    • 原创:31篇
    • 转载:1篇
    • 译文:0篇
    • 评论:6条
    最新评论