当前位置:主页 > 查看内容

jni开发(一):编写第一个多so的app

发布时间:2021-06-29 00:00| 位朋友查看

简介:有句话说得好逆向的高度取决于正向开发的高度。 前言 1.Java 的 native 方法可以通过静态和动态的方式注册JNI来链接 C/C中的函数。 2.产生so的方式有两种1.cmake编译? 2.通过编写android.mk编译 ? 本篇你将学到 1.通过静态注册来访问 C/C中的函数 2.在as中通……

有句话说得好:逆向的高度取决于正向开发的高度。

前言:

1.Java 的 native 方法可以通过静态和动态的方式注册JNI来链接 C/C++中的函数。

2.产生so的方式有两种:1.cmake编译? 2.通过编写android.mk编译

?

本篇你将学到:

1.通过静态注册来访问 C/C++中的函数

2.在as中,通过cmake编译cpp,产生so

3.jni日志打印

?

开始准备工作

1.在as中新创建一个native c++

2.完成相关配置后,build时会报NDK not configured. Download it with SDK manager.,此时需要配置ndk:

如果你没有下载过ndk,则点击提示的 Install NDK '21.0.6113669' and sync project

如果你下载过:点击File->project structure->sdk location 会看到android ndk location 然后选择你的ndk安装的目录

点击确认后,会自动进行重新build。

3.build 成功后,此时的结构目录:

(如果想直接看多so编写的话,直接到阶段三)

阶段一:

1.修改结构目录如下

?

2.修改 MainActivity.java代码如下:

?
package com.test.so.myapplication111111111111;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

import com.myso.test1;

public class MainActivity extends AppCompatActivity {

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

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(test1.stringFromJNI());
    }
}

?

新增 test1.java 代码如下:

package com.myso;

public class test1 {
    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }


    public  static native String stringFromJNI();

}

此时我们的 stringFromJNI 方法显示为红色,不急,将鼠标移到该方法上会出现下图红框中的,点击它

点击后会自动跳到 native-lib.cpp中,显示如下代码:

直接修改它,如下:(关于cpp中的对应java中的native方法的方法名的命名规则可以去了解下)

我们点击绿色运行,将app安装到测试机中,如不出意外,应该会看到上述的字符串:

Hello from C++6666666666666666666

?

阶段二:

1.修改test1.java文件为:

package com.myso;

public class test1 {
    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }


    public  static native String stringFromJNI();
    public  static native String stringFromJNI(String str);

}

2.修改 native-lib.cpp中的? Java_com_myso_test1_stringFromJNI 为? Java_com_myso_test1_stringFromJNI__

(重载函数命名需要在最后加上 __)

3.返回?test1.java 可以看到? ?public static native String stringFromJNI(String str);? 变红了,将鼠标移到红色上进行创建。

4.此时?native-lib.cpp 代码如下:

5.可以将?Java_com_myso_test1_stringFromJNI__Ljava_lang_String_2 修改如下

extern "C"
JNIEXPORT jstring JNICALL
Java_com_myso_test1_stringFromJNI__Ljava_lang_String_2(JNIEnv *env, jclass clazz, jstring str) {
    const char *c_str = NULL;
    char buff[128] = {0};
    c_str = env->GetStringUTFChars(str, NULL);
    if (c_str == NULL) {
        return NULL;
    }
    sprintf(buff, "hello come from c++: %s", c_str);
    env->ReleaseStringUTFChars(str, c_str);
    return env->NewStringUTF(buff);
}

6.接下来的测试该重载方法省略,请自行测试,不出意外的话,你能看到你输入的字符串。

?

阶段三:

1,添加并修改结构目录如下:

cpp中的?CMakeLists.txt 代码如下:

#指定需要CMAKE的最小版本
cmake_minimum_required(VERSION 3.4.1)


#C 的编译选项是 CMAKE_C_FLAGS
# 指定编译参数,可选
#SET(CMAKE_CXX_FLAGS "-Wno-error=format-security -Wno-error=pointer-sign")

#设置生成的so动态库最后输出的路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})

#设置头文件搜索路径(和此txt同个路径的头文件无需设置),可选
#INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/common)

#指定用到的系统库或者NDK库或者第三方库的搜索路径,可选。
#LINK_DIRECTORIES(/usr/local/lib)


