AutoJs6

- Overview - 综述
- About - 关于文档
- Progress - 文档部署进度
- Changelog - 文档更新日志

- Manual - AutoJs6 使用手册
- Q & A - 疑难解答

- Global - 全局对象
- Automator - 自动化
- AutoJs6 - 本体应用
- App - 通用应用
- Color - 颜色
- Image - 图像
- OCR - 光学字符识别
- Barcode - 条码
- QR Code - 二维码
- Keys - 按键
- Device - 设备
- Storage - 储存
- File - 文件
- Engine - 引擎
- Task - 任务
- Module - 模块
- Plugins - 插件
- Toast - 消息浮动框
- Notice - 消息通知
- Console - 控制台
- Shell
- Shizuku
- Media - 多媒体
- Sensor - 传感器
- Recorder - 记录器
- Timer - 定时器
- Thread - 线程
- Continuation - 协程
- Event - 事件监听
- Dialog - 对话框
- Floaty - 悬浮窗
- Canvas - 画布
- UI - 用户界面
- Web - 万维网
- HTTP
- Base64
- Crypto - 密文
- Internationalization - 国际化
- Standardization - 标准化
- E4X

- UiSelector - 选择器
- UiObject - 控件节点
- UiObjectCollection - 控件集合
- UiObjectActions - 控件节点行为
- WebSocket
- EventEmitter - 事件发射器
- ImageWrapper - 包装图像类
- App - 应用枚举类
- Color - 颜色类
- Version - 版本工具类
- Polyfill - 代码填泥
- Arrayx - Array 扩展
- Numberx - Number 扩展
- Mathx - Math 扩展

- Exceptions - 异常
- Intent - 意图
- Runtime - 运行时
- Context - 上下文
- Activity - 活动

- Scripting Java - 脚本化 Java
- Android API Level - 安卓 API 级别
- Color Table - 颜色列表

- Glossaries - 术语
- HttpHeader - HTTP 标头
- HttpRequestMethods - HTTP 请求方法
- MimeType - MIME 类型
- NotificationChannel - 通知渠道

- Data Types - 数据类型
- Omnipotent Types - 全能类型
- Storage - 存储类
- AndroidBundle
- AndroidRect
- CryptoCipherOptions
- CryptoKey
- CryptoKeyPair
- ConsoleBuildOptions
- HttpRequestBuilderOptions
- HttpRequestHeaders
- HttpResponseBody
- HttpResponseHeaders
- HttpResponse
- InjectableWebClient
- InjectableWebView
- NoticeOptions
- NoticeChannelOptions
- NoticePresetConfiguration
- NoticeBuilder
- Okhttp3HttpUrl
- OcrOptions
- Okhttp3Request
- OpencvPoint
- OpencvRect
- OpencvSize

- GitHub - 应用项目地址
- GitHub - 文档项目地址

# 脚本化 Java#

Rhino 引擎提供了脚本化 Java 的便捷性.

> 注: 此章节参考并修改自 Auto.js Pro 及 Scripting Java.

> 注: ECMA 标准并未包含与 Java 的交互, 本章节所有功能均作为扩展功能而非语言标准使用.

## 访问 Java 包和类#

Rhino 定义了顶层变量 `Packages`, 可用于访问顶层 Java 包 (如 [ java / com ] 等).

    typeof Packages === 'object'; // true
    typeof Packages.java === 'object'; // true

为了便于访问, Rhino 提供了顶层包名前缀的快捷访问方式.

    Packages.java === java; // true

> 注: AutoJs6 顶层化的包名前缀包括 [ android / androidx / java / javax / org / com / net / de / ezy / kotlin / okhttp3 ].

顶层方法 `importPackage` 及 `importClass` 可以像 `import` 语句一样导入包或类.

    importPackage(java.io);
    typeof File === 'object'; // true

上述示例相当于 Java 的导入声明语句 `import java.io.*;`

    importClass(java.io.File);
    typeof File === 'object'; // true

上述示例相当于 Java 的导入声明语句 `import java.io.File;`

    const File = java.io.File;
    typeof File === 'object'; // true

上述示例也可使用解构赋值方式导入 File 类: `const {File} = java.io;`

> 注: 配合 TypeScript Declarations 的 IDE 可能对解构赋值变量无法进行类型识别和代码智能提示.
> 因此建议使用原始变量声明方式导入需要使用的类.
> 对于 importClass 和 importPackage, 目前还未能实现类型识别和代码智能提示 (截至 2022 年 7 月).

## 访问扩展的包及类#

