2016-04-14 10:48:21 lvshaorong 阅读数 698

关于如何搭建Android NDK开发环境,并编译出相应的.so文件和jar包,请参阅我之前写的一篇文章eclipse配合Android Studio部署Android NDK开发环境

如果自己编写好了.so库,那么如何连同jar包引入Android Studio,就是本次所要讨论的问题

百度了好多办法都没啥用,最后从老项目中找到的解决办法

首先在main文件夹下新建一个文件夹jniLibs,与java文件夹并列,把.so文件放到armeabi文件夹下

同样在main下面再建一个libs文件夹,把刚刚生成的jar包拖进来


右击这个jar包,点击add to libraries


add 成功之后,build.gradle会多出一行

compile files('src/main/libs/AlxNdk.jar')
完整的build.gradle如下

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.example.administrator.jnidemo"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }



    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

}


dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.0'
    compile 'com.android.support:design:23.2.0'
    compile files('src/main/libs/AlxNdk.jar')
}

这样我们就可以在Andorid Studio直接调用这个native方法了,比如

TextView tv1 = (TextView) findViewById(R.id.tv1);
tv1.setText(""+JNIUtils.getStringFromC(20,30));


2013-07-24 15:29:47 jiuyueguang 阅读数 16794

0:前言:

  1. 在第二篇中,我们主要介绍了丙方android公司利用乙方C++公司给的动态库,直接调用库中的方法,但是这样方式受限于:
    1. 乙方C++公司开发的动态库是否符合jni的规范,如果不规范,则不能直接调用
    2. 如果丙方android公司哪一天老板脑瓜抽筋说:“擦,咱们利用乙方C++公司给的库基础上再包装一下,再添加我们公司业务的新功能,打包成库,我们也卖!!!!”这种情况下不能直接调用乙方给的库了
    3. 有的库只是实现了基本的业务逻辑,更加复杂的需要调用库中的函数来实现
  2. 在本篇中,我们整合第三方库到我们自己的库中,详情请看下面

[第一篇:android调用第三方库——编写库libhello.so]

[第二篇:android调用第三方库——编写库android程序直接调用第三方库libhello.so]

[第三篇:android调用第三方库——编写库android程序整合第三方库libhello.so到自己的库libhelloword.so]

[第四篇:android调用第三方库——调用多个第三方库的写法]

