• 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)
    


    
    
  • 相关阅读:
    visual studio 2008 在调试的时候出现无法启动程序错误时什么原因
    android illegallstateexception:get field slot from row 0 col 1 failed
    android activity has leaked window phonewindow
    the content of the adapter has changed but listview did not
    android create table android_metadata failed
    豌豆荚 软件 android 550 that path is inaccessible sdcard
    android nullpointerexception println needs a message
    android sqlite3 乱码
    android unable to instantiate activity componentinfo
    android.database.sqlite.SQLiteExcepption: near ">":syntax error:,while compiling:
  • 原文地址:https://www.cnblogs.com/lytwajue/p/7115866.html
Copyright © 2020-2023  润新知