Skip to main content

加载apk,arr,aab,jar

AS 可以将一个apk,arr,aab,jar 文件导入,加载并执行APK文件中的类

apk中包含arr?

如果您加载的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_pathstrapk文件的绝对路径
  • 返回值
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方法参数类型写法
Stringfrom java.lang import Stringclazz.getMethod("java方法名称", String)
intfrom java.lang import Integerclazz.getMethod("java方法名称", Integer.TYPE)
floatfrom java.lang import Floatclazz.getMethod("java方法名称", Float.TYPE)
doublefrom java.lang import Doubleclazz.getMethod("java方法名称", Double.TYPE)
longfrom java.lang import Longclazz.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))