1:搞起:

  1. 同样也是从新建helloword的android程序开始,和第一篇中步骤一样,这里不再多说了,主要是内容不一样,我会贴出代码和解释
  2. 在jni文件夹中新建文件夹hello,在hello中新建include,hello放libhello.so,include中放头文件com_hello_hello_HelloActivity.h
  3. 结构如图
  4. src目录下有两个包,分别是
    com.hello.hello
    com.hello.word
  5. com.hello.hello包中HelloActiviry.java中的代码
    package com.hello.hello;
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.os.Bundle;
    
    public class HelloActivity  {
    //	static
    //	  {  
    //	      System.loadLibrary("hello");  
    //	  }
    	public static native String sayHello(); // 第三方库函数
      
    }
  6. com.hello.word包中HellowordActiviry.java中的代码,这个Activity是我们的android主程序
    package com.hello.word;
    
    import com.hello.hello.HelloActivity;
    
    import android.app.Activity;
    import android.app.AlertDialog;
    import android.os.Bundle;
    
    public class HellowordActivity extends Activity {
    	static{  
    	    System.loadLibrary("hello");  //注意这里要引入两个包
    	    System.loadLibrary("helloword");  
    	}
    	public static native String sayHelloWord(); // 本地库函数
    	public static native String sayHello(); // 本地库函数
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            new AlertDialog.Builder( this ).setMessage( new HelloActivity().sayHello()).show();//这个是测试android直接调用库函数
          //  new AlertDialog.Builder( this ).setMessage( sayHelloWord()).show();//这个是测试android调用我们自己的包
         //   new AlertDialog.Builder( this ).setMessage( sayHello()).show();//这个是测试android调用我们自己的包整合第三方包后的调用函数
        }
    }
  7. 同样经过javah命令(不明白的地方请去看第一篇)生成头文件
  8. 自己的头文件com_hello_word_HellowordActivity.h代码,明显是自己的两个接口,
    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_hello_word_HellowordActivity */
    
    #ifndef _Included_com_hello_word_HellowordActivity
    #define _Included_com_hello_word_HellowordActivity
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_hello_word_HellowordActivity
     * Method:    sayHelloWord
     * Signature: ()Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_hello_word_HellowordActivity_sayHelloWord
      (JNIEnv *, jclass);
    
    /*
     * Class:     com_hello_word_HellowordActivity
     * Method:    sayHello
     * Signature: ()Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_hello_word_HellowordActivity_sayHello
      (JNIEnv *, jclass);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    
  9. helloword.cpp代码,这个文件主要用来实现上述头文件中的接口函数,
    #include <string.h>
    #include <jni.h>
    #include "com_hello_word_HellowordActivity.h"
    #include "com_hello_hello_HelloActivity.h"//注意要引入第三方库的头文件
    /*
     * Class:     com_hello_word_HellowordActivity
     * Method:    sayHello
     * Signature: ()Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_hello_word_HellowordActivity_sayHelloWord
      (JNIEnv *env, jclass) {
         //dosomething else
        return env->NewStringUTF("helloword");
    }
    
    /*
     * Class:     com_hello_word_HellowordActivity
     * Method:    sayHello
     * Signature: ()Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_hello_word_HellowordActivity_sayHello
      (JNIEnv *env, jclass thiz){
        //dosomething else
        return Java_com_hello_hello_HelloActivity_sayHello(env,thiz);//在我们自己的库函数中调用第三方库函数
    }
    jint JNI_OnLoad(JavaVM* vm, void* reserved) {
        JNIEnv* env = NULL;
        jint result = -1;
        if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
            return result;
        }
        return JNI_VERSION_1_4;
    }
    
    
    
    1. 注意引入头文件
    2. 在我们自己的库函数中调用第三方库,可扩展性增大
  10. Adnroid.mk代码,这个代码需要注意
    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE := hello  
    LOCAL_SRC_FILES := hello/libhello.so		
    LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/hello/include
    include $(PREBUILT_SHARED_LIBRARY)  
    
    include $(CLEAR_VARS)
    LOCAL_MODULE    := helloword
    LOCAL_SRC_FILES := helloword.cpp
    LOCAL_SHARED_LIBRARIES := libhello
    LOCAL_LDLIBS := -llog
    include $(BUILD_SHARED_LIBRARY)
    

    1. 运行测试android程序直接调用第三方库方式
       new AlertDialog.Builder( this ).setMessage( new HelloActivity().sayHello()).show();
    2. 运行测试android直接调用自己库方式
       new AlertDialog.Builder( this ).setMessage( sayHelloWord()).show();
    3. 运行测试android直接调用自己库方式,但是我们的库调用了第三方库,在我们的库中对第三方库进行了包装,实现了我们自己的逻辑
       new AlertDialog.Builder( this ).setMessage( sayHello()).show();







2:下载demo[猛戳这里下载demo


2016-06-04 22:14:23 huil0925 阅读数 1247

最近项目中需要使用到NDK编译so库,控制硬件。由于不熟悉JNI和NDK,网上搜了一些方法,做个笔记备忘和分享给用需要的朋友。

那如何用Android Studio编写JNI代码,然后生成so库呢?

来看看一个简单的实例: 编写一个native的加法函数,然后在MainActivity中调用并显示结果。

需要准备的事:
1 配置好的JDK环境和Android Studio开发环境、SDK
2 下载好NDK工具 (http://www.androiddevtools.cn/ 网站有很多Android开发需要的工具。)
NDK版本


1 新建Android工程

2 添加一个类,类中包含你想用C/C++语言实现的native方法,只是声明。
MyJni.java


package com.example.hui.myjnitest ;

public class MyJni {

    static {
        System.loadLibrary ("myjni" ) ;
    }

    public native int add (int a , int b) ;
}

其中有个静态代码块,在MyJni类加载时,执行块内代码。
System.loadLibrary (“myjni” ) ; 程序运行时,加载库文件,在Android(Linux)中,会搜索并加载名字为libmyjni.so的文件,如果找不到,会报异常。在Windows中会搜索myjni.dll的库

3 调用native方法

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate (Bundle savedInstanceState) {
        super .onCreate(savedInstanceState) ;
        setContentView(R.layout. activity_main );

        MyJni myJni = new MyJni();
        Toast. makeText( this, "1+3=" + myJni.add( 1 , 3 ) , Toast. LENGTH_LONG).show() ;
    }
}

MyJni myJni = new MyJni(); 获得具有native方法的类对象,然后调用该对象的方法myJni.add( 1 , 3)计算1+3的结果。

4 编译工程
Build–Make Project

5 生成jni的头文件
打开Android Studio的Terminal编辑器,一般在软件底部,如果找不到,可以按快捷键 Alt+F12 打开 (我的AS版本:2.1.1)
Terminal
切换到classes所在目录:
用到的命令: cd 切换路径, dir 显示文件夹内容列表

cd app\build\intermediates\classes\debug

debug目录下的路径跟包名有关,比如本例中的AndroidManifest.xml中声明的包名为

package= "com.example.hui.myjnitest"

那本例中的”.java”文件生成的.class”就在 debug\com\example\hui\myjnitest\下 (切换到该目录下看看)

2016/06/04  19:37               732 BuildConfig.class
2016/06/04  19:37             1,056 MainActivity.class
2016/06/04  19:37               454 MyJni.class
              17 个文件         76,243 字节                                                                                                                                           
               2 个目录 144,080,855,040 可用字节                                                                                                                                     
E:\MyGit\MyJniTest\app\build\intermediates\classes\debug\com\example\hui\myjnitest>

我们只用到MyJni.class文件。

好了,了解这些后,我们应该生成头文件了。(生成头文件干嘛?后面你就知道了)


在app\build\intermediates\classes\debug目录下执行

javah -classpath . -jni com.example.hui.myjnitest.MyJni

javah 用于生成头文件(*.h) (我暂时只了解这个用途)
-classpath . 有个圆点。表示设置class路径为当前路径。如果不在debug这个路径,那这个圆点可以换成具体路径
-jni 生成 JNI 样式的标头文件 (默认值)
com.example.hui.myjnitest.MyJni 包名+类名,注意不要带 .java,否则会报错的。


执行完命令,Terminal没有任何提示,在debug目录下,输入dir命令,可以看到有个 .h 文件,名字好长,其实就是把上面包名+类名中间的点换成下划线了。

来看看这个头文件都写了什么

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_hui_myjnitest_MyJni */

