zoukankan      html  css  js  c++  java
  • Ndk开发笔记

    <pre name="code" class="cpp">ndk开发:
    1.编译android本地程序的二种方法.q
    2.安装ndk编译工具.
    3.编写android.apk程序.
    4.编写jni接口.定义应用程序接口,
    5.编写Java文件,生成相应的字节码文件.
    6.使用javah -jni Test 命令生成该java文件相应的c的头文件.
    7.使用ndk-build命令生成相应的库文件.
    
    一:创建一个arm本地程序.直接使用arm-linux-gcc 进行编译,假设使用到库的话须要使用 -statickeyword进行静态链接库文件.
    
    1.编译android本地程序的三种方法:
    	1.使用ndk开发工具进行编译.
                a)安装ndk android-ndk-r9d-linux-x86_64.tar.bz2 使用tar -xvf android-ndk-r9d-linux-x86_64.tar.bz2.
    	    b)解压完毕须要配置环境变量: 
                  vim ~/.bashrc
    	      加入以下的行. export PATH=/home/zshh/android-ndk-r9d:$PATH    //这个是解压后ndk所在文件文件夹/home/zshh/android-ndk-r9d
    	    c)拷贝一个ndk的例子文件到測试文件夹.例子文件存在/home/zshh/android-ndk-r9d/samples中.
    	      $ cd /home/zshh/android-ndk-r9d/samples 下.
    	      $ cp -a hello-jni/ ~/work/android/JNI/
    	      $ zshh@HP:~/work/android/JNI/hello-jni/jni$ vim Android.mk 
                 
    	      LOCAL_PATH := $(call my-dir)     //    LOCAL_PATH 指的是要编译的文件夹. cd ~/work/android/JNI/hello-jni/ 使用ndk-build,该文件夹指的就是~/work/android/JNI/hello-jni/文件夹.
    	      include $(CLEAR_VARS)            //    使用ndk进行编译的时候.必须指定这项.它会清空Makefile中全部的变量值.使用android源码进行编译的时候,不能使用该项.
    	      LOCAL_MODULE    := hello-jni     //    编译完毕之后的模块的名称.
    	      LOCAL_SRC_FILES := hello-jni.c   //    生成模块须要的.c文件.
    
    	      //以下的是两者选其一.
    	      include $(BUILD_SHARED_LIBRARY)  //  指定生成什么样的文件.还是动态库文件.
     	      include $(BUILD_EXECUTABLE)      //  指定生成什么样的文件.是可运行文件
    	      
    	     改动一下hello-jni.c输出Hello字符.
    
    
    2.改动文件.生成可运行文件.
    	zshh@HP:~/work/android/JNI/hello-jni/jni$ vim hello-jni.c 
    		#if 0 #endif 凝视其它文件.
                    改动为例如以下:
    			#include <string.h>
    		        #include <jni.h>
    			int main(void)
    			{
    				printf("Hello
    ");
    				return 0 ;
    			}
                      
    	zshh@HP:~/work/android/JNI/hello-jni/jni$ ndk-build
            /home/zshh/work/android/JNI/hello-jni/jni/hello-jni.c:57:2: warning: incompatible implicit declaration of built-in function 'printf' [enabled by default]
     	进行编译会输出如上警告.是以为printf没有包括stdlib.h头文件.须要加入#include<stdlib.h>头文件.
    
    	zshh@HP:~/work/android/JNI/hello-jni/jni$ ndk-build  生成例如以下文件.
    
    	zshh@HP:~/work/android/JNI/hello-jni/jni$ ndk-build
    	[armeabi-v7a] Gdbserver      : [arm-linux-androideabi-4.6] libs/armeabi-v7a/gdbserver
    	[armeabi-v7a] Gdbsetup       : libs/armeabi-v7a/gdb.setup
    	[armeabi] Gdbserver      : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
    	[armeabi] Gdbsetup       : libs/armeabi/gdb.setup
    	[x86] Gdbserver      : [x86-4.6] libs/x86/gdbserver
    	[x86] Gdbsetup       : libs/x86/gdb.setup
    	[mips] Gdbserver      : [mipsel-linux-android-4.6] libs/mips/gdbserver
    	[mips] Gdbsetup       : libs/mips/gdb.setup
    	[armeabi-v7a] Install        : hello-jni => libs/armeabi-v7a/hello-jni
    	[armeabi] Install        : hello-jni => libs/armeabi/hello-jni
    	[x86] Install        : hello-jni => libs/x86/hello-jni
    	[mips] Install        : hello-jni => libs/mips/hello-jni
    	
    	他会编译生成三个平台的可运行文件,平台如上. x86,mips,armeabi-v7a,
    	
    3.改动编译生成指定平台的可运行文件.
          
          zshh@HP:~/work/android/JNI/hello-jni/jni$ vim Application.mk 
          APP_ABI := all  这个是生成支持的三种平台的可运行文件.
          APP_ABI := armeabi-v7a 仅仅会生成armeabi-v7a平台的可运行代码.
    
    4.将生成的文件下载到开发版运行.
          //开机进入系统仅仅会.检查usb是否插好.等待进入系统之后,运行挂载命令.是
          zshh@HP:~/work/android/JNI/hello-jni/jni$ adb shell mount -o remount,rw /system    //这个命令的作用又一次使用读写权限挂载这个文件.
          
          //切换到编译完毕的可运行文件所在文件夹.
          zshh@HP:$ cd ~/work/android/JNI/hello-jni/libs/armeabi-v7a
    
          zshh@HP:~/work/android/JNI/hello-jni/libs/armeabi-v7a$ adb push hello-jni  /system  //将应用程序下载到开发版的/system路径下.
          208 KB/s (9500 bytes in 0.044s)
         
    5.最后測试能否成功输出,Hello.
          zshh@HP:~/work/android/JNI/hello-jni/libs/armeabi-v7a$ adb shell       //通过android调试桥登入android操作系统.
          root@android:cd /system
          root@android:/system # ./hello-jni                                             
          Hello
          最后測试完毕.输出Hello.
    
    6.假设使用编译完毕的android源码进行编译的话.须要改动Android.MK文件,
    	
        a. 改动Android.mk
    	zshh@HP:~/work/android/JNI/hello-jni/jni$ vim Android.mk 
                  LOCAL_PATH := $(call my-dir)     //    LOCAL_PATH 指的是要编译的文件夹. cd ~/work/android/JNI/hello-jni/ 使用ndk-build,该文件夹指的就是~/work/android/JNI/hello-jni/文件夹.
    	      #include $(CLEAR_VARS)            //    这项须要凝视掉,它的作用是清除MK文件里变量的值.使用android源码编译时,不须要这样做.切记凝视.
    	      LOCAL_MODULE    := hello-jni     //    编译完毕之后的模块的名称.
    	      LOCAL_SRC_FILES := hello-jni.c   //    生成模块须要的.c文件.
    
    	      //以下的是两者选其一,指定生成什么样的文件.
    	      include $(BUILD_SHARED_LIBRARY)  // 这个是生成动态库文件.
     	      include $(BUILD_EXECUTABLE)      // 这个是生成可运行文件
    
    	zshh@HP$ cd /home/zshh/work/arm/ARM1/Android/android-4.2.2_r1
          
        b.设置当前shell的运行环境.
            zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1$ source ~/.bashrc
    	zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1$ source  setenv 
    	including device/asus/grouper/vendorsetup.sh
    	including device/asus/tilapia/vendorsetup.sh
    	including device/friendly-arm/tiny4412/vendorsetup.sh
    	including device/generic/armv7-a-neon/vendorsetup.sh
    	including device/generic/armv7-a/vendorsetup.sh
    	including device/generic/mips/vendorsetup.sh
    	including device/generic/x86/vendorsetup.sh
    	including device/lge/mako/vendorsetup.sh
    	including device/samsung/maguro/vendorsetup.sh
    	including device/samsung/manta/vendorsetup.sh
    	including device/samsung/toroplus/vendorsetup.sh
    	including device/samsung/toro/vendorsetup.sh
    	including device/ti/panda/vendorsetup.sh
    	including sdk/bash_completion/adb.bash
        
        c.使用mmm编译须要编译的文件夹.
    	zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1$ mmm ~/work/android/JNI/jni_source_build/jni/
    
    	   target Executable: hello-jni (out/target/product/tiny4412/obj/EXECUTABLES/hello-jni_intermediates/LINKED/hello-jni)
    	   /home/zshh/work/arm/ARM1/Android/android-4.2.2_r1/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6
    	    /bin/../lib/gcc/arm-linux-androideabi/4.6.x-google/../../../../arm-linux-androideabi/bin/ld: 
    	   out/target/product/tiny4412/obj/lib/crtbegin_dynamic.o: in function _start:crtbrand.c(.text+0x60): error: undefined reference to '__libc_init'
    	    
    	    假设出现的这个错误.那么须要做包括libc库, 
    	    LOCAL_SHARED_LIBRARIES :=libc
    	    加入完毕之后的Android.mk文件例如以下
    		      LOCAL_PATH := $(call my-dir)     //    LOCAL_PATH 指的是要编译的文件夹. cd ~/work/android/JNI/hello-jni/ 使用ndk-build,该文件夹指的就是~/work/android/JNI/hello-jni/文件夹.
    		      #include $(CLEAR_VARS)            //    这项须要凝视掉,它的作用是清除MK文件里变量的值.使用android源码编译时,不须要这样做.切记凝视.
    		      LOCAL_MODULE    := hello-jni     //    编译完毕之后的模块的名称.
    		      LOCAL_SRC_FILES := hello-jni.c   //    生成模块须要的.c文件.
    	              LOCAL_SHARED_LIBRARIES :=libc
    		      //以下的是两者选其一,指定生成什么样的文件.
    		      include $(BUILD_SHARED_LIBRARY)  // 这个是生成动态库文件.
    	 	      include $(BUILD_EXECUTABLE)      // 这个是生成可运行文件
    
    	    zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1$ mmm ~/work/android/JNI/jni_source_build/jni/'
    	    Install: out/target/product/tiny4412/system/bin/hello-jni
    		
    	   
    	  假设成功编译,生成的目标文件存在hello-jni文件out/target/product/tiny4412/system/bin/hello-jni
    	
    
        d.接下来的步骤,和步骤5.是一样的.
    
    
    二:创建一个NDK本地程序. 该程序的功能是控制led的亮灭.
       1.搭建一个eclipse环境.eclipse.tar.gz
         a.解压这文件.
           zshh@HP:~/work/android$ tar -xvf eclipse.tar.gz -C software   //解压
           zshh@HP:~/work/android$ cd software/eclipse/
           zshh@HP:~/work/android/software/eclipse$ ./eclipse &           //运行eclipse
         b.使用这个ide环境创建一个android apk应用程序. 
    	它大概的功能是提供四个button,当按下当中某个button的时候,就让某个灯亮起来.
         
    
          c.创建一个Test文件,当中包括接口文件例如以下:  
    	1.定义c和java之间的接口.控制亮灭,
    	  1.1.第一个接口应该是打开设备文件.
    		native int openLed();
    	  1.2.最后一个是关闭设备文件.
    		native int closeLed(); 
    	  1.3.第二个接口应该是亮,
    		native int ledOn(int no);
    	  1.4.第三个接口应该是灭. 
    		native int ledOff(int no);
    
    	2. 
             zshh@HP:~/work/android/JNI/NDKnative$ vim Test.java
    	 /*************************************************************************
    	    > File Name: Test.java
    	    > Author: zshh0604
    	    > Mail: zshh0604@.com 
    	    > Created Time: Mon 22 Dec 2014 10:48:09 PM
    	 ************************************************************************/
    	 public class Test
    	 {
    		native int openLed(); 
    		native int closeLed(); 
    		native int onLed(int no); 
    		native int offLed(int no);
    
    		static{
    			System.loadLibrary("led");
    		}
    
    		public static void main(String[] args)
    		{
    		
    		}
    	  }
    
    	3.编译生成字节码文件.
              zshh@HP:~/work/android/JNI/NDKnative$ javac Test.java    
    	
    	4.生成相应的头文件,该命令运行完毕之后.会生成Test.h头文件.
              zshh@HP:~/work/android/JNI/NDKnative$ javah -jni Test   
    	
    	5.拷贝一个NDK代码例子.并把Test.h头文件复制到当前文件的jni文件夹中.
    	  zshh@HP:~/work/android/JNI$ mkdir Jni
    	
    	6.获取ndk开发工具的代码例子.
    	  zshh@HP:~/work/android/JNI/Jni$ cp -a ../../../../android-ndk-r9d/samples/hello-jni/ ./
              zshh@HP:~/work/android/JNI/Jni/jni$ cp ../../NDKnative/Test.h
    	  
    	7.将Test.h改名为led.c, mv Test.h led.c
    	  zshh@HP:~/work/android/JNI/Jni/jni$ mv Test.h led.c
    	
    	8.获取apk应用的完整类名.com_embsky_MainActivity      //讲这个名称替换当前Test类名.
    	  使用vim打开led.c文件,再命令行模式下使用例如以下命令吧Test替换成com_embsky_MainActivity 
         	  
    	  :%s/Test/com_embsky_MainActivity/g.
    	  得到例如以下文件: 
    		#include <jni.h>
    		#include <sys/types.h>
    		#include <stdlib.h> 
    		#include <fcntl.h>
    		#include <errno.h>
    
    		static int fd;
    		static int flags = 0;
    		/*
    		 * Class:     com_embsky_MainActivity
    		 * Method:    openLed
    		 * Signature: ()I
    		 */
    		JNIEXPORT jint JNICALL Java_com_embsky_MainActivity_openLed
    		  (JNIEnv *env, jobject obj)
    		  {
    			if(flags == 0)
    			{
    				fd = open("dev/leds",O_RDWR);
    				if(fd< 0)
    				{
    					return -EPERM;
    				}
    				flags = 1;
    				return 0 ;
    			}
    			return -EBUSY;
    		  }
    
    		/*
    		 * Class:     com_embsky_MainActivity
    		 * Method:    closeLed
    		 * Signature: ()I
    		 */
    		JNIEXPORT jint JNICALL Java_com_embsky_MainActivity_closeLed
    		  (JNIEnv *env , jobject obj)
    		  {
    			if(flags == 1)
    			{
    				close(fd); 
    				flags = 0; 
    				return 0;
    			}
    			return -ENODEV;
    		  }
    
    		/*
    		 * Class:     com_embsky_MainActivity
    		 * Method:    onLed
    		 * Signature: (I)I
    		 */
    		JNIEXPORT jint JNICALL Java_com_embsky_MainActivity_onLed
    		  (JNIEnv *env , jobject obj, jint no)
    		  {
    			int ret; 
    			if(flags == 1)
    			{
    				ret = ioctl(fd,1 ,no); 
    				if(ret < 0 )
    				{
    					return -EPERM;
    				}
    				return 0 ;
    			}
    			return -ENODEV; 
    		  }
    
    		/*
    		 * Class:     com_embsky_MainActivity
    		 * Method:    offLed
    		 * Signature: (I)I
    		 */
    		JNIEXPORT jint JNICALL Java_com_embsky_MainActivity_offLed
    		  (JNIEnv * env, jobject obj, jint no)
    		  {
    			int ret; 
    			if(flags == 1)
    			{
    				ret = ioctl(fd, 0, no); 
    				if(ret < 0)
    				{
    					return -EPERM; 
    				}
    				return 0;
    			}
    			return -ENODEV;
    		  }
    
    
           9.改动Android.mk文件,例如以下:
    	LOCAL_PATH := $(call my-dir)
    	include $(CLEAR_VARS)
    	LOCAL_MODULE    := leds
    	LOCAL_SRC_FILES := led.c
    	include $(BUILD_SHARED_LIBRARY)
           
           10.zshh@HP:~/work/android/JNI/Jni/jni$ ndk-build
    
    
           11.生成动态库例如以下:[armeabi-v7a] Install : libleds.so => libs/armeabi-v7a/libleds.so
    
           12.将动态库push到开发板的/system/lib文件夹下.
              zshh@HP:~/work/android/JNI/Jni/libs/armeabi-v7a$ adb push libleds.so  /system/lib
    
           13.动态库制作完毕.
    	
           14.创建一个apk应用,创建一个类:  com.embsky.MainActivity.再这个类中载入并调用本地库led.
    
    
    	javah -d ../jni com.onesuncomm.JniCallCTest
    
    
    
    
    三: 使用android源码编译apk应用程序.System.loadLibaray("led"); 
            
            zshh@HP:~/work/android/android/07Jar/JniAndroidSrc$ ls
    	Android.mk  led.c
    	
    	使用这两个文件编译生成libled.so文件.
    
    	//zshh@HP:~/work/android/android/06Jni/JniAndroidSrc$ vim Android.mk。 
    	仅仅须要。Android.mk和led.c两个文件.
    
            1.使用android源码编译android应用程序, 
              LOCAL_PATH := $(call my-dir)
    	  LOCAL_MODULE    := libled         //注意必须是在led前面加上lib,编译生成的库名是.libled.so,使用	
    	  LOCAL_SRC_FILES := led.c            
    	  LOCAL_SHARED_LIBRARIES :=libc   
    	  include $(BUILD_SHARED_LIBRARY)    
    	
    	2.编译libled.so库文件.
    	  zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1$ source  setenv 
    	  zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1$ mmm ~/work/android/android/06Jni/JniAndroidSrc/
    	
    	3.输出编译完毕的路径例如以下.
    	  Install: out/target/product/tiny4412/system/lib/libled.so
    	4.将生成的libled.so push到/system/lib中.
    	 Install: out/target/product/tiny4412/system/lib/libled.so
    	 
    	zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1/out/target/product/tiny4412/system/lib$ adb push libled.so /system/lib/
    	115 KB/s (5276 bytes in 0.044s)
    
    	
    	5.生成Android fremework文件夹的 jar包。
    	  zshh@HP:~/work/android/android/07Jar/Jar$ ls
    	  Android.mk  com/embsky/Led.java              //包括两个java文件.
    	 
           	  package com.embsky;
    	  public class Led {
    		native int openLed();
    		native int closeLed();
    		native int ledOn(int no);
    		native int ledOff(int no);
    
    		static {
    			System.loadLibrary("led");
    		}
    
    		public int ledStart(){
    			/*nothing*/
    			return openLed();
    		}
    	
    		public int ledStop(){
    			return closeLed();
    		}	
    
    		public int ledOps(int no, int on){
    			if(on == 1){
    				return ledOn(no);
    			}
    	
    			return ledOff(no);
    		}
    	  }
    
    	6.改动Android.mk文件.
    	  LOCAL_PATH 			:=$(call my-dir)
    	  LOCAL_SRC_FILES		:=$(call all-subdir-java-files)  //当前src文件夹下的全部文件.
    	  LOCAL_MODULE			:=led
    	  LOCAL_JAVA_LIBRARIES	        :=
    	  include $(BUILD_JAVA_LIBRARY)                                 //包括这个生成的是Java的类库.
    	
    	7.完毕之后。能够编译生成这个.jar文件.
    	  zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1$ source  setenv 
              zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1$ mmm ~/work/android/android/07Jar/Jar/
           
    	8. 生成的jar包会存放在,
               Install: out/target/product/tiny4412/system/framework/led.jar
          注意编译的时候,该文件夹一定要由读写权限.否则会失败.
    	  假设由于权限问题。能够使用chown  zshh:zshh out/target/product/tiny4412/system/framework -R
    	  更改用户属主.
       	  生成完毕之后须要将这个framework下的led.jar放到开发版的/system/framework文件夹下.
    	    zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1/out/target/product/tiny4412/system/framework$ adb push led.jar  /system/framework/
    	    
    	9.须要改动开发板中 /etc/permissions   //再platform.xml文件里声明我们的框架库文件.否则这个led.jar无法使用.
             root@android:/etc/permissions # vim platform.xml  
    	 <library name="led" file="/system/framework/led.jar"/> 
         之后重新启动一下开发版,
    	
    
            10.编译android apk
    	  
                zshh@HP:~/work/android/android/07Jar/Apk$ ls  //apk包括例如以下文件和文件夹.
    	    AndroidManifest.xml  Android.mk  res  src
               
    	   须要改动AndroidManifest.xml文件.
    		<?xml version="1.0" encoding="utf-8"?>
    		<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    		    package="com.embsky"
    		    android:versionCode="1"
    		    android:versionName="1.0" >
    
    		    <uses-sdk
    			android:minSdkVersion="17"
    			android:targetSdkVersion="17" />
    
    		    <application
    			android:allowBackup="true"
    			android:icon="@drawable/ic_launcher"
    			android:label="@string/app_name"
    			android:theme="@style/AppTheme" >
    			<uses-library android:name="led" />                 //声明依赖的led.jar文件.假设不声明能够编译通过,但运行会由错误.
    			<activity
    			    android:name="com.embsky.MainActivity"
    			    android:label="@string/app_name" >
    			    <intent-filter>
    				<action android:name="android.intent.action.MAIN" />
    
    				<category android:name="android.intent.category.LAUNCHER" />
    			    </intent-filter>
    			</activity>
    		    </application>
    		</manifest>
                
               11.zshh@HP:~/work/android/android/07Jar/Apk$ gedit Android.mk 
    		LOCAL_PATH		:=$(call my-dir)
    		LOCAL_SRC_FILES		:=$(call all-subdir-java-files)
    		LOCAL_PACKAGE_NAME	:=Led
    		LOCAL_JAVA_LIBRARIES	:=led                           //注意这里必须声明依赖的java库.
    		include $(BUILD_PACKAGE)
            
                12.zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1$ mmm ~/work/android/android/07Jar/Apk/
    		这个是编译生成的apk文件Install: out/target/product/tiny4412/system/app/Led.apk
    		zshh@HP:~/work/arm/ARM1/Android/android-4.2.2_r1/out/target/product/tiny4412/system/app$ adb push Led.apk /system/app/
    		5099 KB/s (294516 bytes in 0.056s)
    


    
    
  • 相关阅读:
    LeetCode 258 Add Digits
    LeetCode 231 Power of Two
    LeetCode 28 Implement strStr()
    LeetCode 26 Remove Duplicates from Sorted Array
    LeetCode 21 Merge Two Sorted Lists
    LeetCode 20 Valid Parentheses
    图形处理函数库 ImageTTFBBox
    php一些函数
    func_get_arg(),func_get_args()和func_num_args()的用法
    人生不是故事,人生是世故,摸爬滚打才不会辜负功名尘土
  • 原文地址:https://www.cnblogs.com/lytwajue/p/7115866.html
Copyright © 2011-2022 走看看