有句話說得好:逆向的高度取決于正向開發的高度,
前言:
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://www.uj5u.com/yidong/275821.html
標籤:其他
上一篇:Android開發筆記之視頻錄制