#ifndef _Included_com_example_hui_myjnitest_MyJni
#define _Included_com_example_hui_myjnitest_MyJni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_hui_myjnitest_MyJni
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_example_hui_myjnitest_MyJni_add
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

这其中的 Java_com_example_hui_myjnitest_MyJni_add 就是我们需要实现的native方法。
其他部分我就不多说了,可以百度一下,google一下。。。C语言的知识。

6 新建一个名为jni的文件夹
在工程目录app\src\main\下,新建一个jni文件夹,把上面步骤的h头文件复制到jni文件夹里。
工程目录更新为:
这里写图片描述
在jni文件夹中添加一个c语言源代码文件,如myjni.c,并完成其内容。函数名从头文件中复制过来,稍作修改。(知道头文件的作用了吧)

#include "com_example_hui_myjnitest_MyJni.h"

jint JNICALL Java_com_example_hui_myjnitest_MyJni_add
  (JNIEnv *env, jobject obj , jint a , jint b)
{
    return a+b ;
}

7 再次编译工程
Build – Project
这时 Message 窗口会提示需要设置使用当前NDK。打开gradle.properties, 在最下面粘贴上 android.useDeprecatedNdk=true

Error:Execution failed for task ‘:app:compileDebugNdk’.

Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set “android.useDeprecatedNdk=true” in gradle.properties to continue using the current NDK integration.

NDK

Build – Project
提示没有配置NDK选项
这里写图片描述

8 配置NDK
Android Studio中,菜单 File – Project Structure SDK Location 选择NDK路径
这里写图片描述

在build.gradle(Module:app)中完成

android{
defaultConfig {
     ndk {
          moduleName "xxx"   // 目标名称,不包括lib   .so
          ldLibs "xx","xx"     // jni代码中引用的库文件,本例没有引用
          abiFilters "", "", "", ""   // 生成不同平台下的so库
     }
   }
}

相当于一个Android.mk文件。
这里写图片描述

9 再次Build–Rebuild Project
没有报错则生成了so库。这个so库路径在

app\build\intermediates\ndk\debug\lib

