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方法不但 ...
随机推荐
- PHP中可变变量到底有什么用?
转自:http://blog.csdn.net/engine_1124/article/details/8660291 什么是可变变量? PHP提供了一种其他类型的变量——可变变量.可变变量允许我们动 ...
- vue axios 攻略
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中. 特点: 从浏览器中创建 XMLHttpRequest 从 node.js 发出 http 请求 支持 ...
- 简单的Maven+SpringMVC
一.SpringMVC非注解编程 1:修改pom.xml文件(相当于非Maven项目的导入jar包) <!-- https://mvnrepository.com/artifact/org.sp ...
- Fight Against Traffic -简单dijkstra算法使用
题目链接 http://codeforces.com/contest/954/problem/D 题目大意 n m s t 分别为点的个数, 边的个数,以及两个特殊的点 要求s与t间的距离在新增一条边 ...
- keepalived原理(主从配置+haproxy)及配置文件详解
下图描述了使用keepalived+Haproxy主从配置来达到能够针对前段流量进行负载均衡到多台后端web1.web2.web3.img1.img2.但是由于haproxy会存在单点故障问题,因此使 ...
- javascript的基本类型和引用类型
一.基本类型和引用类型 基本的数据类型有5个:undefined,boolean,number,string,null ? 1 2 3 4 5 typeof null; //"object& ...
- Mysql关闭和修改密码
数据库的关闭方法: 1.优雅的关闭数据库的方法:mysqladmin -uroot -p123456 shutdown 2.脚本关闭:/etc/init.d/mysqld stop 3.使用kill信 ...
- 整理好的一些mysql表详细操作
一.创建表的完整语法#语法:create table 库名.表名( 字段名1 类型[(宽度) 约束条件], 字段名2 类型[(宽度) 约束条件], 字段名3 类型[(宽度) 约束条件]);约束条件:是 ...
- 使用python3下载网易云音乐歌单歌曲,附源代码
""" 用selenium+PhantomJS配合,不需要进行逆向工程 python 3下的selenium不能默认安装,需要指定版本2.48.0 "" ...
- ARM Linux内核源码剖析索引
start_kernel -->asm-offset.h 生成 -->proc_info_list -->machine_desc -->__vet_atags --> ...