• Android之Windows下生成动态库so并打包到APK中


    Android内核是Linux的,而linux的动态库是*.so文件,那么在windows要如何生成并打包到APK中呢?实现这一过程,大致需要以下几个步骤:

    1、搭建编译环境

    2、使用JNI生成相应的头文件

    3、编写动态库的实现

    4、生成动态库

    5、编译调用动态库的代码

    6、动态库打包到APK中

    7、测试

    下面就依据这些步骤一一进行实现。

    1、搭建编译环境

    要生成*.so的动态库文件,需要有交叉编译的环境,这个可以在Linux下搭建,在windows下也同样可以。在Windows下需要借助Sourcery CodeBench Lite Edition for ARM,这个可以直接到官网上下载(可能需要注册帐号),这里是地址https://sourcery.mentor.com/sgpp/lite/arm/portal/subscription?@template=lite,进入后选择GNU/Linux,如下图。


    选择Sourcery CodeBench Lite 2013.11-33,进入下面的页面。


    下载完后,直接安装,按照提示一路下一步。安装的路径最好不要放在有空格或者含中文的路径下,比如默认文件夹Program Files就是带空格的,这样的路径有可能会影响命令的执行。我是安装到D:Sourcery_CodeBench_Lite_for_ARM_GNU_Linux。

    安装完成后,将安装目录下的bin设置到环境变量中,即D:Sourcery_CodeBench_Lite_for_ARM_GNU_Linuxin。


    设置了环境变量后,才能方便调用这些exe。

    2、使用JNI生成相应的头文件

    (1)、在Eclipse中新建一个Android工程,命名为DynamicLibTest,名包为com.example.dlt,新建一个调用动态库的类NativeJniAdder.java,代码如下

    package com.example.dlt;
    
    import android.util.Log;
    
    public class NativeJniAdder {
    	static 
    	{
    		try {
    			Log.i("JNI", "Trying to load libNativeJniAdder.so");
    			System.loadLibrary("NativeJniAdder");
    			
    		} catch (UnsatisfiedLinkError ule) {
    			Log.e("JNI", "WARNING:Gould not load libNativeJniAdder.so");
    		}
    	}
    	
    	public static native int calculate(int digit_1,int digit_2);
    }
    
    注:System.loadLibrary就是加载动态库的代码,动态库只写lib和.so之间的名称,这个与Windows下调用dll不太一样。比如动态库为libNativeJniAdder.so,那么在loadLibrary时就是NativeJniAdder.

    (2)、使用javah来生成头文件(javah需要安装JDK)。

    在DynamicLibTest的工程下增加一个libcode文件夹,在该文件夹下添加一个生成头文件的genHeader.bat,代码如下:

    javah -classpath ../src com.example.dlt.NativeJniAdder
    执行该,将会生成一个com_example_dlt_NativeJniAdder.h的头文件。


    打开该头文件会看到如下的代码:

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_example_dlt_NativeJniAdder */
    
    #ifndef _Included_com_example_dlt_NativeJniAdder
    #define _Included_com_example_dlt_NativeJniAdder
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_example_dlt_NativeJniAdder
     * Method:    calculate
     * Signature: (II)I
     */
    JNIEXPORT jint JNICALL Java_com_example_dlt_NativeJniAdder_calculate
      (JNIEnv *, jclass, jint, jint);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    
    注:该头文件的代码不要去修改。


    3、编写动态库的实现

    依据生成的头文件com_example_dlt_NativeJniAdder.h实现,代码如下:

    com_example_dlt_NativeJniAdder.c

    #include "com_example_dlt_NativeJniAdder.h"
    
    JNIEXPORT jint JNICALL Java_com_example_dlt_NativeJniAdder_calculate(JNIEnv *env,
    		jclass c, jint digit_1, jint digit_2) {
    	int sum=digit_1+digit_2;
    	return sum;
    }
    
    4、生成动态库

    (1)、生成*.o的中间文件,编写脚本compile.bat,内容如下

    arm-none-linux-gnueabi-gcc -I D:Javajdk7include -I D:Javajdk7includelinux -fpic -nostdlib -c com_example_dlt_NativeJniAdder.c
    注:

    1)、需要安装JDK,而且JDK建立安装在无空格且不含中文的目录下,我是安装在:Java下。执行该脚本后,将会生成com_example_dlt_NativeJniAdder.o。

    2)、windows下安装jdk,在include下会有一个win32的文件夹,这里需要用到liunx的文件夹(该文件夹是在linux下安装jdk产生的),该文件夹可以从liunx下复制过来。或者建一个liunx文件夹,在下面增加jawt_md.h和jni_md.h文件,其内容如下:

    jawt_md.h

    /*
     * %W% %E%
     *
     * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
     * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     */
    
    #ifndef _JAVASOFT_JAWT_MD_H_
    #define _JAVASOFT_JAWT_MD_H_
    
    #include <X11/Xlib.h>
    #include <X11/Xutil.h>
    #include <X11/Intrinsic.h>
    #include "jawt.h"
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    /*
     * X11-specific declarations for AWT native interface.
     * See notes in jawt.h for an example of use.
     */
    typedef struct jawt_X11DrawingSurfaceInfo {
        Drawable drawable;
        Display* display;
        VisualID visualID;
        Colormap colormapID;
        int depth;
        /*
         * Since 1.4
         * Returns a pixel value from a set of RGB values.
         * This is useful for paletted color (256 color) modes.
         */
        int (JNICALL *GetAWTColor)(JAWT_DrawingSurface* ds,
            int r, int g, int b);
    } JAWT_X11DrawingSurfaceInfo;
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif /* !_JAVASOFT_JAWT_MD_H_ */
    
    jni_md.h

    /*
     * %W% %E%
     *
     * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
     * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     */
    
    #ifndef _JAVASOFT_JNI_MD_H_
    #define _JAVASOFT_JNI_MD_H_
    
    #define JNIEXPORT 
    #define JNIIMPORT
    #define JNICALL
    
    typedef int jint;
    #ifdef _LP64 /* 64-bit Solaris */
    typedef long jlong;
    #else
    typedef long long jlong;
    #endif
    
    typedef signed char jbyte;
    
    #endif /* !_JAVASOFT_JNI_MD_H_ */

    (2)、检验*.o文件

    cmd中定位到com_example_dlt_NativeJniAdder.o所在的目录,然后输入

    arm-none-linux-gnueabi-ld com_example_dlt_NativeJniAdder.o
    这时会看到如下图的画面,提示警告。如果提示有error的,说明编译出问题了。

    (3)、生成*.so的中间文件,编写脚本genSo.bat,内容如下

    arm-none-linux-gnueabi-ld -T D:Sourcery_CodeBench_Lite_for_ARM_GNU_Linuxarm-none-linux-gnueabilibldscriptsarmelf_linux_eabi.xsc -shared -o ..libsarmeabilibNativeJniAdder.so com_example_dlt_NativeJniAdder.o
    注:

    1)、D:Sourcery_CodeBench_Lite_for_ARM_GNU_Linux是Sourcery_CodeBench_Lite_for_ARM_GNU_Linux的安装路径,需依据实际的安装路径进行修改。

    2)、在DynamicLibTest工程下的libs文件夹下增加armeabi文件夹,如果libs没有,可以自行增加。

    3)、生成的动态库文件的名字必须是以lib开头、以.so作为后缀的,如libNativeJniAdder.so。否则放到Android中将会识别不了。

    执行脚本后,将会在armeabi文件夹下生成一个libNativeJniAdder.so的动态库文件,见下图。


    5、编译调用动态库的代码

    在DynamicTest工程的MainActivity.java中调用动态库。

    package com.example.dlt;
    
    import android.app.Activity;
    import android.os.Bundle;
    
    import com.example.sumcalculator.R;
    
    public class MainActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.main_activity);
    
    		int digit_1 = 8, digit_2 = 9;
    		int sum = NativeJniAdder.calculate(digit_1, digit_2);
    
    		setTitle("[" + sum + "]");
    	}
    
    }
    

    6、动态库打包到APK中

    将*.so的动态库文件打包到APK中时,如果是在eclipse环境中,必须要在工程下的libs文件夹下增加一个armeabi文件夹(eabi:Embedded application binary interface, 即嵌入式应用二进制接口),然后正常编译生成apk即可。

    在编译生成apk后,可以将apk解开,然后可以看到在lib文件夹下会有一个armeabi的文件夹,里面含有我们打包进去的动态库文件。


    注:也可以通过adb push *.so systemlib的方式,将*.so放到systemlib下,以供调用。但是这个过程,并不是所有手机都可以的。比如小米就不行,会被挡掉。如果使用这个命令来做,还有可能会出现only read file system的错误,这时可以先执行adb remount,然后再adb push *.so systemlib。adb remount这个命令在小米中同样会被挡掉。

    所以要怎么用,需自行斟酌。

    7、测试

    将apk安装到手机中,然后执行。在代码中我们执行的是8+9,所以预期的结果是[17]。测试结果如下图。


    转载请注明出处:《Android之Windows下生成动态库并打包到APK中

    源码下载

  • 相关阅读:
    微信小程序组件loading
    微信小程序组件toast
    微信小程序组件modal
    Thread was being aborted.
    Linux(Contos7.5)环境搭建之Linux远程登录(一)
    Method 'ExecuteAsync' in type 'System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy' does not have an implementation
    Cannot find class [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter]
    Visual Studio 调试时无法命中断点
    springjdbc使用c3p0连接池报错 java.lang.NoClassDefFoundError: com/mchange/v2/ser/Indirector
    JUnit initializationError错误
  • 原文地址:https://www.cnblogs.com/sparkleDai/p/7605017.html
Copyright © 2020-2023  润新知