Android jni 编程入门
本文将介绍如何使用eclipse和ndk-build来编写一个基于Android4.4版本的包含有.so动态库的安卓程序。
前提是已经安装和配置好了诸如SDK,NDK等编译环境。下面开始编程!
1 程序逻辑
我们要编写的程序包含两部分:java部分——负责界面和调用JNI native函数;JNI native 部分——负责native函数的具体实现(本文使用C语言)。
native 函数伪代码如下:
/*
funtion: 传入两个整形变量,计算他们之和
return : 返回字符串“The result is ” +sum
*/
char* test(int fisrt, int second){
sum = first + scond;
return “The result is ” +sum;
}
2 程序实现
2.1 创建项目
如编写普通apk一样创建一个apk项目。然后在该项目的根目录添加一个文件夹 jni,然后在这个文件夹下面添加hello.c和Android.mk两个文件,完成效果如下图所示:

2.2 开始JNI编程
hello.c代码如下:
/*hello.c*/
1 #include <string.h>
#include <stdio.h>
#include <jni.h> //一定不要忘了 JNIEXPORT关键字!
JNIEXPORT jstring Java_com_wan_firstjniprogram_MainActivity_test( JNIEnv* env,
jobject thiz , jint first, jint second)
{
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#define ABI "armeabi-v7a/NEON"
#else
#define ABI "armeabi-v7a"
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#elif defined(__mips__)
#define ABI "mips"
#else
#define ABI "unknown"
#endif const char* format = "The result is %d\n";
char *ret;
//add two values
jint sum = first + second;
//malloc room for the ret
ret = malloc(sizeof(format) + );
//standard sprintf
sprintf(ret, format, sum);
jstring stringRet = (*env)->NewStringUTF(env, ret);
free(ret);
return stringRet;
}
关于JNI函数名的编写,网上有很多资料,这里主要提醒两点:1、包名需要全小写,类名和函数名要大小写一致;2、一定要在函数名前加上关键字 JNIEXPORT 。
再来编写Android.mk,代码如下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello
LOCAL_SRC_FILES := hello.c include $(BUILD_SHARED_LIBRARY)
如何编写Android.mk就不过多解释了,网上资料也是一大堆,这里直接给出代码。
现在,我们的JNI 编写代码部分算是结束了,就还剩下最后一步——编译。编译很简单:使用cmd命令行进入你的apk工程所在的文件夹的jni目录(我的目录是D:\androidWorkSpace\firstJniProgram\jni),然后输入ndk-build命令即可自动编译,结果如下图所示:

从上图可以看出,我们已经成功生成了libhello.so库。到这里,JNI编程部分已经完结。下面就是进入JAVA部分了。
2.2 java编写
如何编写界面我就不多说了,这里指出我所遇到的一个问题。
问题:由于Android4.4的apk项目会创建两个layout.xml布局文件,如下图所示:
且首先展示给developer的是fragment_main.xml。这同Android2.3.3是不一样的(默认只有一个布局文件——activity_main.xml)!所以如果要添加组件的话,最好添加到activity_main中,这样才不会发生各种activity错误~。
activity_main.xml代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.wan.firstjniprogram.MainActivity"
tools:ignore="MergeRootFrame" > <TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text ="JNItest"/> </LinearLayout>
下面展示MainActivity.java的代码:
package com.wan.firstjniprogram; import junit.framework.Test;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.R.string;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends ActionBarActivity { static{
System.loadLibrary("hello");
} public native String test(int first, int second); private TextView info = null;
private Button button = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
} this.info = (TextView)super.findViewById(R.id.info);
this.button = (Button)super.findViewById(R.id.button); this.button.setOnClickListener(new MyonclickListen()); } private class MyonclickListen implements OnClickListener{ @Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
//MainActivity.this.info.setText("123"/*test(1, 2)*/);
int first = 1, second = 2;
String ret = test(first, second);
MainActivity.this.info.setText(ret);
} } @Override
public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
} /**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment { public PlaceholderFragment() {
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
} }
OK!到此,整个程序的代码已经编写完毕,可以鼠标右击项目,run as->android application了。点击JNItest按钮后,效果如下图所示:

3 修改
如果需要修改hello.c文件,那么在修改完成后,同样的方式编译即可,无需其他操作。还有一点需要指出的是,程序在运行的时候,eclipse的DDMS的logcat会提示:
NO JNIOnLoad....,这是一个warmming,是因为我们使用的javah方式编写native代码,而非使用jni_onload方式动态注册native函数,初学JNI编程可以不用理会。
Android jni 编程入门的更多相关文章
- Android jni 编程4(对基本类型二维整型数组的操作)
Android jni 编程 对于整型二维数组操作: 类型一:传入二维整型数组,返回一个整型值 类型二:传入二维整型数组,返回一个二维整型数组 声明方法: private native int Sum ...
- Android jni 编程(参数的传递,成员,方法的)相互访问
package com.test.androidjni; import android.app.Activity; import android.os.Bundle; import android.u ...
- Android系统编程入门系列之加载界面Activity
上回说到应用初始化加载及其生命周期,在Android系统调用Applicaiton.onCreate()之后,继续创建并加载清单文件中注册的首个界面即主Activity,也可称之为入口界面.主Acti ...
- Android系统编程入门系列之应用环境及开发环境介绍
作为移动端操作系统,目前最新的Android 11.0已经发展的比较完善了,现在也到了系统的整理一番的时间,接下来的系列文章将以Android开发者为中心,争取用归纳总结的态度对初级入门者所应 ...
- (转)Android: NDK编程入门笔记
转自: http://www.cnblogs.com/hibraincol/archive/2011/05/30/2063847.html 为何要用到NDK? 概括来说主要分为以下几种情况: 1. 代 ...
- 【转】Android JNI编程—JNI基础
原文网址:http://www.jianshu.com/p/aba734d5b5cd 最近看到了很多关于热补的开源项目——Depoxed(阿里).AnFix(阿里).DynamicAPK(携程)等,它 ...
- Android jni 编程3(对基本类型一维整型数组的操作)总结版
主要学习资料:黑马程序员的NDK方法使用(生产类库so) jni编程指南中文版(已上传至博客园) 博主文章(它使用的是VS和eclipse联合开发):http://www.c ...
- Android 4 编程入门经典
这是一本入门级的经典教才从Android编程入门到发布Android应用程序,每一个章节都是讲得很透,让人轻松的接受. 第1章 Android编程入门 1.1 Android简介 1.1.1 Andr ...
- 【转】android JNI编程 一些技巧(整理)
原文网址:http://blog.csdn.net/linweig/article/details/5203716 本篇将介绍在JNI编程中如何传递参数和返回值. 首先要强调的是,native方法不但 ...
随机推荐
- 面向对象编程 -------JavaScrip
本文摘要:http://www.liaoxuefeng.com/ 一定明白面向对象的两个基本概念: 类:类是对象的类型模板,例如,定义Student类来表示学生,类本身是一种类型,Student表示学 ...
- C# sizeof运算符
一.C# sizeof运算符 sizeof运算符用于获取值类型的字节数. 二.示例 using System;using System.Collections.Generic;using System ...
- java 程序设计第三次作业内容
第一题:输出结果是什么? System.out.println("5+5="+5+5); 第二题:输出结果是什么? int a=3,b; b=a++; sop("a=&q ...
- (78)zabbix值缓存(value cache)说明
在zabbix-2.2版本之前,zabbix计算trigger与calculated/aggregate值都是直接通过sql语句查询并处理出来的结果,为了提高这块的性能与效率,zabbix引入了val ...
- centos7上基于kubernetes的docker集群管理
kubernetes和docker的作用这里就不作介绍了,直接进入主题. 本文的目的是搭建docker集群,并使用kubernetes管理它们. 文中的软件环境除了kubernetes和docker, ...
- 2017 United Kingdom and Ireland Programming(Gym - 101606)
题目很水.睡过了迟到了一个小时,到达战场一看,俩队友AC五个了.. 就只贴我补的几个吧. B - Breaking Biscuits Gym - 101606B 旋转卡壳模板题.然后敲错了. 代码是另 ...
- Robo 3T
开源,免费的MongoDB桌面管理工具. [官方地址] https://robomongo.org/ https://studio3t.com/
- 笔记-python-standard library-8.1 data types-datetime
笔记-python-standard library-8.1 data types-datetime 1. Datatimes 本章节内容为日期和时间处理类和方法. 1.1. date ...
- Redis实现之RDB持久化(一)
RDB持久化 Redis是一个键值对数据库服务器,服务器中通常包含着任意个非空数据库,而每个非空数据库中又可以包含任意个键值对,为了方便起见,我们将服务器中的非空数据库以及它们的键值对统称为数据库状态 ...
- mof格式的文件怎么打开?用什么工具?
托管对象格式 (MOF) 文件是创建和注册提供程序.事件类别和事件的简便方法.在 MOF 文件中创建类实例和类定义后,可以对该文件进行编译.有关更多信息,请参见编译托管对象格式 (MOF) 文件.编译 ...