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方法不但 ...
 
随机推荐
- 分享12款最佳的Bootstrap设计工具
			
设计师总会渴望有一些新奇有趣的设计工具来提高工作效率,而Bootstrap就是您的不二选择.2013年Bootstrap得到了广泛普及, 它是开发者较为常用的框架之一,本文我们将分享12款最佳的Boo ...
 - Nginx学习记录(一)
			
1. 什么是nginx Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器.由俄罗斯的程序设计师Igor Sysoev所开发,官方测试nginx能够支支 ...
 - 魅族MX3 Flyme3.0找回手机功能支持远程拍照密码错两次自动拍照
			
进入Flyme页面(http://app.meizu.com/),选择“查找手机”即可进行查找自己登记的魅族系列手机. 如果您在一个账号下登记过N多魅族系列手机,那么都是可以进行查找的,参见下图 魅族 ...
 - 已解决: idea创建并部署SpringMVC项目时 报错 java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
			
用IDEA创建并运行SpringMVC项目时,最初发现没有Servlet包,这个问题已在上篇解决,然而当我们尝试去运行此时的SpringMVC项目时,发现仍然有错误.ClassNotFoundExce ...
 - 1074: [SCOI2007]折纸origami
			
Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 372 Solved: 229[Submit][Status][Discuss] Descriptio ...
 - MVP模式与MVVM模式
			
1.mvp模式(Model层 Presenter层 View 层) Model层 :数据层(ajax请求) Presenter层:呈现层,view逻辑相关的控制层,控制层可以去调Model去发ajax ...
 - 以太坊国内节点大全(ropsten)
			
admin.addPeer('enode://2d1e1f1242c3b54ea56046f74f15943f47ab410e3c0b82bffb501793ebb19e147f8f0e63d01c2 ...
 - 精通SpringBoot:详解WebMvcConfigurer接口
			
SpringBoot 确实为我们做了很多事情, 但有时候我们想要自己定义一些Handler,Interceptor,ViewResolver,MessageConverter,该怎么做呢.在Sprin ...
 - 模块numpy的用法
			
https://blog.csdn.net/qq351469076/article/details/78817378 机器学习三剑客之Numpy: https://www.jianshu.com/p/ ...
 - 单片机入门学习笔记6:新唐单片机N76E003
			
学习新唐单片机是从2018年3月开始的,之前一点也不懂这一块单片机,之后脉络变的越来越清晰. 由于N76E003档次太低,新塘科技官方的管脚配置,芯片选型……都没有这一块芯片,资料唯独只有:芯片的数据 ...