这里写图片描述这里写图片描述

10 生成APK,用解压工具查看,apk内部有个lib文件夹,如下图所示。
这里写图片描述

11 在模拟器中安装并运行。
Toast显示的是正确调用so库运行的结果。
这里写图片描述

代码地址:https://github.com/BrightLin/MyJniTest
参考播客地址:http://blog.csdn.net/sodino/article/details/41946607 感谢作者 Sodino

提示:
如果编译时报错:需要在jni文件夹中添加一个空文件,名字为util.c

Error:Execution failed for task ‘:app:compileDebugNdk’. > com.android.ide.common.internal.LoggedErrorException: Failed to run command: D:\Mission\adt-bundle-windows\ndk-r10b\ndk-build.cmd NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=C:\Users\sodinochen\AndroidstudioProjects\JniTest2\app\build\intermediates\ndk\debug\Android.mk APP_PLATFORM=android-21 NDK_OUT=C:\Users\sodinochen\AndroidstudioProjects\JniTest2\app\build\intermediates\ndk\debug\obj NDK_LIBS_OUT=C:\Users\sodinochen\AndroidstudioProjects\JniTest2\app\build\intermediates\ndk\debug\lib APP_ABI=armeabi,armeabi-v7a,x86 Error Code: 2 Output: make.exe: * No rule to make target C:\Users\sodinochen\AndroidstudioProjects\JniTest2\app\build\intermediates\ndk\debug\obj/local/armeabi/objs/JniTest/C_\Users\sodinochen\AndroidstudioProjects\JniTest2\app\src\main\jni', needed byC:\Users\sodinochen\AndroidstudioProjects\JniTest2\app\build\intermediates\ndk\debug\obj/local/armeabi/objs/JniTest/C_\Users\sodinochen\AndroidstudioProjects\JniTest2\app\src\main\jni\main.o’. Stop.

2016-09-22 19:06:43 sinat_19385391 阅读数 19148

      Android NDK开发中,除了可以通过自己编写C/C++代码来构建动态连接库进行调用之外,还可以通过直接调用现成的so库开进行NDK开发。接下来,我将介绍在Android Studio中如何调用第三方动态连接库。

    首先需要考虑的是如何获得so库文件,这里介绍自己编译生成的方法。
    在该项目的基础上http://blog.csdn.net/sinat_19385391/article/details/52294711 ,对该项目进行Build->Make Project操作,在相应的目录下就会生成so文件,具体路径如下图:
这里写图片描述
在需要使用该第三方so库文件的项目的src/main目录下,新建jniLibs目录,将刚才得到的so库复制到jniLibs目录下,如图所示:
这里写图片描述
也可以直降将第三方so文件复制到libs目录下,此时需要在app下的build.gradle文件中的buildTypes下添加如下代码:sourceSets{
main{
jniLibs.srcDirs = ['libs']
}
}

然后在项目中的MainActivity中加载库,生命需要调用的native方法即可:

这里写图片描述
需要注意的时,加载动态连接库的文件所在的包名必须和so库的包名一致!也就是说要和
http://blog.csdn.net/sinat_19385391/article/details/52294711该项目中的包名一致!
最后将调用native方法所得到的结果显示到页面上查看效果如下图:
这里写图片描述
因为调用的是同一个动态库中的同一个方法,所以返回的结果是一样的,都是hello,NDK!
至此,Android Studio中的Android项目调用第三方库so库的相关内容就介绍的差不多了,文中有什么不周到或者错误的地方欢迎读者指正,谢谢。

2018-05-30 17:32:32 Jason__K 阅读数 490

文章主要目的用作记录生成so库及串口JNI的调用方法

参考博客https://www.jianshu.com/p/a37782b56770

主要有四个步骤:

一、编写需要调用的JNI接口的JAVA类,通过JAVA类生成相对应的.h头文件

二、编写Android.mk和Application.mk,通过实现.h的c++文件与头文件生成对应的so库


最终效果图如下:


1、其中JAVA类SerialPort调用JNI,通过它生成skyworth_native_class_offcialseal_SerialPort.h头文件

2、SerialPort.cpp为实现头文件里的具体函数

3、libs底下为通过Android.mk和Application.mk生成的so库


具体详细过程可看参考博客,写得很详细。








没有更多推荐了,返回首页