Android项目中创建Library模块

步骤:项目名称右键->New->Moudle->Android Library

编译:

编译单独模块:选中模块->Build->Make Moudle

旧版本产出位置:模块\build\intermediates\packaged-classed\debug\

新版本产出位置:模块\build\intermediates\arr_main_jar\debug\

使用Android SDK中的dx工具生成

dx位置:AndroidSDK根目录\build-tools\28.0.3\dx.bat

用法:dx.bat–dex–output=xx srcDir

set filename=test2.jar
set srcDir=D:\__job\study20230717-pkgJar\pkgJarForLoad\mylibrary1\build\intermediates\aar_main_jar\debug\
set dx="D:\Android SDK\build-tools\34.0.0\d8.bat"
del out\%filename%
call %dx% --dex --output=out\%filename% %srcDir%
pause

使用gradlew生成

模块内build.gradle添加:

task makeJar(type:Copy)

{

//删除旧的jar

delete 'build/libs/test.jar'

//设置源.jar目录

from('build/intermediates/arr_main_jar/release')

//设置产出目录

into('build/libs/')

//设置源目录内文件过滤

include('classes.jar')

//重命名

rename('classes.jar','test.jar)

}

项目根目录执行Ctrl+Enter:

gradlew makeJar

NDK编程

创建NDK项目及JNI函数

创建NDK项目:

1、下载ndk

2、创建so项目

NDK(Native Development Kit)是Android提供的一个工具集,允许开发者使用C或C++等本地语言编写部分Android应用的代码,并通过JNI(Java Native Interface)与Java代码进行交互。NDK主要用于提高应用程序的性能、复用现有的本地代码库以及访问设备硬件等功能

创建JNI函数

1、函数命名规则

2、参数

JNI(Java Native Interface)是Java提供的一种机制,用于实现Java代码与本地(Native)代码(如C、C++等)之间的交互和通信。它允许Java应用程序调用本地方法(Native Method),也允许本地方法调用Java代码。

函数签名

作用:函数的身份证

方法:javap -s a.b.cjavareflection.Student获取签名

例子( descriptor: (Ljava/lang/String;DJ)I)

读写SD卡文件

权限:静态申请权限、动态申请权限、检查自己权限

读取文件:fopen、fgets、fput、fclose

MainActivity

package a.b.c.ndk01;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.PackageManagerCompat;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import a.b.c.ndk01.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity
{

private final static int MY_PERMISSIONS_REQUEST_WRITE_CODE = 11;
// Used to load the 'ndk01' library on application startup.
static {
System.loadLibrary("ndk01");
}
public int testFun(String a,Double b,long c)
{
return 1;
}


private ActivityMainBinding binding;

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch(requestCode)
{
case MY_PERMISSIONS_REQUEST_WRITE_CODE:
{
if(grantResults.length>0 && grantResults[0]!=-1)
{
Log.i("qqqqqq","写SDCard权限申请成功");
}
else
{
Log.i("qqqqqq","写SDCard权限申请失败");
}
break;
}
case 33:
{
Log.i("qqqqqq","这里是申请其他权限的结果");
break;
}
}


}

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);

binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
testFun("aa",4.5,5);

// Example of a call to a native method
TextView tv = binding.sampleText;
tv.setText(stringFromJNI());
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
int ret = ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);// ContextCompat这里选Android
if(ret == PackageManager.PERMISSION_GRANTED)
{
Log.i("qqqqqq","已经有写SDCar的权限");
String fp1 = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
String fc = readSDcardFile(fp1+"b.txt");
Log.i("qqqqqq","文件内容" + fc);
}
else
{
Log.i("qqqqqq","还没有写SDCar的权限");
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},MY_PERMISSIONS_REQUEST_WRITE_CODE);
}
}
});
}

