加载apk、aar、aab、jar
AS 可以将一个apk,arr,aab,jar 文件导入,加载并执行其中的类
如果apk,arr中包含so库,也会一并加载.
整个过程通过使用JQQR实现
apk中包含arr?
如果您加载的apk中包含arr,arr中包含so 那么需要将arr中的so拷贝一份放在apk的libs中即可正常加载.
jar包需要转换
传统的jar包无法加载,需要android工具进行转换.
获取类加载器ClassLoader
此方法会将apk,arr,jar,aab等文件加载进一个DexClassLoader中.
通过DexClassLoader,我们可以访问包中的类.
from ascript.android import plug
classloader = plug.load_apk(file_path:str)
使用案例
- 假如在你的工程res目录下包含 一个 app-release.apk 文件. 且apk中包含 一个Person类
// Java Person类结构
package com.aojoy.plug.testloader;
public class Person {
public static String a = "a_public";
private static String b = "b_private";
public String name;
private int age;
public Person(){}
public Person(String name,int age){
this.age = age;
this.name = name;
}
public String eat(){
return this.name +"吃饭了";
}
public String eat(String what){
return this.name +"吃的是"+what;
}
public static Person create(){
return new Person();
}
public static Person create(String name,int age){
return new Person(name,age);
}
}
- 用 python 动态加载apk 中 Person类
# 在Python加载apk中的Person的属性方法
from ascript.android.system import R
from ascript.android import plug
from org.joor import Reflect
from java import jint,jboolean,jlong,jdouble
# 加载项目res目录下的 app-release.apk
classloader = plug.load_apk(R.res("app-release.apk"))
# 获取类
person_class = Reflect.onClass("com.aojoy.plug.testloader.Person",classloader)
# 下面是操作类
# 获取静态公共属性
a_static_public_filed = person_class.field("a").get()
# 获取静态私有属性
b_static_public_filed = person_class.field("b").get()
# 访问静态有参方法.(python传递给java的数字,默认是long类型.这里用jint转换一下数字)
person = person_class.call("create","张三",jint(18)).get()
# 访问静态无参方法
person = person_class.call("create").get()
# 创建无参对象
person = person_class.create().get()
# 创建有参对象 (python传递给java的数字,默认是long类型.这里用jint转换一下数字)
person = person_class.create("张三",jint(18)).get()
# 获取对象公共属性
person.name
# 获取对象私有属性
age = Reflect.on(person).field("age").get()
# 调用对象方法
res = person.eat()
# 调用对象有参方法
res = person.eat("包子")
# 链式调用
# 找到Person类,创建对象,再调用其中的eat方法,并获取返回结果.
res = Reflect.onClass("com.aojoy.plug.testloader.Person",classloader).create("张三",jint(18)).call("eat").get()
print(res)
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
# java的数组
class java.jarray
数值类型包装器接受一个可选的truncate
参数。如果设置了该参数,那么给定值的任何多余的高位将被丢弃,就像在Java中进行类型转换一样。否则,向包装器类传递一个超出范围的值将导致OverflowError。
当使用这些包装器时,将应用Java的重载解析规则来处理被包装的参数。例如,一个jint只适用于Java的int或更大的类型,并且会使用最短的可适用重载。
- 案例
from java import jint,jboolean,jlong,jdouble,jarray
a = jint(10)
b = jboolean(True)
c = jlong(10)
d = jdouble(10.2222)
# Python code // Java equivalent
jarray(jint)([1, 2, 3]) new int[] {1, 2, 3}
jarray(jarray(jint))([[1, 2], [3, 4]]) new int[][] {{1, 2}, {3, 4}}
jarray(String)(["Hello", "world"]) new String[] {"Hello", "world"}
jarray(jchar)("hello") new char[] {'h', 'e', 'l', 'l', 'o'}