調用第三方的so方法,但這個so內的方法不是標準的jni方法。這就需要我們自己寫jni然后鏈接到第三方so庫,通過jni調用so庫中的方法。
1.簡述:
要先有第三方的so庫.so文件和編譯庫對應的.h頭文件
- 我們自己用 c/c++ 創建一個標準的so 庫,比如 mynative.so
- 然后用我們自己的mynative.so 庫中去調用第三方的libnative.so庫
- 我們在上層 調用我們自己的mynativeso 庫 ,就實現了對第三方 libnativeso 庫 方法的調用。
2.先編譯出一個第三方非標準so庫
1).android studio 新創建一個項目
我們先制作一個非標準 jni 庫,只要功能實現兩個數相加 ,并返回相加后的結果。
2).main 新創建 jni 文件夾
3).新建 .cpp 文件和 .h 實現求和功能,并把文件放在jni目錄下
test.cpp
#include "test.h"
Add::Add(){}
Add::~Add(){}int Add::add(int x, int y){return x + y;
}
test.h
#ifndef _TEST_JNI_ADD_H_
#define _TEST_JNI_ADD_H_class Add{public :Add();~Add();int add(int x, int y);
};
#endif
4).編寫 CMakeLists.txt 用來編譯 cpp 文件為so庫,在 app文件下新建CMakeLists.txt 文件
#指定cmake最小版本
cmake_minimum_required(VERSION 3.4.1)#設置生成的so動態庫最后輸出的路徑
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})#生成so
add_library( # 設置生成庫的名字nativeso# 生成動態庫SHARED# 指定源碼文件,這里指定test.cpp文件src/main/jni/test.cpp )#依賴的頭文件
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src/main/jni)
find_library( # log庫的別名log-lib#log庫log )#鏈接代碼到指定的庫
target_link_libraries( # Specifies the target library.nativeso# Links the target library to the log library# included in the NDK.${log-lib} )
5).配置項目的build.gradle
6).配置 gradle.properties
android.useDeprecatedNdk=true
7).編譯第三方非標準庫,直接運行即可。
3.新建項目引用第三方 so 庫
1)新建 android studio 項目
2)新建 java 類,封裝想要調用的接口函數
package com.example.demo05;public class JniCallNative {static {System.loadLibrary("mynativeso");}public static native int getAddFromNative(int a,int b);
}
3)Main 文件夾新建 jniLibs 文件夾,并拷貝第三方so到此文件夾下
4)創建 對應的 jni java 類文件的頭文件
在Termial控制臺中cd到項目目錄中的源碼目錄下,并執行命令生成.h文件
??javac?-encoding utf-8 -h .??JniCallNative.java
執行完成后,會在 java 目錄生成 對應 .h 文件
5) main 文件夾 下新建 jni文件夾,實現底層邏輯
- 將上一步 生成 .h 文件 拷貝進來,以及第三方so提供的對應.h頭文件也要拷貝到jni目錄中
- 根據.h 文件 編寫 對應的 .cpp 文件 ,在cpp 文件里實現對 第三方 so 庫 的引用
- 自己實現的邏輯中調用第三方.h內容
jninative.cpp?文件
#include <jni.h>
#include <string>
#include <test.h>//導入需要的.h文件,這個是必須的,如果依賴的第三方庫沒有.h,需要自己編寫extern "C"
JNIEXPORT jint JNICALL Java_com_example_demo05_JniCallNative_getAddFromNative(JNIEnv *, jclass, jint a, jint b){//生成add對象并調用方法Add addObj;int result = addObj.add(a,b);return result;}
7) 編寫 自己 so 庫的 CMakeLists.txt 文件
app 文件下新建 CMakeLists.txt
#指定cmake最小版本
cmake_minimum_required(VERSION 3.4.1)
#設置生成的so動態庫最后輸出的路徑
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})#生成so
add_library( # 設置生成庫的名字mynativeso# 生成動態庫SHARED# 指定源碼文件,這里指定test.cpp文件src/main/jni/jninative.cpp )#依賴的頭文件
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src/main/jni)#依賴的add庫
add_library(nativeso SHARED IMPORTED)
set_target_properties(nativesoPROPERTIES IMPORTED_LOCATION${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libnativeso.so)find_library( # log庫的別名log-lib#log庫log )#鏈接代碼到指定的庫
target_link_libraries( # Specifies the target library.mynativeso#add庫需要鏈接nativeso# Links the target library to the log library# included in the NDK.${log-lib} )
8) ?配置環境 build.gradle和?gradle.properties
9) 編譯自己的so庫,直接運行即可
10) 主函數調用測試
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:id="@+id/tv01"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World!"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>
package com.example.demo05;import android.os.Bundle;
import android.widget.TextView;import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);EdgeToEdge.enable(this);setContentView(R.layout.activity_main);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});TextView textView = findViewById(R.id.tv01);int addFromNative = JniCallNative.getAddFromNative(5, 5);textView.setText(addFromNative + "");}
}