Android Studio 3.0 JNI的实现

转自:https://blog.csdn.net/ziyoutiankoong/article/details/79696279

当前环境: 
android studio 3.0.0 

android-ndk版本:

1、创建android项目 (JNIDemo)

2、创建jni文件夹

右键 src->New->Folder->JNI Folder 如图:

结果如图:

3、创建JNI类

 

[java] view plain copy

print?

  1. <code class="language-java">public class JNITest {  
  2.   
  3.     static {  
  4.         System.loadLibrary("JniLib");  
  5.     }  
  6.   
  7.     public native String getString();  
  8.   
  9. }</code>  
public class JNITest {

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

    public native String getString();

}

如图:

3.1生成.h文件

3.1.1方法一

配置 Anroid Studio 外部工具,一劳永逸,往后无需命令行,File->Setting->Tools->External Tools->“+”进入页面

Program:$JDKPath$\bin\javah.exe

Parameters:-classpath . -jni -d $ModuleFileDir$\src\main\jni $FileClass$

Working directory:$ModuleFileDir$\src\main\Java

注释:

-classpath classes 指明类所在的位置

-jni com.jni.jnitest.JNITest 类的绝对路径

-d 产生的.h文件放到指定目录下;

配置成功如图:

开始生成.h文件,选中JNI类右键->New->External Tools->javah,如图:

成功后如图:

3.1.2方法二

右键拖动JNI类所在的包的路径到Terminal,自动切换到该目录下

javac编译生成class文件(生成class文件的方法有很多,这里提供一种)

右键拖动java文件夹到Terminal,自动切换到该目录下

必须在包名外使用javah命令,编译生成.h文件,把.h文件移动到jni文件夹(生成.h文件后可以删除class文件)如图:

3.2、创建文件 JniLib.cpp 、Android.mk、Application.mk

在jni目录下分别创建并编写 JniLib.cpp、Android.mk、Application.mk 这三个文件

复制.h文件内容到JniLib.cpp并修改,如下(此文件为JNI内容文件):

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

/*
 * Class:     com_jni_jnitest_JNITest
 * Method:    getString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_jni_jnitest_JNITest_getString
  (JNIEnv * env, jobject jobject){

  return (*env).NewStringUTF("成功调用JNI内容");

  }

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := JniLib
LOCAL_SRC_FILES =: JniLib.cpp
include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_MODULES := JniLib
APP_ABI := all

4、其它相关配置

4.1 修改app下的build.gradle文件, 如下图

ndk{
            moduleName "JniLib"
//            abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定的三种abi体系下的so库
        }
        sourceSets.main{
            jni.srcDirs = []
            jniLibs.srcDir "src/main/libs"
        }

4.2 项目下的gradle.properties文件(如果没有此文件,自己新建一个)添加代码:

android.useDeprecatedNdk=true

5、执行ndk-build

此处我用的是配置好的工具来执行,和 3.1.1 一样的步骤

选中JNI类右键->New->External Tools->ndk-build,结果如图:

6、调用so

package com.jni.jnitest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    Button button;
    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = findViewById(R.id.button);
        tv = findViewById(R.id.tv);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                tv.setText("结果:"+ new JNITest().getString());
            }
        });

    }
}

结果

Demo 

 

https://blog.csdn.net/u011057439/article/details/51459620

动态库*.so在linux下用c和c++编程时经常会碰到,最近在网站找了几篇文章介绍动态库的编译和链接,总算搞懂了这个之前一直不太了解得东东,这里做个笔记,也为其它正为动态库链接库而苦恼的兄弟们提供一点帮助。
1、动态库的编译


下面通过一个例子来介绍如何生成一个动态库。这里有一个头文件:so_test.h,三个.c文件:test_a.c、test_b.c、test_c.c,我们将这几个文件编译成一个动态库:libtest.so。


//so_test.h:
#include "stdio.h"
void test_a();
void test_b();
void test_c();


//test_a.c:
#include "so_test.h"
void test_a()
{
  printf("this is in test_a...\n");
}




//test_b.c:
#include "so_test.h"
void test_b()
{
  printf("this is in test_b...\n");
}






//test_c.c:
#include "so_test.h"
void test_c()
{
  printf("this is in test_c...\n");
}
将这几个文件编译成一个动态库:libtest.so
$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so


2、动态库的链接
在1、中,我们已经成功生成了一个自己的动态链接库libtest.so,下面我们通过一个程序来调用这个库里的函数。程序的源文件为:test.c。


test.c:
#include "so_test.h"
int main()
{
test_a();
test_b();
test_c();
return 0;
}
将test.c与动态库libtest.so链接生成执行文件test:
$ gcc test.c -L. -ltest -o test
测试是否动态连接,如果列出libtest.so,那么应该是连接正常了
$ ldd test
执行test,可以看到它是如何调用动态库中的函数的。
3、编译参数解析
最主要的是GCC命令行的一个选项:
-shared该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件


-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。


-L.:表示要连接的库在当前目录中


-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称


LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。


当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,不过如果没有root权限,那么只能采用输出LD_LIBRARY_PATH的方法了。


4、注意


调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。


在linux下可以用export命令来设置这个值,在linux终端下输入:
export LD_LIBRARY_PATH=/opt/au1200_rm/build_tools/bin: $LD_LIBRARY_PATH:   
然后再输入:export   
即会显示是否设置正确   
export方式在重启后失效,所以也可以用 vim /etc/bashrc ,修改其中的LD_LIBRARY_PATH变量。   
例如:LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/au1200_rm/build_tools/bin。 --------------------- 本文来自 严慈善 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/u011057439/article/details/51459620?utm_source=copy

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值