/**
* A native method that is implemented by the 'ndk01' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
public native int getlength(String param);
public native String readSDcardFile(String filepath);
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Ndk01"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

jni.h

extern "C"
JNIEXPORT jstring JNICALL
Java_a_b_c_ndk01_MainActivity_readSDcardFile(JNIEnv *env, jobject thiz, jstring filepath) ;
// TODO: implement readSDcardFile()

native-lib.cpp

extern "C"
JNIEXPORT jstring JNICALL
Java_a_b_c_ndk01_MainActivity_readSDcardFile(JNIEnv *env, jobject thiz, jstring filepath)
{
char* filePath = (char*)env->GetStringUTFChars(filepath,0);
FILE *fp;
jstring jstring_ret = env->NewStringUTF("null");
char *tmp = (char*)env->GetStringUTFChars(jstring_ret,0);
fp = fopen(filePath,"r");//"r":只读模式,文件必须存在。
if(fp == NULL)
{
LOGE("fp == NULL, %s",filePath);
return jstring_ret;
}
char buff[1024];
while(fgets(buff,1024,fp)!=NULL)
{
LOGI("fgets :%s",buff)
}
env->ReleaseStringChars(jstring_ret,reinterpret_cast<const jchar*>(tmp));
jstring_ret = env->NewStringUTF(buff);
}

JNI 签名规则

在JNI中,方法签名采用一种特定的格式,用于描述Java方法的参数类型和返回值类型。格式为:

  • 参数类型:
    • Z:boolean
    • B:byte
    • C:char
    • S:short
    • I:int
    • J:long
    • F:float
    • D:double
    • Lfully/qualified/ClassName;:对象类型,如 Ljava/lang/String;
    • [Type:数组类型,如 [I 表示 int[]
    • ():分别用于标识方法的开始和结束

Java反射

作用:获取和操作已经装载的类。

函数:

1、获取类:

1.1Class.forName(“类名全路径”) 1.2类名.class c 1.3实例.getClass()

2、获取方法和属性:

2.1 类.getDeclareMethods() 2.2类.getDeclaredConstructors() 2.3类.getMethod() 2.4类.getDeclaredFields()

public void fun2()
{
Class clz = Student.class;

try
{
Method method_study = clz.getMethod("study",new Class[]{int.class});
Constructor constructor_Student = clz.getConstructor(new Class[]{String.class,int.class});
Student student = (Student) constructor_Student.newInstance(new Object[]{"lisi",25});
Object obj_ret = method_study.invoke(student,new Object[]{77});
Log.i("qqqqqqqq","study ret:" + (String) obj_ret);
}catch (Exception ee)
{
ee.printStackTrace();

3、调用方法:

3.1方法.invoke()

public void fun3()
{
Class clz = one.getClass();
try
{
Method method_getAge0 = clz.getDeclaredMethod("getAge");
method_getAge0.setAccessible(true);
Method method_getAge = clz.getMethod("getAge",new Class[]{});
Object obj_ret = method_getAge.invoke(one,new Object[]{});
Log.i("qqqqqqq","getAge ret"+(int)obj_ret);
}catch (Exception ee)
{
ee.printStackTrace();
}
}

NDK反射Java层

作用:NDK层代码可以获取、调用java层方法和变量

函数:

1、获取类:

1.1jclass GetObjectClass(对象) 1.2jclass FindClass(“类名”)

2、获取方法ID:(javap -s a.b.c.javareflectiontest.Student获取签名)

2.1jmetthodID GetMethodID(jclass,const char*name,const char(sig))

2.2jmethodID GetstaticMethodID(jclass clazz,const char*name,const char(sig))

3、调用方法:

3.1void CallVoidMethod(jobject obj,jmethodID,methodID,…)

3.2void CallStaticVoidMethod(jclass clazz,jmethodID,methodID,….)

3.3jobject CallObjectMethod(JNEnv*,jobject,jmethodID,….)

4、获取和设置成员变量

4.1GetFieldID

4.2GetObjectField

4.3SetObjectField

extern "C"
JNIEXPORT jstring JNICALL
Java_a_b_c_ndk01_MainActivity_callStaticJavaFunJNI(JNIEnv *env, jobject thiz)
{
jclass jclass_student2 = env->FindClass("a/b/c/ndk01/Student");
jmethodID jmethodId_calcLength = env->GetStaticMethodID(jclass_student2,"calcLength", "(Ljava/lang/String;)I");
jstring jstring_param = env->NewStringUTF("hahahaha");
jint jint_ret = env->CallStaticIntMethod(jclass_student2,jmethodId_calcLength,jstring_param);
LOGI("ndk call calcLength ret: %d",jint_ret);
return jstring_param;
}