第1步:新建一个Android Studio 工程 gmos。新建一个GmosJni.java文件。 第2步:点击一下 make project 会在app的build目录下面生成.class文件。 第3步,在app/src/main文件夹下新建一个jni文件夹,然后打开Android Studio的Terminal终端,cd到这个目录,然后输入下面的指令
javah -jni -classpath F:\MyWorkSpace\android_worksapce\mosToSo\gmos\app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes mlab.android.gmos.GmosJni
就会在这个jni文件夹下生成一个.h文件,mlab_android_gmos_GmosJni.h,文件内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class mlab_android_gmos_GmosJni */
#ifndef _Included_mlab_android_gmos_GmosJni
#define _Included_mlab_android_gmos_GmosJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: mlab_android_gmos_GmosJni
* Method: calMOSc
* Signature: ([Lmlab/android/gmos/pojo/CloudGameInfo;I)[D
*/
JNIEXPORT jdoubleArray JNICALL Java_mlab_android_gmos_GmosJni_calMOSc
(JNIEnv *, jclass, jobjectArray, jint);
#ifdef __cplusplus
}
#endif
#endif
第4步:在jni目录下新建一个c/c++source file ,取名mlab_android_gmos_GmosJni.cpp 实现上面.h文件中的方法。
//
// Created by Administrator on 2019/11/22.
//
#include "gMOS.h"
#include "mlab_android_gmos_GmosJni.h"
JNIEXPORT jdoubleArray JNICALL Java_mlab_android_gmos_GmosJni_calMOSc
(JNIEnv *env, jclass jz, jobjectArray cloudGameFullInfo , jint InfoArrLen){
int size = env->GetArrayLength(cloudGameFullInfo);
CloudGameInfo cloudGameInfo[size];
int i = 0;
for (i = 0; i < size; i++) {
jobject obj_cloudGameFullInfo = (jobject) env->GetObjectArrayElement(cloudGameFullInfo, i);
jclass cls_cloudGameInfo = env->GetObjectClass(obj_cloudGameFullInfo);
//video_codec
jfieldID video_codecFieldID = env->GetFieldID(cls_cloudGameInfo, "video_codec", "I");
jint video_codec = env->GetIntField(obj_cloudGameFullInfo, video_codecFieldID);
//video_bitrate
jfieldID video_bitrateFieldID = env->GetFieldID(cls_cloudGameInfo, "video_bitrate", "D");
jdouble video_bitrate = env->GetDoubleField(obj_cloudGameFullInfo, video_bitrateFieldID);
//video_framerate
jfieldID video_framerateFieldID = env->GetFieldID(cls_cloudGameInfo, "video_framerate", "D");
jdouble video_framerate = env->GetDoubleField(obj_cloudGameFullInfo, video_framerateFieldID);
//video_horizontal_resolution
jfieldID video_horizontal_resolutionFieldID = env->GetFieldID(cls_cloudGameInfo, "video_horizontal_resolution", "D");
jdouble video_horizontal_resolution = env->GetDoubleField(obj_cloudGameFullInfo, video_horizontal_resolutionFieldID);
//video_vertical_resolution
jfieldID video_vertical_resolutionFieldID = env->GetFieldID(cls_cloudGameInfo, "video_vertical_resolution", "D");
jdouble video_vertical_resolution = env->GetDoubleField(obj_cloudGameFullInfo, video_vertical_resolutionFieldID);
//ppd
jfieldID ppdFieldID = env->GetFieldID(cls_cloudGameInfo, "ppd", "D");
jdouble ppd = env->GetDoubleField(obj_cloudGameFullInfo, ppdFieldID);
//device_framerate
jfieldID device_framerateFieldID = env->GetFieldID(cls_cloudGameInfo, "device_framerate", "D");
jdouble device_framerate = env->GetDoubleField(obj_cloudGameFullInfo, device_framerateFieldID);
//audio_bitrate
jfieldID audio_bitrateFieldID = env->GetFieldID(cls_cloudGameInfo, "audio_bitrate", "D");
jdouble audio_bitrate = env->GetDoubleField(obj_cloudGameFullInfo, audio_bitrateFieldID);
//audio_video_asyn_delay
jfieldID audio_video_asyn_delayFieldID = env->GetFieldID(cls_cloudGameInfo, "audio_video_asyn_delay", "D");
jdouble audio_video_asyn_delay = env->GetDoubleField(obj_cloudGameFullInfo, audio_video_asyn_delayFieldID);
//operration_response_delay_average
jfieldID operration_response_delay_averageFieldID = env->GetFieldID(cls_cloudGameInfo, "operration_response_delay_average", "D");
jdouble operration_response_delay_average = env->GetDoubleField(obj_cloudGameFullInfo, operration_response_delay_averageFieldID);
//audio_video_asyn_delay
jfieldID packet_loss_rate_averageFieldID = env->GetFieldID(cls_cloudGameInfo, "packet_loss_rate_average", "D");
jdouble packet_loss_rate_average = env->GetDoubleField(obj_cloudGameFullInfo, packet_loss_rate_averageFieldID);
CloudGameInfo info;
info.video_codec = video_codec;
info.video_bitrate = video_bitrate;
info.video_framerate = video_framerate;
info.video_horizontal_resolution = video_horizontal_resolution;
info.video_vertical_resolution = video_vertical_resolution;
info.ppd = ppd;
info.device_framerate = device_framerate;
info.audio_bitrate = audio_bitrate;
info.audio_video_asyn_delay = audio_video_asyn_delay;
info.operration_response_delay_average = operration_response_delay_average;
info.packet_loss_rate_average = packet_loss_rate_average;
cloudGameInfo[i] = info;
}
GMOS gmos = calMOSc(cloudGameInfo,InfoArrLen);
jdouble value_array[5];
value_array[0] = gmos.MOSv;;
value_array[1] = gmos.MOSav;
value_array[2] = gmos.MOSi;
value_array[3] = gmos.MOSp;
value_array[4] = gmos.MOSc;
jdoubleArray ret;
ret = env->NewDoubleArray(5);
env->SetDoubleArrayRegion(ret, 0, 5, value_array);
return ret;
}
第5步:在jni文件夹下新建Android.mk和Application.mk文件 Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := _gmos
LOCAL_SRC_FILES := mlab_android_gmos_GmosJni.cpp\
gMOS.cpp
include $(BUILD_SHARED_LIBRARY)
APP_ABI := all
第6步,关联下载好的ndk包 第7步:在终端Terminal进入到jni目录,输入指令 ndk-build,就会生成相应的so文件。 第8步:调用so文件。 在app的bulid文件中加入如下代码,然后build project
android {
...
sourceSets {
main() {
jniLibs.srcDirs = ['src/main/libs']
jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
}
}
}
package mlab.android.gmos;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import mlab.android.gmos.pojo.CloudGameInfo;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.sample_text);
CloudGameInfo[] cloudGameInfos = {new CloudGameInfo()};
double[] re = GmosJni.calMOSc(cloudGameInfos,1);
String rr = "";
for (int i = 0; i < re.length; i++) {
rr += re[i] + "***";
}
textView.setText(rr);
}
}
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
运行结果
接下来是打jar包使用so文件
第1步:删除一些无用的资源,如MainActivity,layout等,只留下和JNI有关的java类 第2步:修改module的build.gradle文件 修改一:将最前面的apply plugin: 'com.android.application’修改为apply plugin: ‘com.android.library’ 修改二:将defaultConfig修改为(版本根据需要修改):
defaultConfig {
minSdkVersion 16
targetSdkVersion 29
}
android {
...
task deleteOldJar(type: Delete) {
delete 'build/outputs/test.jar'
}
task exportJar(type: Copy) {
from('build/intermediates/packaged-classes/release/')
into('build/libs/')
include('classes.jar')
rename ('classes.jar', 'gmos.jar')
}
exportJar.dependsOn(deleteOldJar, build)
}
第3步:导出jar包,打开Gradle,打开app->Tasks->other->exportJar 双击exportJar
使用jar包
第1步:将so文件与jar包放入项目libs文件夹中 第:2步:在app的bulid文件中加入如下代码,然后build project
android {
...
sourceSets {
main() {
jniLibs.srcDirs = ['libs']
jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
}
}
}
第3步:multiDexEnabled true 与 implementation ‘com.android.support:multidex:1.0.1’ 第4步:在在MainActivity中调用,显示结果