接上一篇,搭建好基于Android Studio的环境之后,编写native代码相对来说也比较简单了。在Android上编写Native代码和在Linux编写C/C++代码还是有区别,Native代码一般需要与JVM交互数据,需要遵循一定的规范,本文来介绍一下基本的JNI代码写法。

  我们还是从实例出发,配置好Android Studio工程之后,我们需要创建jni目录和在jni目下创建c/c++文件和相应的头文件,创建方式见下图。

  在实例工程中我们创建了NdkSample.cpp 和 NdkSample.h,源码见下面:

#include "NdkSample.h"

JNIEXPORT jstring JNICALL Java_com_zyp_ndktest_MainActivity_sayHello
(JNIEnv *env, jclass cls, jstring j_str)
{
const char *c_str = nullptr;
char buff[128] = {0};
jboolean isCopy;
c_str = env->GetStringUTFChars(j_str, &isCopy);
printf("isCopy:%d\n",isCopy);
if(c_str == NULL)
{
return NULL;
}
printf("C_str: %s \n", c_str);
sprintf(buff, "hello %s", c_str);
env->ReleaseStringUTFChars(j_str, c_str);
return env->NewStringUTF(buff);
}  
#ifndef NDKTEST_NDKSAMPLE_H
#define NDKTEST_NDKSAMPLE_H #include "jni.h"
#include <stdio.h>
#include <string.h> extern "C" {
JNIEXPORT jstring JNICALL
Java_com_zyp_ndktest_MainActivity_sayHello(JNIEnv *env, jclass type,
jstring filename);
} #endif //NDKTEST_NDKSAMPLE_H

  现在来简单介绍一下,首先是NdkSample.h文件,刚刚创建的时候只有相应的预处理命令,我们在头文件预处理命令之间加上 jni.h ,stdio.h ,string.h 后两个非必要。将我们要在java层调用的接口声明出来,放在extern "c"{} 中(告诉编译器按照C标准进行编译)。第一次接触jni的同学看到那么复杂的函数命名和奇怪的JNIEXPORT ,JNICALL,JNIEnv之类的估计有点不习惯,本文就不详细介绍它们的意思,其实你跟踪源码它们就是几个宏(JNIEnv是一个结构体保存当前环境的上下文),其它的jstring,jclass之类的很好理解就是在Native环境中对JVM中java对应结构的一种表示方式。

  函数命令方式是包名加activity名加函数名,表如我们在java层中的包名是java.com.zyp.ndktest,在MainActivity中调用sayHello函数,则jni层函数命名就要写成上面的方式。

  接下来看NdkSample.cpp文件中函数的定义。ni层的函数还需要多两个参数,一个是JNIEnv * ,一个是jclass。我们在java层调用的时候就只用传递前两个参数之外的参数。例子中我们想从java层传递一个String类型的参数到jni层,jni层从JVM中取数据的时候取到的却是jstring类型,在jni层我们不能直接使用需要转换。这里我们通过env->GetStringUTFChars(j_str, &isCopy)函数来完成,将j_str所在的地址转换并赋值给const char *类型的指针,之后我们就可以通过该指针访问那块内存了。注意这里是const char * 表示该指针指向的内存区域的内容是不可以改变的,java中的String 也是自带final属性的。GetStringUTFChars()实际上是将JVM内部的Unicode转化成为了C/C++认识的UTF-8的格式的字符串,注意这个函数内部发生了内存分配,相当于是拷贝了一份Unicode然后进行转化,所以后面需要ReleaseStringUTFChars()来释放内存。

  最后该函数返回一个新的构建好的jstring类型给java层,为了将C/C++层的UTF-8字符串转换为JVM中的Unicode字符串,需要调用另外一个函数NewStringUTF()来完成转换。

  我们注意到JVM中的内容jni中不能直接操作需要进行转换,jni中的内同也要进行转换,因此也有大量的相关jni接口存在,后面文章中会挑选一些来讲解。

  此外,函数中JNIEnv *env这个参数需要说一下,在C和C++中使用方式是不一样的,不要搞混了。在C中,看到JNIEnv 我们实质是取得了JNINativeInterface* (JNIEnv指针的指针),我们得使用**env获取结构体,从而才能使用结构体里面的方法。在C++中,看到JNIEnv我们实质是取得了JNIEnv*(JNIEnv结构体的指针),我们可以直接使用env->使用结构体里面的方法。注意我们调用GetStringUTFChars()的方式,但是注意和Java_com_zyp_ndktest_MainActivity_sayHello()进行区别。

  现在来看看我们在java层中如何调用jni层的接口,看下面代码:

package com.zyp.ndktest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log; public class MainActivity extends AppCompatActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String ret = sayHello("zhuzhu");
Log.i("JNI_INFO", ret);
} static {
System.loadLibrary("NdkSample");
} public native static String sayHello(String str);
}

  我们首先要通过System.loadLibrary()加载jni代码编译后生成的.so,但是这个库的名字怎么来的呢,注意回过头去看上一篇中gradle ndk{}中的内容,我们是在那里进行的命名的;然后还要声明native static 类型的该函数。然后直接调用就好了。运行结果见下图。

  希望通过这篇文章能够让大家入门JNI开发^_^。

