android so_android socket - CSDN
精华内容
参与话题
  • Android Studio 简单生成so文件并调用

    万次阅读 热门讨论 2019-04-15 09:49:10
    IDE :Android Studio 下载好ndk:下载地址 https://developer.android.com/ndk/downloads/index.html第1步:新建一个Android Studio 工程 JniHelloWorld。新建一个MyJni.java文件。 MyJni.javapublic class MyJni

    平台:windows
    IDE :Android Studio
    下载好ndk:下载地址 https://developer.android.com/ndk/downloads/index.html

    第1步:新建一个Android Studio 工程 JniHelloWorld。新建一个MyJni.java文件。
    这里写图片描述

    MyJni.java

    public class MyJni {
    
        static {
            System.loadLibrary("MyJni");
        }
    
        public native static String getString();
    }
    
    

    第2步:然后点击一下 make project 会在app的build目录下面生成.class文件。
    这里写图片描述

    第3步,在app/src/main文件夹下新建一个jni文件夹,然后打开Android Studio的终端,cd到这个目录,然后输入下面的指令

    javah -jni -classpath D:\github\JniHelloWorld\app\build\intermediates\classes\debug com.brotherd.jnihelloworld.MyJni
    
    

    就会在这个jni文件夹下生成一个.h文件,com_brotherd_jnihelloworld_MyJni.h,文件内容如下。

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_brotherd_jnihelloworld_MyJni */
    
    #ifndef _Included_com_brotherd_jnihelloworld_MyJni
    #define _Included_com_brotherd_jnihelloworld_MyJni
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_brotherd_jnihelloworld_MyJni
     * Method:    getString
     * Signature: ()Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_brotherd_jnihelloworld_MyJni_getString
      (JNIEnv *, jclass);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    
    

    在jni目录下新建一个c/c++source file ,取名test.c 实现上面.h文件中的方法。

    #include "jni.h"
    #include "com_brotherd_jnihelloworld_MyJni.h"
    
    JNIEXPORT jstring JNICALL Java_com_brotherd_jnihelloworld_MyJni_getString
      (JNIEnv *env, jclass jz){
    
      return (*env)->NewStringUTF(env,"this is the first time for me to use jni");
    
      }
    

    接着在jni文件夹下新建Android.mk和Application.mk文件。
    Android.mk

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := MyJni
    LOCAL_SRC_FILES := Test.c
    include $(BUILD_SHARED_LIBRARY)
    

    Application.mk

    APP_ABI := all
    

    第4步,关联下载好的ndk包,我的解压好的路径是C:\android-ndk-r14b
    这里写图片描述

    然后在终端进入到jni目录,输入指令 ndk-build,就会生成相应的so文件。

    这里写图片描述

    第5步,调用so文件。
    在app的bulid文件中加入如下代码,然后build project

    android {
        ...
        sourceSets {
            main() {
                jniLibs.srcDirs = ['src/main/libs']
                jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
            }
        }
    }
    

    在MainActivity中调用

    public class MainActivity extends AppCompatActivity {
    
        private TextView textView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            textView = (TextView) findViewById(R.id.textView);
            textView.setText(MyJni.getString());
        }
    }
    
    

    运行效果图

    这里写图片描述

    结尾:现在对JNI还是一窍不通,有时间再看看,先记录一下。

    参考链接:

    我的Android NDK之旅(二),使用ndk-build构建Jni

    展开全文
  • 这篇是针对我们在JNI开发过程中利用javah生成本地层对应的函数名类似于java_com_XX这种形式,很容易被逆向者在逆向so的时候在IDA的Exports列表中找到这样一个问题,我们的目的就是让IDA在反汇编过程显示不出来,以及...

            继上次基于源码级别和二进制级别的SO文件的核心函数保护后,没看的网友可以点击:点击打开链接;这篇是针对我们在JNI开发过程中利用javah生成本地层对应的函数名类似于java_com_XX这种形式,很容易被逆向者在逆向so的时候在IDA的Exports列表中找到这样一个问题,我们的目的就是让IDA在反汇编过程显示不出来,以及就算找到函数实现也是乱码的形式接下来开始搞;有问题欢迎大家批评指正和讨论。

    问题篇:

    比如拿上一篇中的例子来说,我们在破解分析的时候,在java层看到调用libegg.so文件,我们用IDA打开,很容易的看到:


    造成的结果会使得破解者很容易的切入主题,因此我们接下来就要解决这个问题。


    原理篇:

    我们知道JNI就是在java层与本地层之间起着一个桥梁的作用,因为java层是运行在Dalvik虚拟机中,而本地层则不会,因此这里在进入主题前很有必要理解一些几个问题:
    1.java层虚拟机需要使用到哪些的本地层的lib库?

    2.java层与本地层是怎么建立起一个对应的映射关系?

    这时候我们不得不分析android源码:

    首先我们知道对于第一个问题,在JNI开发的过程中我们会在java层编写这种形式:


    第一:告诉虚拟机去加载用static里面的libegg.so的动态链接库;

    第二:告诉虚拟机用native声明的getStringFromNative的方法是在本地层实现的;


    对于第二个问题,当虚拟机加载这个libegg.so这个库的时候,从java层进入本地层首先会执行JNI_Onload这个函数,所以可以在JNI_OnLoad函数中完成一些native层组件的初始化工作,同时更加重要的是,通常在JNI_jint JNI_OnLoad(JavaVM* vm, void* reserved)函数中会注册java层的native方法,提到注册就不得不提到一个很重要的一个静态函数registerNativeMethods:

    传统java  Jni方式:1.编写带有native方法的Java类;--->2.使用javah命令生成.h头文件;--->3.编写代码实现头文件中的方法,这样的“官方” 流程,是我们认识到这样会带来java_com_xxxx这样很容易被逆向者发现的弊端;
    通用方式:RegisterNatives方法能帮助你把c/c++中的方法隐射到Java中的native方法,而无需遵循特定的方法命名格式。应用层级的Java类别透过VM而呼叫到本地函数。一般是仰赖VM去寻找*.so里的本地函数。如果需要连续呼叫很多次,每次都需要寻找一遍,会多花许多时间。此时,组件开发者可以自行将本地函数向VM进行登记。

    VM调registerNativeMethods()函数的用途有二:  

    (1)更有效率去找到函数。  

    (2)可在执行期间进行抽换。

    由于gMethods[]是一个<名称,函数指针>对照表,在程序执行时,可多次呼叫registerNativeMethods()函数来更换本地函数之指针,而达到弹性抽换本地函数之目的。这就引出了本文解决以上问题所采用的办法:

    第一步:自定义JNI_Onload,来自定义JNI函数的函数名,通过registerNativeMethods()函数来更换本地函数指针并加入头文件;
    第二步:所更换的本地函数所对应的函数的实现。
    第三步:隐藏符号表,在Android.mk文件里面添加一句LOCAL_CFLAGS := -fvisibility=hidden


    实现篇:

    第一步:自定义JNI_Onload,来自定义JNI函数的函数名,通过registerNativeMethods()函数来更换本地函数指针并加入头文件;我们在上一个工程的基础上来改:

    void* getStringc(JNIEnv *env, jobject obj, jstring str);
    static JNINativeMethod gMethods[] = {
            { "getStringFromNative", "(Ljava/lang/String;)Ljava/lang/String;", (void*)getStringc},
    
    };
    static int registerNativeMethods(JNIEnv* env, const char* className,
                                     JNINativeMethod* gMethods, int numMethods)
    {
        jclass clazz;
        clazz = (*env)->FindClass(env, className);
        if (clazz == NULL) {
            return JNI_FALSE;
        }
        if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
            return JNI_FALSE;
        }
    
        return JNI_TRUE;
    }
    static int registerNatives(JNIEnv* env)
    {
        if (!registerNativeMethods(env, JNIREG_CLASS, gMethods,
                                   sizeof(gMethods) / sizeof(gMethods[0])))
            return JNI_FALSE;
    
        return JNI_TRUE;
    }
    void anti_debug(){
        ptrace(PTRACE_TRACEME,0,0,0);
    }
    jint JNI_OnLoad(JavaVM* vm,void* reserved){
        //anti_debug();
        JNIEnv* env;
        if ((*vm)->GetEnv(vm,(void**)(&env), JNI_VERSION_1_6) != JNI_OK)
    
        {
            return -1;
        }
        assert(env != NULL);
    
        if (!registerNatives(env)) {//注册
            return -1;
        }
    
        return JNI_VERSION_1_6;
    }
    
    这里我们要注意一点:

    JNINativemethod中结构体的定义:

    typedef struct {  
      
    const char* name;  
    const char* signature;  
    void* fnPtr;  
    } JNINativeMethod;  
    第一个变量name是Java中函数的名字。

    第二个变量signature,用字符串是描述了Java中函数的参数和返回值

    第三个变量fnPtr是函数指针,指向native函数。前面都要接 (void *)

    第一个变量与第三个变量是对应的,一个是java层方法名,对应着第三个参数的native方法名字:就像在本文中

    第三步:隐藏符号表,在Android.mk文件里面添加一句LOCAL_CFLAGS := -fvisibility=hidden

    第一个和第三个好理解:对于第二个:

    括号里面表示参数的类型,括号后面表示返回值。我们要参照一个表格:


    第二步:所更换的本地函数所对应的函数的实现:

    __attribute__((section (".mytext")))  JNICALL jstring getStringc
            (JNIEnv *env, jobject obj, jstring str)
    {
       // jstring   CharTojstring(JNIEnv* env,   char* str);
        //首先将string类型的转化为char类型的字符串
        const char *strAry=(*env)->GetStringUTFChars(env,str,0);
        if(strAry==NULL){
            return NULL;
        }
        int len=strlen(strAry);
        char* last=(char*)malloc((len+1)* sizeof(char));
        memset(last,0,len+1);
        //char buf[]={'z','h','a','o','b','e','i','b','e','i'};
        char* buf ="beibei";
        int buf_len=strlen(buf);
        int i;
        for(i=0;i<len;i++){
            last[i]=strAry[i]|buf[i%buf_len];
            if(last[i]==0){
                last[i]=strAry[i];
            }
        }
        last[len]=0;
        return (*env)->NewStringUTF(env, last);
    }
    这里的关键是,在函数前加上attribute((section (“.mytext”))),这样的话,编译的时候就会把这个函数编译到自定义的名叫”.mytext“的section里面,由于我们在java层没有定义这个函数因此要写到一个自定义的section里面。

    第三步:隐藏符号表,在Android.mk文件里面添加一句LOCAL_CFLAGS := -fvisibility=hidden

    注意的是在android studio中在build.gradle中

    第一:defaultConfig{}中增加ndk设置:

      ndk{
                moduleName "egg"
                ldLibs "log","z","m"
                abiFilters "armeabi","armeabi-v7a","x86"
            }
    第二:因为要手动ndk-build,需要在android{}中增加jni和jniLibs路径说明:

    sourceSets {
            main {
                jni.srcDirs = []
                jniLibs.srcDirs = ['src/main/libs']
            }}

    第三:在/src/main/jni中进行ndk-build手动编译生成对应的.so文件。

    程序跑起来跟之前一样,我们用IDA打开对应的.so文件可以看出:


    总结篇:

    优点:

    1.源码改动少,只需要添加JNI_Onload函数;

    2.无需加解密so,就可以实现混淆so中的JNI函数(使得IDA分析紊乱);

    3.可以加上前面说到的基于源码的函数的加解密,从而增加破解者的难度;

    步骤:

    第一步:自定义JNI_Onload,来自定义JNI函数的函数名,并加入头文件;
    第二步:Java层函数所对应的函数的实现。
    第三步:隐藏符号表,在Android.mk文件里面添加一句LOCAL_CFLAGS := -fvisibility=hidden

    原理本质:

    当java层调用System.loadLibrary函数时,函数会找到对应的so库,然后试着去找“JNI_Onload函数”;JNI_OnLoad可以和JNIEnv的registerNatives函数结合起来,实现动态的函数替换,再加上getStringc函数符号表的隐藏,就可以起到保护的作用。

    附件:源码下载处:点击打开链接 






    展开全文
  • Android studio添加第三方库和so

    万次阅读 2017-12-27 16:09:09
    添加so库的两种方式 以下两种方式二选一 方法一: 1.在src/main中新建jniLibs文件夹 ,把.so复制进去即可 方法二: 1.在app/中新建libs文件夹,把.so复制...

    原文:

    添加so库的两种方式

    以下两种方式二选一


    方法一:

    1.在src/main中新建jniLibs文件夹 ,把.so复制进去即可






    方法二:

    1.在app/中新建libs文件夹,把.so复制进去


    2.在app/build.gradle中添加以下五行脚本即可(注:以下脚本意思是会把libs文件夹当成jniLibs文件夹,可以直接用so库了)

    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

    贴上完整的app/build.gradle文件,红色的部分是新增的

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 23
        buildToolsVersion "23.0.2"
    
        defaultConfig {
            applicationId "com.tofu.chat"
            minSdkVersion 16
            targetSdkVersion 23
            versionCode 1
            versionName "1.0"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    
        sourceSets {
            main {
                jniLibs.srcDirs = ['libs']
            }
        }
    }
    
    dependencies {
        compile fileTree(include: ['*.jar'], dir: 'libs')
        testCompile 'junit:junit:4.12'
        compile 'com.android.support:appcompat-v7:23.1.1'
        compile project(':common')
        compile files('libs/kandy-1.6.244.jar')
    }
    


    原文:

    使用Gradle引入第三方库文件的总结

    不知不觉,使用Android Studio开发App已有一段时间了,接触到了各式各样的第三方库文件的引入,也是时候总结一波了。

    使用Android Studio开发Android应用时,避免不了需要借助Gradle引入各式各样的第三方库文件,帮助我们更好的开发App,常见的引入方式有:Jar文件,so文件,Library库文件,aar文件,远程jcenter、maven仓库文件。这几种引入方式各有利弊,对应的gradle配置也有所不同,本文根据平时的使用经验,做一个简单的总结,帮助大家更好的利用Gradle引入第三方库文件。

    jar文件


    将jar文件复制至app module目录下的libs文件夹下,然后打开app module目录下的build.gradle配置文件,在dependencies项中添加配置命令,这里有两种配置方式可供选择:

    • 一次性引入libs目录下所有jar文件
    compile fileTree(include: ['*.jar'], dir: 'libs')
    • 1
    • 单个逐一引入jar文件
    compile files('libs/universal-image-loader-1.8.6-with-sources.jar')
    • 1

    so文件


    • Gradle 旧版本

    将so文件(包含arm64等文件夹)复制app module下面的libs文件夹中,和jar文件类似,然后在build.gradle的android栏目下添加一个task:指定so文件的目录,并将其转化为Jar文件。命令如下:

    task nativeLibsToJar(type: Zip, description: "create a jar archive of the native libs") {  
            destinationDir file("$projectDir/libs")  
            baseName "Native_Libs2"  
            extension "jar"  
            from fileTree(dir: "libs", include: "**/*.so")  
            into "lib"  
        }  
    
        tasks.withType(JavaCompile) {  
            compileTask -> compileTask.dependsOn(nativeLibsToJar)  
        }  
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • Gradle 新版本

    新版Gradle实现了自动打包编译so文件的功能,并且为so文件指定了默认的目录app/src/main/jniLibs,当然默认是没有这个文件夹的,我们只需要新建一个jniLibs文件夹,并将so文件复制到该文件夹下,编译运行即可。

    通常,为了更好地管理第三方库文件,或者更简单地将Eclipse项目转化为Android Studio项目,建议将jar文件和so文件放在一起,统一搁置在app/libs目录下,此时,我们只需要在build.gradle的android一栏中添加如命令,指定so文件的目录即可:

        sourceSets {
            main {
                    jniLibs.srcDirs = ['libs']
            }
        }
    • 1
    • 2
    • 3
    • 4
    • 5

    通过这种方式,编译过后,将项目目录切换至Android试图,可以看到,app目录下多了一个jniLibs文件夹,里面包含了引入的so文件和jar包,如下图所示,表示集成成功。

    Library库文件


    将第三方Library库文件复制到项目根目录下,打开项目根目录下的settings.gradle文件,添加配置命令,如:

    include ':app', ':PullToRefresh'
    • 1

    然后打开app module目录下的build.gradle,添加配置命令,如:

    compile project(':PullToRefresh')
    • 1

    小技巧:推荐在项目根目录下新建一个文件夹,如extras文件夹,将所有Library库文件都复制到该文件下,方便统一浏览管理,这样上面两步对应的配置命令将变成:

    include ':app', ':extras:PullToRefresh'
    • 1

    compile project(':extras:PullToRefresh')
    • 1

    aar文件


    aar其实也是一个压缩文件,相比jar文件,它能够含带res资源文件等,aar文件的引入方式有两种:

    • Module形式引入

    选择File菜单,或者打开Project Structure界面,添加新的Module(New Module…),选择Import .JAR/.AAR Package,选择目标aar文件导入。导入之后,在项目根目录下会自动生成一个新的文件夹放置aar文件及其配置文件,如:

    这里写图片描述

    然后打开app module目录下的build.gradle配置文件,在dependencies依赖项中添加配置即可:

    compile project(':qiniu-android-sdk-7.2.0')
    • 1

    注意:这种引入方式无法查看aar文件中的代码和资源等文件。

    • libs目录中引入

    将aar文件复制到app module目录下的libs文件夹中,然后打开app module目录下的build.gradle配置文件,在android一栏中添加依赖:

    repositories {
        flatDir {
            dirs 'libs'
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    然后再在dependencies一栏中添加:

    compile(name:'qiniu-android-sdk-7.2.0', ext:'aar')
    • 1

    对应完整的app module目录下的build.gradle配置文件如:

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 23
        buildToolsVersion "23.0.2"
    
        defaultConfig {
            applicationId "com.feng.demo"
            minSdkVersion 11
            targetSdkVersion 23
            versionCode 1
            versionName "1.0.0"
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    
        repositories {
            flatDir {
                dirs 'libs'
            }
        }
    
    }
    
    dependencies {
        compile fileTree(include: ['*.jar'], dir: 'libs')
        testCompile 'junit:junit:4.12'
        compile 'com.android.support:appcompat-v7:23.3.0'
        compile project(':extras:PullToRefresh')
        compile 'com.squareup.okhttp3:okhttp:3.2.0'
        compile(name:'qiniu-android-sdk-7.2.0', ext:'aar')
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    重新同步,编译工程,然后可以在app的build目录下生成对应aar的临时文件,可以看到aar文件中的jar文件、资源文件等,看上去更像是一个解压缩文件夹:

    这里写图片描述

    jcenter、maven仓库文件


    在项目根目录的build.gradle文件中添加仓库,如:

    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:2.1.0'
        }
    }
    
    allprojects {
        repositories {
            jcenter()
        }
    }
    
    task clean(type: Delete) {
        delete rootProject.buildDir
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    然后再各个Module的build.gradle配置文件的dependencies项中添加依赖,格式为`compile ‘name:version’`,如:

    compile 'com.squareup.okhttp3:okhttp:3.2.0'
    • 1

    总结


    以上便是针对Android Studio引入第三方库文件的几种方式,它们各有利弊,总结来看,就是在包含内容、源码修改、版本更新三方面上的差异。Jar文件只包含java代码,不像aar等其他文件能够包含res资源文件;Library文件形式的引入可以让开发人员根据自己的需求修改库文件源码,以达到适应自己项目的目的;而远程仓库形式的引入可以实现版本的自动检测更新,保证自己项目使用的第三方库文件始终是最新版本。

    当然,一个优秀的第三方库一般会提供多种方式的引入,考虑到Eclipse和AS用户,至少要包含Jar文件和Gradle构建这两种,其他一些供应者会根据自己的功能模式提供其他引入方式,比如七牛云存储便提供了aar的引入方式。大家可以根据自己的项目需求选择合适的引入方式,毕竟,适合自己的才是最好的。


    展开全文
  • Androidso文件的生成和调用

    千次阅读 2019-07-09 10:33:52
    so”文件是使用C/C++编写生成的,在Android 平台上快速编译、打包该文件,它是一个动态链接库,而生成“so”文件其实就是JNI开发。 2、JNI开发简介 (1)、JNI简介 JNI全称为Java Native Interface(JAVA本地调用...

    1、so文件介绍
       “so”文件是使用C/C++编写生成的,在Android 平台上快速编译、打包该文件,它是一个动态链接库,而生成“so”文件其实就是JNI开发。

    2、JNI开发简介
    (1)、JNI简介
      JNI全称为Java Native Interface(JAVA本地调用)。从Java1.1开始,JNI成为java平台的一部分,它允许Java代码和其他语言写的代码(如C&C++)进行交互。并非从Android发布才引入JNI的概念的。
      JNI是一个协议,这个协议用来沟通java代码和外部的本地代码(c/c++),外部的c/c++代码也可以调用java代码。
    (2)、JNI的作用

    • 效率上 C/C++是本地语言,比java更高效;
    • 代码移植,如果之前用C语言开发过模块,可以复用已经存在的c代码;
    • java反编译比C语言容易,一般加密算法都是用C语言编写,不容易被反编译。

    (3)、JNI的数据类型
      Java的数据类型是跟C/C++的数据类型是不一样的,而JNI是处于Java和Native本地库(大部分是用C/C++写的)中间的一层,JNI对于两种不同的数据类型之间必须做一种转换,所以在JNI跟Java之间就会有数据类型的对应关系。
       JNI的数据类型包含两种:基本类型和引用类型。基本类型主要有jboolea、jchar、jbyte等,他们和Java中的数据类型的对应关系如下图所示:
    jni类型映射

      JNI中的引用类型主要有类、对象和数组,他们和Java中的引用类型的对应关系如下图所示: 在这里插入图片描述

    (4)、JNI函数命名规则
      javah生成的c/c++头文件的时候,会对java中定义的 native 函数生成对应的jni层函数,如下:

        #include <cn_xinxing_jnitest_CalculateUtils.h> 
        JNIEXPORT jstring JNICALL  Java_cn_xinxing_jnitest_CalculateUtils_getStringFromNative
                (JNIEnv * env, jobject obj, jstring str){
                return str;
        }
    

       首先函数名的格式遵循如下规则:Java_包名_类名_方法名。比如

       Java_cn_xinxing_jnitest_CalculateUtils_getStringFromNative (JNIEnv * env, jobject obj, jstring str)
    

      其中cn_xinxing_jnitest是包名,CalculateUtils是类名,getStringFromNative是方法名,jstring 是方法的String类型的参数。JNIEXPORT、JNICALL、JNIEnv和jobject都是JNI标准中所定义的类型或者宏,它们的含义如下:

    • JNIEnv * :表示一个指向JNI环境的指针,可以通过它来访问JNI提供的接口方法;

    • jobject: 表示Java对象种的this;

    • JNIEXPORT和JNICALL: 它们是JNI中所定义的宏可以在jni.h这个头文件中查找到。

        如果不这样命名,当把动态库加载进DVM的时候,通过JNIEnv *指针去查找Java Native方法对应的JNI方法的时候,就会找不到了。

    3、NDK的介绍
    (1)、NDK的简介
      NDK全称为native development kit本地语言(C&C++)开发包。简单来说利用NDK,可以开发纯C&C++的代码,然后编译成库,让Java程序调用。NDK开发的可以称之为底层开发或者jni(java native interface)层开发。
       NDK是一系列工具的集合,NDK提供了一系列的工具,可以帮助开发者进行c/c++的开发,并能自动将.so打包成apk。NDK集成了交叉编译器,并提供了相应的mk文件可以做到隔离CPU,平台,ABI等差异,只需修改mk文件即可。开发人员只需要简单修改mk文件,就可以创建出“.so”文件。NDK还提供了一份稳定的功能有限的API头文件声明。

    (2)、NDK和JNI的关系
      简单来说,NDK是工具,使用NDK可以更方便、快捷的开发JNI,NDK开发是基于JNI的。而JNI,是Java提出的协议,从Java1.1开始,JNI就已经是Java平台的一部分,它允许Java代码和其他语言写的代码进行交互,JNI开发便是基于此开发。
      使用NDK开发JNI的步骤如下;
    ① JNI接口的设计;
    ② 使用C/C++实现本地方法;
    ③ 使用NDK生成JNI动态链接库.so文件;
    ④ 将动态链接库复制到Java/Android工程,调用,运行即可。
    ⑤ so文件生成步骤
    ⑥ so文件调用

    (3)、NDK的配置
      在android studio中下载NDK,然后在系统的环境变量中配置: 环境变量 PATH 下追加 :G:\AndroidSDK\ndk-bundle 这个表示NDK的位置。

    4、so文件的生成步骤(有两种方法,这是方法一)
    (1)、新建一个Android Studio 工程 JniTest,新建一个MyJni.java文件:

     public class MyJni {
        static {
            System.loadLibrary("MyJni");   //链接后面生成的MYJni.so库
        }
        public native static String getString();    //native 方法是C语言中要实现的方法
    }
    

    (2)、通过将java文件生成.class文件,然后编译成.h文件,这里使用了extend tool来实现一步生成.h文件。

    配置javah和ndk-build: 在setting中选择extend tool,然后添加javah 命令的配置(一键生成h文件)
    参数:
          Program:    $JDKPath$\bin\javah.exe 这里配置的是javah.exe的路径(基本一致)
                      $JDKPath$可以从右侧按钮(insert mac...)中选择
          Parametes:  $FileClass$ 这里指的是要编译.h文件的java类 (注意这里只填写了FileClass,其他参数没有导入那么自定义的一些model,或者Android.jar中的类是不支持的,可以先生成h然后手动输入特殊的参数。 比如Bitmap,在native方法中先不传这个参数,当生成h文件后,手动添加一个jobject的参数)
          Working:    ModuleFileDir\src\main\java //工作路径,也是.h生成的路径
    

    在这里插入图片描述
      通过右键需要生成.h文件的MyJni 类然后找extend tool中的javah,点击就可以获得在Main文件夹下Java文件夹下jni文件夹下对应的.h文件,其中就包含了java中要实现的getString方法。
    (2)、在jni文件夹下新建一个C语言程序:

      #include <stdio.h>
      #include <jni.h>
      #include <wu_com_ndktest_JNIUtils.h>
      JNIEXPORT jstring JNICALL Java_wu_com_ndktest_JNIUtils_getString
        (JNIEnv *env, jclass jclass){    //实现.h文件中的方法,返回字符串
          //返回一个字符串
              return (*env)->NewStringUTF(env,"This is my first NDK Application");
        }
    

    (3)、在jni文件夹下新建Android.mk和Application.mk文件。
    Android.mk

    LOCAL_PATH := $(call my-dir)           //固定写法,把路径赋给LOCAL_PATH变量
    include $(CLEAR_VARS)                  //清除其他LOCAL变量
    LOCAL_MODULE := JNITest             //这个模块的名字,最后生成的.so的名字就是它,要跟java里面的loadLibray的名字一样。
    LOCAL_SRC_FILES :=test.c\     //这里是要编译的文件,\ 符号是换行,可以有多个
    include $(BUILD_SHARED_LIBRARY)        //SHARED_LIBRARY就是动态库,即.so文件
    

    Application.mk

    APP_ABI := all    / /生成在什么架构下的.so文件,all指所有架构都生成
    

    (4)、在命令行下,cd到jni目录下,输入指令: ndk-build,等一会即可生成.so文件;当然也可以添加extend tool来实现。位于lib目录下,将其放到app/src/main/jniLibs目录下就能用了。

    5、so文件的调用
      找到libs下生成的各体系结构下的.so库文件,然后把.so文件复制出来,放到需要使用的程序的Main的JAVA下新建的libs文件夹下:
    (1)、把复制的so包,放到项目的libs目录下
    (2)、在app module 下的buide.gradle 中添加下面代码:

    //放在libs目录中
    sourceSets {
    main {
        jni.srcDirs=[]             //使用自己编写的两个mk文件,避免android studio想自动生成而导致错误。
        jniLibs.srcDirs = ['src/main/libs']        //libs表示libs文件夹的地址,一定要保证正确
       }
    }
    

    这样就可以在安卓中使用c语言或者c++语言了。

    6、Android studio使用CMake生成”so”文件:
    (1)、使用CMake构建native项目,使用CMake的话,必须要有CMakeLists.txt(注意名字不能写错),以及对应的cpp资源;在新建项目的时候把 include C++ support 勾选上就可以了,这样在MainActivity终就会生成对应的native方法对应Main文件夹下cpp文件夹的c或c++的文件方法,同样自己也可以定义需要的native方法,通过按alt+Enter就可以选择在c或c++文件中生成对应的方法,就可以在里面实现对应的代码逻辑。而CMakeLists.txt在App文件夹下,如果有需要的话,可以修改里面内容,CMakeLists.txt的内容如下:

    # CMake最低版本 cmake_minimum_required(VERSION 3.4.1)
    # 将需要打包的资源添加进来 
    add_library( 
    # 库名字 
    native_hello 
    # 库类型      表示编译生成的是动态链接库 
    SHARED     
    # 包含的cpp :表示编译文件的相对路径,这里可以是一个文件的路径也可以是多个文件的路径
    native_hello.cpp ) 
    
    # 链接到项目中 
    target_link_libraries( 
    native_hello 
    android 
    log )
    

    (2)、当然上面介绍的是自动生成的c或c++,不过一般我们都是使用自定义的,这样才能符合自己的需求,方法如下:
    AS已经提供了相对便捷的方法。首先在要使用jni调用的工程模块下新建一个
    在这里插入图片描述
    CMakeLists.txt:

    代码:
    cmake_minimum_required(VERSION 3.6)
    add_library( # Sets the name of the library.
                 xjni
    
                 # Sets the library as a shared library.
                 SHARED
    
                 # Provides a relative path to your source file(s).
                 src/main/jni/XJni.c )
    
    find_library( # Sets the name of the path variable.
                    log-lib
    
                    # Specifies the name of the NDK library that
                    # you want CMake to locate.
                    log )
    target_link_libraries( # Specifies the target library.
                  xjni
                  # Links the target library to the log library
                  # included in the NDK.
                  ${log-lib} )
    

      CMakeLists.txt具体配置上面已经说过了,这个地方是去掉了注释了的。需要注意的是,如果我们不在c源代码文件中输出日志到logcat,那么我们是不需要依赖log库的,也就是说find_library、target_link_libraries不是必须的。
      接着配置模块支持jni调用,对项目模块右键:
    在这里插入图片描述
      在弹出的提示框中选择刚新建配置的CMakeLists.txt文件:
    在这里插入图片描述
      看看app/build.gradle的变化:
    在这里插入图片描述
      编译完成,编译器会报找不到XJni.c文件错误。ok,那我们新建一个/app/src/main/jni/XJni.c:
    只有一行代码,ok,再编译,没问题!接下来新建jni调用java文件XJni.java:

       #include <jni.h>
        public class XJni {
            static {
                System.loadLibrary("xjni");
            }
            public native String getStr(String s);
        }
    

      如果getStr方法显示错误红色,不用着急,选中函数名,按快捷键alt+enter:
      选择create function后,函数就自动在XJni.c文件中生成了

    #include <jni.h>
    JNIEXPORT jstring JNICALL
    Java_com_test_jnitest4_XJni_getStr(JNIEnv *env, jobject instance, jstring s_) {
        const char *s = (*env)->GetStringUTFChars(env, s_, 0);
        // TODO
        (*env)->ReleaseStringUTFChars(env, s_, s);
    
        return (*env)->NewStringUTF(env, returnValue);
    }
    

      需要注意的是,最好让.java文件名与.c文件名同名,否则你可能快捷键不会出现create function选项。修改.c文件名的时候记得对应将CMakeLists.txt中修改。

    最后这篇文章是借鉴了以下几位的心得:
    https://blog.csdn.net/zxw136511485/article/details/53304258
    https://blog.csdn.net/quwei3930921/article/details/78820991
    还有不足,可以看这位大佬的引入第三方库:
    https://blog.csdn.net/Xiongjiayo/article/details/85340121

    展开全文
  • Android编写.so入门介绍

    千次阅读 2018-01-16 14:37:11
    Android开发中,我们经常会用到.so文件。原因有很多,比如部分方法不想暴露,如加密规则。比如部分秘钥需要存储,哪怕最简单的一个加盐的String。我们使用.so调用获取这个String,也比直接明文写在代码中要来的安全...
  • Android 调用so库全过程

    万次阅读 多人点赞 2017-12-05 10:41:59
    Android中有时候为了效率以及平台开发库的支持,难免会用到NDK开发,那么都会产生一个so文件,通过native方法进行调用,开发和调用步骤很简单,这里就不多说了,本文主要来介绍,我们在使用so的时候总是会出现一些...
  • Android so文件浅析

    万次阅读 2018-05-19 21:48:33
    Android中的so文件是动态链接库,是二进制文件,即ELF文件。多用于NDK开发中。 二. 基础知识 三. so文件格式解析 so文件即ELF文件,是一个二进制文件,我们可以用UltraEdit打开查看。如下: 上面有一处很...
  • Android .so文件引用

    千次阅读 2018-12-27 17:27:31
    在src目录下Java同级别创建jniLibs目录,再此目录下创建armeabi-v7a目录将.so文件放入其中。 在build.gradle中加入 sourceSets{ main { jni.srcDirs = ['libs'] } } ...
  • Android studio中正确引入so文件的方法

    万次阅读 多人点赞 2017-03-10 19:09:40
    相信很多朋友在使用Android studio开发中,遇到过如何引入第三方so文件的问题,然而第三方官方仅仅给出了ADT环境下的集成方式。 Android studio中默认使用的是gradle编译方式,与ADT编辑方式不一样,那么so文件应当...
  • Android apk中so库文件未压缩

    万次阅读 2020-03-05 17:59:12
    查看apk包,发现apk 包中so库文件未被压缩. 但是一个类似项目,相同版本却没有问题 升级前 升级后 升级后Raw File Size 正好是未压缩的大小 可能原因 不同版本AGP gradle build task 实现不一样, 再某情况下回不进行...
  • Android NDK开发中,除了可以通过自己编写C/C++代码来构建动态连接库进行调用之外,还可以通过直接调用现成的so库开进行NDK开发。接下来,我将介绍在Android Studio中如何调用第三方动态连接库。 首先需要考虑的是...
  • AndroidStudio中调用So库方法

    千次阅读 2019-03-06 17:40:13
    Android QQ交流群:813273942 想要调用.so文件,必须先引入.so……是不是有点废话了。 据说没有图片的阅读很麻烦(完全正确啊)…… 首先 (1) 将AS切换到Project目录,在main下新建jniLibs,在jniLibs下新建...
  • 今天说下自己项目遇到的问题,Android studio(简称as) model转变成jar包使用。 其实每次as编译,model都会生成aar文件,比jar包更强大,他可以包含资源文件,还有第三方引用jar如下图 2.aar跟jar使用方式一样直接...
  • Android Studio打包.so到apk中

    万次阅读 2018-09-05 21:59:57
    Android Studio 项目是从Eclipse 中导入到 Android Studio 现象: Eclipse的项目中包含libs文件夹,转到Android Studio,路径有一定的变化,见下图: 在图一中的第2-5行,也就是Android Studio中这个文件夹jni...
  • Android 打包so动态库文件到APK

    万次阅读 热门讨论 2011-03-09 13:11:00
    有时由于项目需要使用JNI来调用.so文件,需要将so文件一起打包到APK文件中,这有两种方法:1. 使用mm命令和Android SDK源代码一起编译。在project根目录创建一个Android.mk,文件内容如:LOCAL_PATH:= $(call my-dir...
  • 如何简单修改Androidso文件

    万次阅读 2013-05-30 09:22:45
    场景 ...这时候就需要修改so文件了。 蓝牙默认设备名称的修改在: frameworks\base\core\jni\Android_bluetooth_common.h 主要就是修改BTMTK_ANDROID_DEFAULT_LOCAL_NAME的值 #define BTMTK_AN
  • Android Studio之导入外部so

    千次阅读 2015-08-06 16:00:25
    Android Studio导入外部so库目前知晓四种方法,测试版本Android Studio1.31.Studio自带jniLibs方法(推荐)这种方式对于新建的studio项目很适用因为Studio支持jniLibs方式,所以在项目目录下的 app/src/main目录下...
  • Android Studio加载so库和调用native方法

    千次阅读 多人点赞 2017-07-11 15:11:53
    现在智能家居很火,有很多的云平台提供者,也有很多智能设备提供者,例如智能摄像头,偶然的机会我接触了一款智能摄像头PnP网络摄像头,就下载了他的sdk玩了一下,简单记录一下调用so库踩的坑。 PnP网络摄像头的demo...
  • Android 源码编译 libc++.so

    万次阅读 2016-11-03 09:41:10
    Android源码 5.1.0_r1 clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [/aosp/out/host/linux-x86/obj/lib/libc++.so] Error 1 make时报错。
  • AndroidStudio如何引入so

    万次阅读 多人点赞 2016-06-06 15:13:18
    先说前提条件,我的AndroidStudio版本是2.2 Preview 3,版本是2.1的同学应该也是一样的。 然后说结论吧,有些同学可能赶着做项目: 结论: so包应该放在相应模块(比如app模块)下的src目录下的main目录下的jniLibs...
1 2 3 4 5 ... 20
收藏数 167,404
精华内容 66,961
关键字:

android so