AutoJs6 的项目扩展库及项目依赖包均可直接访问.

    /* 依赖包: implementation("joda-time:joda-time:2.10.14") */
    typeof org.joda.time.LocalDateTime.now; // "function"

    /* 扩展库: implementation(project(":libs:org.opencv-4.5.5")) */
    typeof org.opencv.core.Point; // "function"

## 与 Java 协作#

Rhino 提供了在 JavaScript 代码中 [ 创建 Java 类 / 调用 Java 方法 / 访问变量 ] 等能力.

### Java 类及方法#

    let builder = new java.lang.StringBuilder();
    builder.append('foo');
    builder.append('bar');
    builder.toString(); // "foobar"

### Java 类的静态方法及字段#

    java.lang.Math.PI; // 3.141592653589793
    java.lang.Math.cos(0); // 1

### Java 重载方法签名#

    new java.io.File("foo").listFiles.toString();

    /* 代码结果 (共 5 行) */

    // function listFiles() {/*
    //     java.io.File[] listFiles(java.io.FileFilter)
    //     java.io.File[] listFiles(java.io.FilenameFilter)
    //     java.io.File[] listFiles()
    // */}

### JavaBean 属性#

读写方法符合以下命名规范的类称为 JavaBean:

    /* 读方法 */
    getXyz(): Type
    /* 写方法 */
    setXyz(Type value): void

以下 JavaBean 示例 (Student) 定义了 age 和 sex 属性:

    public class Student {

        private int mAge;

        public int getAge() { return mAge; }
        public void setAge(int anAge) { mAge = anAge; }

        public String getSex() { return "male"; }

    };

其中 age 属性可读写, 而 sex 属性只读.

在 JavaScript 代码中可通过实例成员访问属性及方法:

    let stu = new Student();
    stu.sex; // "male" - 相当于 stu.getSex();
    stu.age = 33; /* 相当于 stu.setAge(33); */
    stu.age; // 33
    stu.getAge(); // 33

同样地, 对于属性类型为 boolean 类型的 JavaBean:

    public class Student {

        private boolean mMale;

        public boolean isMale() { return mMale; }
        public String setMale(boolean value) { mMale = value; }

    };

JavaScript 使用方式:

    let stu = new Student();
    stu.male; // false - 相当于 stu.isMale();
    stu.male = true; /* 相当于 stu.setMale(true); */
    stu.male; // true
    stu.isMale(); // true

## 实现 Java 接口#

### 函数转换#

    "ui";

    ui.layout(
        <frame>
            <button id="btn" text="BUTTON"/>
        </frame>
    );

    let listener = new android.view.View.OnClickListener(function (view) {
        toastLog("clicked");
    });
    ui.btn.setOnClickListener(listener);

上述示例将 JavaScript 函数作为 Java 接口传入 `OnClickListener` 方法.
将函数作为接口使用的条件: 接口只有一个方法 (不可为 0 或多于 1 个) 且参数类型依次匹配.

### 对象转换#

若 Java 接口有多个方法, 则可传入一个 JavaScript 对象:

    public interface OnAttachStateChangeListener {
        public void onViewAttachedToWindow(View v);
        public void onViewDetachedFromWindow(View v);
    }

JavaScript 代码实现:

    new android.view.View.OnAttachStateChangeListener({
        onViewAttachedToWindow(view) {
            toastLog('attached');
        },
        onViewDetachedFromWindow(view) {
            toastLog('detached');
        },
    });

## JavaAdapter 构造器#

### 实现 Java 接口#

    new JavaAdapter(android.view.View.OnAttachStateChangeListener, {
        onViewAttachedToWindow(view) {
            toastLog('attached');
        },
        onViewDetachedFromWindow(view) {
            toastLog('detached');
        }
    });

### 实现多个 Java 接口#

    /* 语法: new JavaAdapter(javaIntfOrClass, [javaIntf, ..., javaIntf,] javascriptObject) */

    new JavaAdapter(android.view.View.OnAttachStateChangeListener, java.lang.Runnable, {
        onViewAttachedToWindow(view) {
            toastLog('attached');
        },
        onViewDetachedFromWindow(view) {
            toastLog('detached');
        },
        run() {
            toastLog('run');
        }
    });

### 继承 Java 类并重写方法#

    "ui";

    ui.layout(
        <vertical>
            <frame id="container"/>
        </vertical>
    );

    let paint = new Paint();
    /* android.view.View 构造器的参数. */
    let viewParam = activity;
    let view = new JavaAdapter(android.view.View, {
        onDraw(canvas) {
            /* 调用父类 View 的 onDraw 方法. */
            this.super$onDraw(canvas);
            canvas.drawRect(500, 500, 1000, 1000, paint);
        },
    }, viewParam);

    ui.container.addView(view);