Android Studio1.4.x JNI开发基础 - 简单实例的更多相关文章

  1. Android Studio1.4.x JNI开发基础-基本环境配置

    从Eclipse时代到Android Studio普及,开发工具越来越好用.早些时候还需要安装Cygwin工具,从Android Studio1.3以后,在Android 环境开发JNI程序搭建开发环 ...

  2. AutoCAD ObjectARX(VC)开发基础与实例教程2014版光盘镜像

    AutoCAD ObjectARX(VC)开发基础与实例教程2014,最新版,光盘镜像 作者:张帆 朱文俊 编著 出版社:中国电力出版社 出版时间:2014年6月 点击一下

  3. JNI 开发基础篇:Android开发中os文件的探索

    正题: android开发中,时长会遇到os文件的使用,那么os文件到底是什么?在这篇文章中会进行说明. .os文件在android中意味着C语言书写的方法,经android提供的ndk进行编译,从而 ...

  4. (Hibernate进阶)Hibernate搭建开发环境+简单实例(二)

    hibernate是非常典型的持久层框架,持久化的思想是非常值得我们学习和研究的.这篇博文,我们主要以实例的形式学习Hibernate,不深究Hibernate的思想和原理,否则,一味追求,苦学思想和 ...

  5. 【SSH进阶之路】Hibernate搭建开发环境+简单实例(二)

    Hibernate是很典型的持久层框架,持久化的思想是很值得我们学习和研究的.这篇博文,我们主要以实例的形式学习Hibernate,不深究Hibernate的思想和原理,否则,一味追求,苦学思想和原理 ...

  6. 【android 开 发 】 - Android studio 下 NDK Jni 开发 简单例子

    Android 开发了一段时间,一方面 ,感觉不留下点什么.有点对不起自己, 另一方面,好记性不如烂笔头,为了往后可以回头来看看,就当做是笔记,便决定开始写博客.废话不多说 ! 今天想搞一搞 ndk ...

  7. android studio 3.4配置Android -jni 开发基础

    首先下载配置android studio ndk 1.打开sdkManager下载CMake和LLDB 2.配置ndk 项目新建 项目建立完毕后,工程目录如下,cpp文件夹是系统自动生成的 3.自定义 ...

  8. Android studio 下 NDK Jni 开发 简单例子

    1. 创建一个新的工程 2. 创建一个新的类 JniText.java  点击Build--Make Project  后     选中工程 点击F4键 sdk location 中 Android ...

  9. Android平台下的JNI开发

    JNI是Java Native Interface的缩写,通过JNI可以方便我们在Android平台上进行C/C++编程.要用JNI首先必须安装Android的NDK,配置好NDK环境之后就可以在Ec ...

随机推荐

  1. libmegjb.so加载问题调试和分析

    欢迎转载opendevkit文章, 文章原始地址: http://www.opendevkit.com/?e=70 01-01 00:09:21.084: D/dalvikvm(10394): Try ...

  2. DataTable汇总

    一.排序 1 获取DataTable的默认视图 2 对视图设置排序表达式 3 用排序后的视图导出的新DataTable替换就DataTable (Asc升序可省略,多列排序用"," ...

  3. 使用OAuth打造webapi认证服务供自己的客户端使用(二)

    在上一篇”使用OAuth打造webapi认证服务供自己的客户端使用“的文章中我们实现了一个采用了OAuth流程3-密码模式(resource owner password credentials)的W ...

  4. Java语法糖4:内部类

    内部类 最后一个语法糖,讲讲内部类,内部类指的就是在一个类的内部再定义一个类. 内部类之所以也是语法糖,是因为它仅仅是一个编译时的概念,outer.java里面定义了一个内部类inner,一旦编译成功 ...

  5. kali linux 2016.1 滚动更新源

    修改 /etc/apt/sources.list  #kali官方源 deb http://http.kali.org/kali kali-rolling main non-free contrib ...

  6. Portal.MVC —— nopcommerce的简化版

    Portal.MVC 简介 项目是基于MVC4+EF,带有角色,权限,用户中心及账户相关(登录,注册,修改密码,找回密码等)等基本功能.参考的开源项目 nopcommerce,这是一个电商架构的MVC ...

  7. 【吉光片羽】ie6兼容性的几个点

    1.浮动换行.自己写个导航,li向左浮动,到ie6下全部错开了. --> 还是在现有bootstrap框架的基础上修改样式保险一些. <div id="mymenu" ...

  8. C#将dll打包到程序中

    最近比较懒,加上内容也不多就懒得排版了,字放大了,看起来应该方便一点 直接进入主题 先来看一个栗子,假设现在有一个第三方dll namespace TestLibrary1 { public clas ...

  9. Effective c#学习笔记(1)

    条款1 使用属性代替可访问的数据成员 属性是个啥,谁在用? 1. C#的属性在被访问的时候看起来好像是数据成员,但其实是方法.     2. 在.NET框架中,一般使用属性表达公有数据成员.      ...

  10. DDD~领域事件应用篇(订单处理变得更清晰)

    回到目录 上一讲主要说了领域事件和领域总线,这并不是一个很容易理解的文章,所以本讲实例篇主要是为了补充上一讲的理论知识,本讲实例关注的是实际中的订单处理模块,我们知道,订单处理是电子商务的核心,往往在 ...