1 / 43

Android 应用程序开发进阶

Android 应用程序开发进阶. Android 的 Native 开发 陈水德. NDK 简介 NDK 开发环境搭建 在应用程序中使用 JNI Native 与 Java 之间的沟通 MIPS 的 NDK 及开发环境. NDK 简介. NDK 简介. 关于 NDK Android 提供的工具,方便应用程序嵌入 native 代码 . 目前基本上支持 c, c++ 和 assembly 的 native 开发 目标以动态链接库 so 的形式提供给应用程序 要求系统有 SDK , NDK 不能开发应用程序,附着于 SDK

berg
Télécharger la présentation

Android 应用程序开发进阶

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Android应用程序开发进阶 Android 的Native开发 陈水德

  2. NDK简介 • NDK开发环境搭建 • 在应用程序中使用JNI • Native与Java之间的沟通 • MIPS的NDK及开发环境

  3. NDK 简介

  4. NDK简介 • 关于NDK • Android提供的工具,方便应用程序嵌入native代码. • 目前基本上支持c, c++和assembly的native开发 • 目标以动态链接库so的形式提供给应用程序 • 要求系统有SDK,NDK不能开发应用程序,附着于SDK • 包括交叉编译环境、文档和sample • NDK可简单看作Android源码编译环境的精简版 • 官方仅支持ARM指令系统 • ARMv5TE (including Thumb-1 instructions) • ARMv7-A (including Thumb-2 and VFPv3-D16 instructions, with optional support for NEON/VFPv3-D32 instructions)

  5. NDK简介 • 关于Android应用的Native开发 • 不管有没有NDK,由于dalvik支持jni,native开发一直被支持。 • jni不可开发Android可执行程序 • 不能扩展Android服务/功能等 • 不能扩展编/解码功能 • 不能扩展驱动 • 只是是应用程序的补充(运算方面及系统资源访问) • 对界面控制能力相当弱(弱到忽略不计) • 没有glibc,posix支持不完善,移植要注意. No SysV IPC

  6. NDK简介 • NDK提供的接口 • Bionic C库, openGL库和linux头文件 • Android-8(froyo)之前 • 仅能使用android的log (liblog) • Android-8 (froyo) • 增加了bitmap接口,jni可控制java bitmap类,在native端render界面。 • Android-9 增加了native_window • 增加了Native window接口 • 除NDK提供的接口外,不要用到其他任何android源码提供的系统接口 • Native的系统接口不保证版本一致性 • Native的系统接口没有强制要求厂商保持一致

  7. NDK 开发环境的搭建

  8. NDK开发环境搭建 • Software Requirement • 完全安装的SDK开发环境 • 至少要 android SDK 1.5版本 • Make 3.81版本之后

  9. NDK开发环境搭建 • Android NDK开发环境 • Windows • Windows XP (32-bit) or Vista (32- or 64-bit) • Cygwin 1.7(一定要安装devel包), 1.5版本不工作 • NDK 开发包(绿色,解压即可) • Linux • Linux (32- or 64-bit, tested on Linux Ubuntu Dapper Drake) • NDK开发包 • Mac OS • Mac OS X 10.4.8 or later (x86 only)

  10. 在应用程序中使用JNI

  11. 什么是JNI • JNI 是java native interface的简称 • JNI是定义java和java虚拟机之外的native代码的交流标准 • JNI可以让java直接访问系统,java通过解释器之后访问,非常慢! • JNI中,native代码的声明在java程序中,实现是放在C中。native实现的也是java类的方法 • 提供用另外一种语言实现java语言方法(method)的功能。

  12. 在应用程序中使用JNI

  13. 在应用程序中使用JNI Native线程

  14. 在应用程序中使用JNI • 在应用程序中使用JNI • 使用eclipse创建android应用程序 • 构建应用程序类,申明native方法 • 创建jni目录 • 编写native代码

  15. 在应用程序中使用JNI • JNIEnv JNI运行时环境 • JavaVM Java VM的handle

  16. 在应用程序中使用JNI • 创建JNI的androidapp • 1. 实现正常的android工程 • 2. 在java中声明native方法 • 3. 在C/c++中编写native方法的实现代码 • 4. 编译native代码,生成so库 • 5. java代码中加载 so库 • 6. 在java代码中调用native方法 • 7. 运行、调试

  17. 在应用程序中使用JNI • 编写java代码,声明native方法 publicclass HelloJni extends Activity { @Override publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); setContentView(tv); } publicnative String stringFromJNI(); }

  18. 在应用程序中使用JNI • Java方法和Native函数之间的对应关系 // Java code JniDemo.java package com.example.jnidemo; …… public native String stringFromJNI() /* native code */ Java_com_example_jnidemo_JniDemo_stringFromJNI( JNIEnv* env, jobject thiz ) { …… }

  19. 在应用程序中使用JNI • 编写native代码 • C的方式: #include <string.h> #include <jni.h> jstring Java_com_example_jnidemo_JniDemo_stringFromJNI( JNIEnv* env, jobject thiz ) { return (*env)->NewStringUTF(env, "Hello from JNI !"); }

  20. 在应用程序中使用JNI • 编写native代码 • C++的方式: #include <string.h> #include <jni.h> extern "C" jstring Java_com_example_jnidemo_JniDemo_stringFromJNI( JNIEnv* env, jobject thiz ) { return env->NewStringUTF("Hello from JNI !"); }

  21. 在应用程序中使用JNI • 编写native代码 • Jni Onload方式 extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { goto bail; } if (registerMethods(env) != 0) { goto bail; } result = JNI_VERSION_1_4; bail: return result; }

  22. 在应用程序中使用JNI • Java类型/C++类型 • Char为2字节 • Long为8字节 • 其他非内置数据类型的,都是object类型 • Java都是大端表示

  23. 在应用程序中使用JNI • Java 方法的符号标识 native String funcA(int i, double j, String s) 标识(signature):(IDLjava/lang/String;)Ljava/lang/String; native void funcB(int[] k, String[] s) 标识(signature):([I[Ljava/lang/String;)V native void funcC() 标识(signature):()V

  24. 在应用程序中使用JNI • 编译 • Application.mk • make APP=<project directory name> • 生成的库放在 <project dir>/libs/<abi>/<lib>.so • Java加载动态库 static { System.loadLibrary("jni-demo"); } static { System.load(“<path>/libjni-demo.so"); }

  25. 在应用程序中使用JNI • 加载so,调用native方法 publicclass HelloJni extends Activity { @Override publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setText( stringFromJNI() ); setContentView(tv); } publicnative String stringFromJNI(); static { System.loadLibrary("jni-demo"); } }

  26. 在应用程序中使用JNI • 使用Native的注意事项 • 没有glibc • 没有native的window system(如GTK) • 不包括全部的linux utilities • Bionic • 小而精炼(换句话说:健壮性不强) • 快速pthread实现(健壮性不强) • 内置了android的服务系统(如log,property) • 只支持posix的部分功能 • so在应用程序中扮演的是资源角色 • 应用程序不检验合法性 • Native和java之间的对应关系不作判断

  27. Native与java之间的沟通(Invocation API)

  28. Invocation API • Native端需要获取的信息 • Class (jclass) • 类型的定义。通常也就是class文件描述的信息。 • Object (jobject) • Class的实例,通常都是分配在堆上的。 • Filed (jfieldID) • Class的数据成员 • Method (jmethodID) • Class的方法(成员函数) • JNIEnv JNI运行时环境,提供invocation API

  29. Invocation API • 访问java String /* DO NOT USE jstring THIS WAY !!! */ string Java_Test_getLine(JNIEnv *env, jobject obj, jstring jstr) { printf("%s", jstr); } jstring Java_Test_getLine(JNIEnv *env, jobject obj, jstring jstr) { char buf[128]; const char *str = (*env)->GetStringUTFChars(env, jstr, 0); printf("%s", str); (*env)->ReleaseStringUTFChars(env, prompt, str); scanf("%s", buf); return (*env)->NewStringUTF(env, buf); }

  30. Invocation API • 访问java Array /* This program is illegal! */ jint Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr) { int i, sum = 0; for (i=0; i<10; i++) sum += arr[i]; } jint Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr) { int i, sum = 0; jsize len = (*env)->GetArrayLength(env, arr); jint *body = (*env)->GetIntArrayElements(env, arr, 0); for (i=0; i<len; i++) sum += body[i]; (*env)->ReleaseIntArrayElements(env, arr, body, 0); return sum; }

  31. Invocation API • JNI调用java方法 public class CallBacks { ……… public void callback() {……} } JNIEXPORT void JNICALL Java_Callbacks_nativeMethod(JNIEnv *env,jobject obj,jint depth) { jclass cls = (*env)->GetObjectClass(env, obj); jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "(I)V"); if (mid == 0) return; printf("In C, depth = %d, about to enter Java\n", depth); (*env)->CallVoidMethod(env, obj, mid, depth); printf("In C, depth = %d, back from Java\n", depth); }

  32. Invocation API • JNI访问java数据成员(field) // java code ……… int si = …… String s = “………”; ……… /* native code */ ……… jint si; jstring jstr; fid = (*env)->GetStaticFieldID(env, cls, "si", "I"); fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;"); si = (*env)->GetStaticIntField(env, cls, fid); jstr = (*env)->GetObjectField(env, obj, fid); ………

  33. JNI的异常处理 ……… jclass cls = (*env)->GetObjectClass(env, obj); jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V"); jthrowable exc; if (mid == 0) return; (*env)->CallVoidMethod(env, obj, mid); exc = (*env)->ExceptionOccurred(env); if (exc) { jclass newExcCls; (*env)->ExceptionDescribe(env); (*env)->ExceptionClear(env); newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); if (newExcCls == 0) /* Unable to find the new exception class, give up. */ return; (*env)->ThrowNew(env, newExcCls, "thrown from C code"); } 捕获异常 处理异常 Create Exception Throw new exception

  34. Invocation API • 局部和全局引用 /* This code is illegal */ static jclass cls = 0; static jfieldID fld; JNIEXPORT void JNICALL Java_FieldAccess_accessFields(JNIEnv *env, jobject obj) { ... if (cls == 0) { cls = (*env)->GetObjectClass(env, obj); if (cls == 0) ... /* error */ fid = (*env)->GetStaticFieldID(env, cls, "si", "I"); } ... /* access the field using cls and fid */ }

  35. Invocation API • 局部和全局引用 /* This code is OK */ static jclass cls = 0; static jfieldID fld; JNIEXPORT void JNICALL Java_FieldAccess_accessFields(JNIEnv *env, jobject obj) { ... if (cls == 0) { jclass cls1 = (*env)->GetObjectClass(env, obj); if (cls1 == 0) ... /* error */ cls = (*env)->NewGlobalRef(env, cls1); if (cls == 0) ... /* error */ fid = (*env)->GetStaticFieldID(env, cls, "si", "I"); } ... /* access the field using cls and fid */ }

  36. Invocation API • 线程同步 • sychronize(obj) { // critical section } • (*env)->MonitorEnter(env, obj); // critical section (*env)->MonitorExit(env, obj);

  37. MIPS的NDK及开发环境

  38. Mips NDK 下载 • http://mipsandroid.org/projects/show/mips-android-public

  39. MIPS NDK与Android NDK的差异 • 1. mips写了一个java gui界面,配置运行更简单 • 2. 使用mips的交叉编译环境

  40. 1. 安装Mips NDK • 和android NDK一样 • 需要安装JDK

  41. 源码开发环境 • 下载源码 • 编译源码 • 添加模块 • 启动模拟器

  42. Mips Android 环境编译 export TARGET_ARCH=mips source build/envsetup.sh export TARGET_ARCH_VERSION=mips32r2 export TARGET_CPU_ENDIAN=EL

  43. Thanks!

More Related