加载apk,arr,aab,jar
AS 可以将一个apk,arr,aab,jar 文件导入,加载并执行APK文件中的类
如果您加载的apk中包含arr,arr中包含so 那么需要将arr中的so拷贝一份放在apk的libs中即可正常加载.
如果apk,arr中包含so库,也会一并加载.
整个过程通过反射实现 如果您掌握一点java的反射知识,那将更容易上手~
加载
此方法会将apk,arr,jar,aab等文件加载进一个DexLoader中,方便后续通过反射拿到其中的类.
from ascript.android import plug
- 函数
plug.load_apk(file_path:str)
- 参数
参数 | 类型 | 是否必填 | 说明 |
---|---|---|---|
file_path | str | 是 | apk文件的绝对路径 |
- 返回值
dalvik.system.DexClassLoader<?> //class 对象.
拿到该对象,我们可以通过java 反射,创建类的实例,并运行其内部方法等等..
- 示例:
from java.lang import Class
from ascript.android import plug
# 加载apk,获取 DexClassLoader 对象
clazz_loader = plug.load_apk("sdcard/my.apk")
# 获取 Apk中的类
clazz = Class.forName("com.aojoy.apkplug.TestPlug", True, clazz_loader);
# 获取 获取公共(无参数)构造
constructor = clazz.getConstructor()
# 创建类的实例
instance = constructor.newInstance();
# 获取成员方法run
method = clazz.getMethod("run");
# 执行成员方法
method.invoke(instance);
反射参数与类型转换
反射参数类型
在通过反射获取java构造函数或某个方法时,通常需要需要写入的参数类型.
在python 中如何写入这些类型呢?
java参数类型 | Python导入包 | Python反射获取java方法参数类型写法 |
---|---|---|
String | from java.lang import String | clazz.getMethod("java方法名称", String) |
int | from java.lang import Integer | clazz.getMethod("java方法名称", Integer.TYPE) |
float | from java.lang import Float | clazz.getMethod("java方法名称", Float.TYPE) |
double | from java.lang import Double | clazz.getMethod("java方法名称", Double.TYPE) |
long | from java.lang import Long | clazz.getMethod("java方法名称", Long.TYPE) |
Python类型转Java实参类型
一个Python的布尔型(bool)、整型(int)、浮点型(float)或字符串(str)对象可以直接传递给任何兼容的Java方法参数或字段。
然而,Java拥有比Python更多的基本数据类型,因此,当方法调用存在多个适用的整型或浮点型重载时,将使用参数类型最长的那个。类似地,当将一个单字符字符串传递给一个同时拥有String和char类型重载的方法时,将使用String类型的重载。
- 如果上述规则不能得到期望的结果,可以使用以下包装类来选择您想要使用的Java基本数据类型:
# 转java boolean
class java.jboolean(value)
# 转java byte
class java.jbyte(value, truncate=False)
# 转java short
class java.jshort(value, truncate=False)
# 转java int
class java.jint(value, truncate=False)
# 转java long (python int 默认会转为java long)
class java.jlong(value, truncate=False)
# 转java float
class java.jfloat(value, truncate=False)
# 转java double
class java.jdouble(value, truncate=False)
# 转java jchar
class java.jchar(value)
# 转java jvoid 无法被实例化,但在定义静态代理时可以作为返回类型使用。
class java.jvoid
数值类型包装器接受一个可选的truncate
参数。如果设置了该参数,那么给定值的任何多余的高位将被丢弃,就像在Java中进行类型转换一样。否则,向包装器类传递一个超出范围的值将导致OverflowError。
当使用这些包装器时,将应用Java的重载解析规则来处理被包装的参数。例如,一个jint只适用于Java的int或更大的类型,并且会使用最短的可适用重载。
- 案例
from java import jint,jboolean,jlong,jdouble
a = jint(10)
b = jboolean(True)
c = jlong(10)
d = jdouble(10.2222)
获取构造函数
java 创建一个类实例的函数
java 因为参数的不同,可能会有多个构造函数.
- 先获取某个apk下的java类实例
# 获取 Apk中的类
from java.lang import Class
from ascript.android import plug
# 加载apk,获取 DexClassLoader 对象
clazz_loader = plug.load_apk("sdcard/my.apk")
# 获取 Apk中的类
clazz = Class.forName("com.aojoy.apkplug.TestPlug", True, clazz_loader);
from java.lang import Class, String, Float, Integer
获取无参构造与创建实例
from java.lang import Class
from ascript.android import plug
# 加载apk,获取 DexClassLoader 对象
clazz_loader = plug.load_apk("sdcard/my.apk")
# 获取 Apk中的类
clazz = Class.forName("com.aojoy.apkplug.TestPlug", True, clazz_loader);
# 获取 获取公共(无参数)构造
constructor = clazz.getConstructor()
# 创建类的实例
instance = constructor.newInstance();
获取有参构造函数
from java.lang import Class
from ascript.android import plug
from java.lang import String,Integer
from java import jfloat, jint, jarray
# 加载apk,获取 DexClassLoader 对象
clazz_loader = plug.load_apk("sdcard/my.apk")
# 获取 Apk中的类
clazz = Class.forName("com.aojoy.apkplug.TestPlug", True, clazz_loader);
# 获取 获取公共(无参数)构造
constructor = clazz.getDeclaredConstructor(String, Integer.TYPE)
# 创建类的实例
instance = constructor.newInstance("张三",jint(18));
获取属性与方法
静态属性,成员属性,静态方法,成员方法 的获取方式一致.
区别在于执行该方法时,传入的第一个参数
.
-
如果第一个参数传入为None,则代表获取静态属性或执行静态方法.
-
如 果第一个参数传入为类实例对象,则代表获取成员属性或成员方法.
获取-某个属性或方法
# 获取 Apk中的类
from java.lang import Class
from ascript.android import plug
from java.lang import String,Integer
from java import jfloat, jint, jarray
# 加载apk,获取 DexClassLoader 对象
clazz_loader = plug.load_apk("sdcard/my.apk")
# 获取 Apk中的类
clazz = Class.forName("com.aojoy.apkplug.TestPlug", True, clazz_loader);
- 假如方法和属性是静态的,执行案例
# 反射某个静态方法,并执行. 静态方法的第一个参数为None(代表无实例)
# 这里的反射类型,请见 #反射参数与类型转换
clazz.getDeclaredMethod("save",String,Integer.TYPE)
clazz.invoke(None,"张三",jint(18))
# 反射某个静态属性
static_field = clazz.getDeclaredField("name")
name_val = static_field.get(None)
- 假如方法和属性为对象的,执行案例
# 获取 获取公共(无参数)构造,创建类的实例
constructor = clazz.getConstructor()
instance = constructor.newInstance()
# 反射某个静态方法,并执行. 成员方法或属性,第一个参数为对象实例
# 这里的反射类型,请见 #反射参数与类型转换
clazz.getDeclaredMethod("save",String,Integer.TYPE)
clazz.invoke(instance,"张三",jint(18))
# 反射某个静态属性
static_field = clazz.getDeclaredField("name")
name_val = static_field.get(instance)
获取-所有属性案例
# Method[] methods = clazz.getDeclaredFields();
from java.lang import Class
from ascript.android import plug
from java.lang import String,Integer
from java import jfloat, jint, jarray
# 加载apk,获取 DexClassLoader 对象
clazz_loader = plug.load_apk("sdcard/my.apk")
# 获取 Apk中的类
clazz = Class.forName("com.aojoy.apkplug.TestPlug", True, clazz_loader);
# 获取类中的所有静态属性,返回值为数组[属性字段,属性字段]
fields = clazz.getDeclaredFields()
# 将属性数组转换为一个 字典{属性名:属性对象,....},方便后期使用
py_fields = {}
for field in fields:
py_fields[field.getName()] = field
- 假如类中有一个name 静态属性,执行案例
name = field["name"].get(None)
- 假如类中有一个name 成员属性,执行案例
# 获取 获取公共(无参数)构造,创建类的实例
constructor = clazz.getConstructor()
instance = constructor.newInstance()
name = field["name"].get(instance)
# 打印获取到的name属性
pritn(name)
获取-所有方法案例
# Method[] methods = clazz.getDeclaredMethods();
from java.lang import Class
from ascript.android import plug
from java.lang import String,Integer
from java import jfloat, jint, jarray
# 加载apk,获取 DexClassLoader 对象
clazz_loader = plug.load_apk("sdcard/my.apk")
# 获取 Apk中的类
clazz = Class.forName("com.aojoy.apkplug.TestPlug", True, clazz_loader);
# 获取类中的所有静态方法,返回值为数组[方法,方法]
methods = clazz.getDeclaredMethods()
# 将方法转换为一个 字典{方法名:方法,....},方便后期使用
py_methods = {}
for m in methods:
py_methods[m.getName()] = m
- 假如类中有一个静态save(String a,int b)方法,执行案例
py_methods["save"].invoke(None,"张三",jint(18))
- 假如类中有一个成员save(String a,int b)方法,执行案例
# 获取 获取公共(无参数)构造,创建类的实例
constructor = clazz.getConstructor()
instance = constructor.newInstance()
py_methods["save"].invoke(instance,"张三",jint(18))