#为了编写多个so,添加子目录,将会调用子目录中的CMakeLists.txt
ADD_SUBDIRECTORY(one)
ADD_SUBDIRECTORY(two)


jni日志打印,mylog.h 代码如下:

#include <android/log.h>

#ifndef MYLOG_H
#define MYLOG_H
/*
 * 添加日志打印
 */

#define TAG "testApp" // 这个是自定义的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)


#endif //MYLOG_H

one中?CMakeLists.txt代码如下:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        native-one

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        native-lib1.cpp)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

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)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        native-one

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

native-lib1.cpp代码如下:

#include <jni.h>
#include <string>
#include "../mylog.h"

extern "C"
JNIEXPORT jstring JNICALL Java_com_myso_test1_stringFromJNI__(JNIEnv *env, jclass clazz) {
    std::string hello = "Hello from C++ 6666666666666666666677";
    return env->NewStringUTF(hello.c_str());
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_myso_test1_stringFromJNI__Ljava_lang_String_2 (JNIEnv *env, jclass clazz, jstring str) {
    const char *c_str = NULL;
    char buff[128] = {0};
    c_str = env->GetStringUTFChars(str, NULL);
    if (c_str == NULL) {
        LOGI("out of memory.\n");
        return NULL;
    }
    LOGI("lib1 java str:%s", c_str);
    sprintf(buff, "hello come from c++: %s", c_str);
    env->ReleaseStringUTFChars(str, c_str);
    return env->NewStringUTF(buff);

}

?

two中?CMakeLists.txt代码如下:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        native-two

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        native-lib2.cpp)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

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)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        native-two

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

native-lib2.cpp代码如下:

#include <jni.h>
#include <string>
#include "../mylog.h"


extern "C"
JNIEXPORT jstring JNICALL
Java_com_myso_test1_stringFromJNI__Ljava_lang_String_2Ljava_lang_String_2(JNIEnv *env, jclass clazz, jstring str, jstring str1) {
    LOGI("我来自:222222222222222222");
    return env->NewStringUTF("2 str2222");
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_myso_test1_stringFromJNI__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2(JNIEnv *env, jclass clazz, jstring str, jstring str1, jstring str2) {
    LOGI("我来自:33333333333333333333");
    return env->NewStringUTF("3 str3333");
}

build.gradle(:app)代码如下:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"

    defaultConfig {
        applicationId "com.test.so.myapplication111111111111"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
        ndk {
            ldLibs "log"            //实现__android_log_print
            // 设置支持的so构架
            abiFilters 'armeabi-v7a', 'arm64-v8a'// , 'x86', 'x86_64'
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }
    //解决:在增加多个cpp后,编译时出现More than one file was found with OS independent path 'lib/arm64-v8a/libnative-two.so'问题,添加如下代码
    packagingOptions {
        pickFirst 'lib/armeabi-v7a/libnative-one.so'
        pickFirst 'lib/armeabi-v7a/libnative-two.so'
        pickFirst 'lib/arm64-v8a/libnative-one.so'
        pickFirst 'lib/arm64-v8a/libnative-two.so'
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

}

然后sync now下,发现cpp中的红色都消失了,

2.点击 build -> make project 会看到有so产生

3.修改?test1.java 代码如下:

package com.myso;

public class test1 {
    static {
        System.loadLibrary("native-one");
        System.loadLibrary("native-two");
    }

    public static native String stringFromJNI();
    public static native String stringFromJNI(String str);
    public static native String stringFromJNI(String str,String str1);
    public static native String stringFromJNI(String str,String str1,String str2);

}

3.修改MainActivity.java代码如下:

package com.test.so.myapplication111111111111;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.TextView;

import com.myso.test1;

public class MainActivity extends AppCompatActivity {

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

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
//        tv.setText(test1.stringFromJNI());
//        tv.setText(test1.stringFromJNI("1111111199999999999999"));
        tv.setText(test1.stringFromJNI("",""));
    }
}

5.点击绿色运行安装app,不出意外,你将在app中看到 2 str2222,在logcat中看到:我来自:222222222222222222

?

?

;原文链接:https://blog.csdn.net/qq_42748190/article/details/115608686
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:Android Parcelable序列化源码解析 下一篇:没有了

推荐图文


随机推荐