From f65ab0fc572283aeca5a73d8a2ce4507c8f4fae1 Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Fri, 21 Dec 2018 14:26:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/assets/docs/all.html | 899 ++++++++++++++---- app/src/main/assets/docs/app.html | 118 ++- app/src/main/assets/docs/assets/fonts.css | 48 + .../assets/fonts/S6u9w4BMUTPHh6UVSwiPGQ.woff2 | Bin 0 -> 22820 bytes .../assets/fonts/S6uyw4BMUTPHjx4wXg.woff2 | Bin 0 -> 23316 bytes app/src/main/assets/docs/canvas.html | 6 +- app/src/main/assets/docs/console.html | 95 +- .../docs/coordinates-based-automation.html | 6 +- app/src/main/assets/docs/device.html | 6 +- app/src/main/assets/docs/dialogs.html | 40 +- app/src/main/assets/docs/documentation.html | 6 +- app/src/main/assets/docs/engines.html | 10 +- app/src/main/assets/docs/events.html | 6 +- app/src/main/assets/docs/files.html | 6 +- app/src/main/assets/docs/floaty.html | 6 +- app/src/main/assets/docs/globals.html | 25 +- app/src/main/assets/docs/http.html | 6 +- app/src/main/assets/docs/images.html | 523 ++++++++-- app/src/main/assets/docs/index.html | 6 +- app/src/main/assets/docs/keys.html | 6 +- app/src/main/assets/docs/media.html | 6 +- app/src/main/assets/docs/modules.html | 12 +- app/src/main/assets/docs/overview.html | 6 +- app/src/main/assets/docs/qa.html | 58 +- app/src/main/assets/docs/sensors.html | 6 +- app/src/main/assets/docs/shell.html | 6 +- app/src/main/assets/docs/storages.html | 6 +- app/src/main/assets/docs/threads.html | 6 +- app/src/main/assets/docs/timers.html | 6 +- app/src/main/assets/docs/ui.html | 11 +- app/src/main/assets/docs/util.html | 6 +- .../assets/docs/widgets-based-automation.html | 93 +- 32 files changed, 1634 insertions(+), 406 deletions(-) create mode 100644 app/src/main/assets/docs/assets/fonts.css create mode 100644 app/src/main/assets/docs/assets/fonts/S6u9w4BMUTPHh6UVSwiPGQ.woff2 create mode 100644 app/src/main/assets/docs/assets/fonts/S6uyw4BMUTPHjx4wXg.woff2 diff --git a/app/src/main/assets/docs/all.html b/app/src/main/assets/docs/all.html index 1920eb19..b9861522 100644 --- a/app/src/main/assets/docs/all.html +++ b/app/src/main/assets/docs/all.html @@ -2,8 +2,8 @@ - 综述 | Auto.js 3.0.0 文档 - + 综述 | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@
-

Auto.js 3.0.0 文档

+

Auto.js 4.1.0 文档

索引 | @@ -77,8 +77,9 @@

  • 综述
  • Q & A
  • @@ -105,6 +106,11 @@
  • app.intent(options)
  • app.startActivity(options)
  • app.sendBroadcast(options)
  • +
  • app.startService(options)
  • +
  • app.sendBroadcast(name)
  • +
  • app.intentToShell(options)
  • +
  • app.parseUri(uri)
  • +
  • app.getUriForFile(path)
  • Console
  • @@ -415,6 +425,8 @@
  • requiresApi(api)
  • requiresAutojsVersion(version)
  • runtime.requestPermissions(permissions)
  • +
  • runtime.loadJar(path)
  • +
  • runtime.loadDex(path)
  • context
  • @@ -462,19 +474,35 @@
  • colors.MAGENTA
  • colors.TRANSPARENT
  • Images +
  • +
  • MatchingResult
  • Image
  • SimpleActionAutomator
      @@ -552,6 +602,7 @@
    • UiSelector
      • selector()
      • +
      • UiSelector.algorithm(algorithm)
      • UiSelector.text(str)
      • UiSelector.textContains(str)
      • UiSelector.textStartsWith(prefix)
      • @@ -933,35 +984,30 @@

        Q & A#

        如何定时运行脚本#

        点击脚本右边的菜单按钮->更多->定时任务即可定时运行脚本,但是必须保持Auto.js后台运行(自启动白名单、电源管理白名单等)。同时,可以在脚本的开头使用device.wakeUp()来唤醒屏幕;但是,Auto.js没有解锁屏幕的功能,因此难以在有锁屏密码的设备上达到效果。

        -

        如何把图片和脚本一起打包,或者打包多个脚本#

        -

        如果除了单脚本以外还有其他脚本、图片、音乐等资源一起打包,则需要使用项目打包功能。

        -
          -
        1. 新建一个文件夹,命名为项目名称。
        2. -
        3. 在该文件夹下新建脚本,或者移动脚本到该文件夹,命名为main.js,表示主脚本。脚本打包后将会从该脚本开始运行。
        4. -
        5. 把其他资源或脚本放在该文件夹,并通过相对路径引用。
        6. -
        7. 通过文件夹菜单的"打包"功能来打包该项目
        8. -
        +

        定时任何如何获取外部参数#

        +

        如果一个脚本是用intent"启动"的,比如定时任务中的特定事件(网络状态变化等)触发而启动的,则可以通过engines.myEngine().execArgv.intent获取启动的intent,从而获取外部参数。

        +

        如何把图片和脚本一起打包,或者打包多个脚本#

        +

        如果除了单脚本以外还有其他脚本、图片、音乐等资源一起打包,则需要使用项目功能。

        +

        点击Auto.js的"+"号,选择项目,填写项目名称、包名等信息以后,点击"√"即可新建一个项目。可以在项目中放多个脚本、模块、资源文件,点击项目工具栏的apk打包图标即可打包一个项目,点击工具栏可以重新配置项目。

        例如,主脚本要读取同一文件夹下的图片1.png,再执行找图,则可以通过images.read("./1.png")来读取,其中"./1.png"表示同一目录1.png图片;ui中的图片控件要引用同一文件夹的2.png图片则为<img src="file://2.png"/>。Auto.js内置的函数和模块都支持相对路径,但是,其他情况则需要使用files.path()函数来把相对路径转换为绝对路径。

        -

        目前Auto.js还不支持项目的图形化管理,后续会加入。

        -

        如何使打包的应用不显示主界面#

        -

        需要使用项目打包功能。

        -
          -
        1. 新建一个文件夹,命名为项目名称。
        2. -
        3. 在该文件夹下新建脚本,或者移动脚本到该文件夹,命名为main.js,表示主脚本。脚本打包后将会从该脚本开始运行。
        4. -
        5. 在该文件夹下新建一个project.json的文件,其内容如下:
          {
          -"name": "项目名称",
          -"versionName": "1.0.0",
          -"versionCode": 1,
          -"packageName": "org.autojs.example",
          -"main": "main.js",
          -"launchConfig": {
          -   "hideLogs": true
          +

          如何使打包的应用不显示主界面#

          +

          需要使用项目功能。新建项目后,修改项目下的project.json文件,增加以下条目:

          +
          "launchConfig": {
          +    "hideLogs": true
           }
          +

          例如:

          +
          {
          +  "name": "项目名称",
          +  "versionName": "1.0.0",
          +  "versionCode": 1,
          +  "packageName": "org.autojs.example",
          +  "main": "main.js",
          +  "launchConfig": {
          +      "hideLogs": true
          +  }
           }
          -
          其中,项目名称改为自己的项目名称,"org.autojs.example"改成自己的包名,下面的"launchConfig"表示启动配置,"hideLogs"表示隐藏日志。
        6. -
        7. 通过文件夹菜单的"打包"功能来打包该项目
        8. -
        -

        有关项目打包和配置的更多信息,参见项目与项目配置(待补)。

        +

        "launchConfig"表示启动配置,"hideLogs"表示隐藏日志。

        +

        参见项目与项目配置。

        Auto.js自带的模块和函数中没有的功能如何实现#

        由于Auto.js支持直接调用Android的API,对于Auto.js没有内置的函数,可以直接通过修改Android代码为JavaScript代码实现。例如旋转图片的Android代码为:

        import android.graphics.Bitmap;
        @@ -1060,7 +1106,7 @@ launch("com.tencent.mm");
         

        该函数也可以作为全局函数使用。

        app.viewFile(path)#

        用其他应用查看文件。文件不存在的情况由查看文件的应用处理。

        如果找不出可以查看该文件的应用,则抛出ActivityNotException

        @@ -1068,7 +1114,7 @@ launch("com.tencent.mm"); app.viewFile("/sdcard/1.txt");

        app.editFile(path)#

        用其他应用编辑文件。文件不存在的情况由编辑文件的应用处理。

        如果找不出可以编辑该文件的应用,则抛出ActivityNotException

        @@ -1132,17 +1178,36 @@ app.sendEmail({

      本模块提供了构建Intent的函数(app.intent()), 启动Activity的函数app.startActivity(), 发送广播的函数app.sendBroadcast()

      使用这些方法可以用来方便的调用其他应用。例如直接打开某个QQ号的个人卡片页,打开某个QQ号的聊天窗口等。

      -
      
      +
      var qq = "2732014414";
      +app.startActivity({ 
      +    action: "android.intent.action.VIEW", 
      +    data:"mqq://im/chat?chat_type=wpa&version=1&src_type=web&uin=" + qq, 
      +    packageName: "com.tencent.mobileqq", 
      +});
       

      app.intent(options)#

        -
      • options <Object> 选项,包括:
          -
        • action <string> 意图的Action,指意图要完成的动作,是一个字符串常量,比如"android.intent.action.SEND"。当action以"android.intent.action"开头时,可以省略前缀,直接用"SEND"代替。常见的action参见常用的意图动作
        • -
        • type <string> 意图的MimeType,表示和该意图直接相关的数据的类型,表示比如"text/plain"为纯文本类型。
        • -
        • data <string> 意图的Data,表示和该意图直接相关的数据,是一个Uri, 可以是文件路径或者Url等。例如要打开一个文件, action为"android.intent.action.VIEW", data为"file:///sdcard/1.txt"。
        • -
        • category <Array> 意图的类别。比较少用。
        • -
        • packageName <string> 目标包名
        • -
        • className <string> 目标Activity或Service等组件的名称
        • -
        • extras <Object> 以键值对构成的这个Intent的Extras(额外信息)。提供该意图的其他信息,例如发送邮件时的邮件标题、邮件正文。
        • +
        • options <Object> 选项,包括:

          +
            +
          • action <string> 意图的Action,指意图要完成的动作,是一个字符串常量,比如"android.intent.action.SEND"。当action以"android.intent.action"开头时,可以省略前缀,直接用"SEND"代替。参见Actions

            +
          • +
          • type <string> 意图的MimeType,表示和该意图直接相关的数据的类型,表示比如"text/plain"为纯文本类型。

            +
          • +
          • data <string> 意图的Data,表示和该意图直接相关的数据,是一个Uri, 可以是文件路径或者Url等。例如要打开一个文件, action为"android.intent.action.VIEW", data为"file:///sdcard/1.txt"。

            +
          • +
          • category <Array> 意图的类别。比较少用。参见Categories

            +
          • +
          • packageName <string> 目标包名

            +
          • +
          • className <string> 目标Activity或Service等组件的名称

            +
          • +
          • extras <Object> 以键值对构成的这个Intent的Extras(额外信息)。提供该意图的其他信息,例如发送邮件时的邮件标题、邮件正文。参见Extras

            +
          • +
          • flags <Array> intent的标识,字符串数组,例如["activity_new_task", "grant_read_uri_permission"]。参见Flags

            +

            [v4.1.0新增]

            +
          • +
          • root <Boolea> 是否以root权限启动、发送该intent。使用该参数后,不能使用context.startActivity()等方法,而应该直接使用诸如app.startActivity({...})的方法。

            +

            [v4.1.0新增]

            +
        @@ -1154,19 +1219,75 @@ var i = app.intent({ type: "image/png", data: "file:///sdcard/1.png" }); -app.startActivity(i); -

      更多信息,请百度安卓Intent或参考Android指南: Intent

      +context.startActivity(i); +

      需要注意的是,除非应用专门暴露Activity出来,否则在没有root权限的情况下使用intent是无法跳转到特定Activity、应用的特定界面的。例如我们能通过Intent跳转到QQ的分享界面,是因为QQ对外暴露了分享的Activity;而在没有root权限的情况下,我们无法通过intent跳转到QQ的设置界面,因为QQ并没有暴露这个Activity。

      +

      但如果有root权限,则在intent的参数加上"root": true即可。例如使用root权限跳转到Auto.js的设置界面为:

      +
      app.startActivity({
      +    packageName: "org.autojs.autojs",
      +    className: "org.autojs.autojs.ui.settings.SettingsActivity_",
      +    root: true
      +});
      +

      另外,关于intent的参数如何获取的问题,一些intent是意外发现并且在网络中传播的(例如跳转QQ聊天窗口是因为QQ给网页提供了跳转到客服QQ的方法),如果要自己获取活动的intent的参数,可以通过例如"intent记录","隐式启动"等应用拦截内部intent或者查询暴露的intent。其中拦截内部intent需要XPosed框架,或者可以通过反编译等手段获取参数。总之,没有简单直接的方法。

      +

      更多信息,请百度安卓Intent或参考Android指南: Intent

      app.startActivity(options)#

      根据选项构造一个Intent,并启动该Activity。

      -

      app.sendBroadcast(options)#

      +
      app.startActivity({
      +    action: "SEND",
      +    type: "text/plain",
      +    data: "file:///sdcard/1.txt"
      +});
      +

      app.sendBroadcast(options)#

      根据选项构造一个Intent,并发送该广播。

      - +

      app.startService(options)#

      +
      +

      根据选项构造一个Intent,并启动该服务。

      +

      app.sendBroadcast(name)#

      +

      [v4.1.0新增]

      +
        +
      • name <string> 特定的广播名称,包括:
          +
        • inspect_layout_hierarchy 布局层次分析
        • +
        • inspect_layout_bounds 布局范围
        • +
        +
      • +
      +

      发送以上特定名称的广播可以触发Auto.js的布局分析,方便脚本调试。这些广播在Auto.js发送才有效,在打包的脚本上运行将没有任何效果。

      +
      app.sendBroadcast("inspect_layout_bounds");
      +

      app.intentToShell(options)#

      +

      [v4.1.0新增]

      + +

      根据选项构造一个Intent,转换为对应的shell的intent命令的参数。

      +

      例如:

      +
      shell("am start " + app.intentToShell({
      +    packageName: "org.autojs.autojs",
      +    className: "org.autojs.autojs.ui.settings.SettingsActivity_"
      +}), true);
      +

      参见intent参数的规范

      +

      app.parseUri(uri)#

      +

      [v4.1.0新增]

      + +

      解析uri字符串并返回相应的Uri对象。即使Uri格式错误,该函数也会返回一个Uri对象,但之后如果访问该对象的scheme, path等值可能因解析失败而返回null

      +

      需要注意的是,在高版本Android上,由于系统限制直接在Uri暴露文件的绝对路径,因此如果uri字符串是文件file://...,返回的Uri会是诸如content://...的形式。

      +

      app.getUriForFile(path)#

      +

      [v4.1.0新增]

      +
        +
      • path <string> 文件路径,例如"/sdcard/1.txt"
      • +
      • 返回 <Uri> 一个指向该文件的Uri的对象,参见android.net.Uri
      • +
      +

      从一个文件路径创建一个uri对象。需要注意的是,在高版本Android上,由于系统限制直接在Uri暴露文件的绝对路径,因此返回的Uri会是诸如content://...的形式。 +

      Console#

      Stability: 2 - Stable

      控制台模块提供了一个和Web浏览器中相似的用于调试的控制台。用于输出一些调试信息、中间结果等。 @@ -1179,8 +1300,8 @@ console模块中的一些函数也可以直接作为全局函数使用,例如l

      清空控制台。

      console.log([data][, ...args])#

        -
      • data
      • -
      • ...args
      • +
      • data <any>
      • +
      • ...args <any>

      打印到控制台,并带上换行符。 可以传入多个参数,第一个参数作为主要信息,其他参数作为类似于 printf(3) 中的代替值(参数都会传给 util.format())。

      const count = 5;
      @@ -1192,26 +1313,26 @@ console.log('count:', count);
       

      该函数也可以作为全局函数使用。

      console.verbose([data][, ...args])#

        -
      • data
      • -
      • ...args
      • +
      • data <any>
      • +
      • ...args <any>

      与console.log类似,但输出结果以灰色字体显示。输出优先级低于log,用于输出观察性质的信息。

      console.info([data][, ...args])#

        -
      • data
      • -
      • ...args
      • +
      • data <any>
      • +
      • ...args <any>

      与console.log类似,但输出结果以绿色字体显示。输出优先级高于log, 用于输出重要信息。

      console.warn([data][, ...args])#

        -
      • data
      • -
      • ...args
      • +
      • data <any>
      • +
      • ...args <any>

      与console.log类似,但输出结果以蓝色字体显示。输出优先级高于info, 用于输出警告信息。

      console.error([data][, ...args])#

        -
      • data
      • -
      • ...args
      • +
      • data <any>
      • +
      • ...args <any>

      与console.log类似,但输出结果以红色字体显示。输出优先级高于warn, 用于输出错误信息。

      console.assert(value, message)#

      @@ -1222,10 +1343,46 @@ console.log('count:', count);
  • 断言。如果value为false则输出错误信息message并停止脚本运行。

    var a = 1 + 1;
     console.assert(a == 2, "加法出错啦");
    -

    console.input(data[, ...args])#

    +

    console.time([label])#

    +

    [v4.1.0新增]

    + +

    启动一个定时器,用以计算一个操作的持续时间。 +定时器由一个唯一的 label 标识。 +当调用 console.timeEnd() 时,可以使用相同的 label 来停止定时器,并以毫秒为单位将持续时间输出到控制台。 +重复启动同一个标签的定时器会覆盖之前启动同一标签的定时器。

    +

    console.timeEnd(label)#

    +

    [v4.1.0新增]

    + +

    停止之前通过调用 console.time() 启动的定时器,并打印结果到控制台。 +调用 console.timeEnd() 后定时器会被删除。如果不存在标签指定的定时器则会打印 NaNms

    +
    console.time('求和');
    +var sum = 0;
    +for(let i = 0; i < 100000; i++){
    +    sum += i;
    +}
    +console.timeEnd('求和');
    +// 打印 求和: xxx ms
    +
    +

    console.trace([data][, ...args])#

    +

    [v4.1.0新增]

    + +

    与console.log类似,同时会打印出调用这个函数所在的调用栈信息(即当前运行的文件、行数等信息)。

    +
    console.trace('Show me');
    +// 打印: (堆栈跟踪会根据被调用的跟踪的位置而变化)
    +// Show me
    +//  at <test>:7
    +
    +

    console.input(data[, ...args])#

      -
    • data
    • -
    • ...args
    • +
    • data <any>
    • +
    • ...args <any>

    与console.log一样输出信息,并在控制台显示输入框等待输入。按控制台的确认按钮后会将输入的字符串用eval计算后返回。

    部分机型可能会有控制台不显示输入框的情况,属于bug。

    @@ -1236,8 +1393,8 @@ toast(n + 1); //显示124

    console.rawInput(data[, ...args])#

      -
    • data
    • -
    • ...args
    • +
    • data <any>
    • +
    • ...args <any>

    与console.log一样输出信息,并在控制台显示输入框等待输入。按控制台的确认按钮后会将输入的字符串直接返回。

    部分机型可能会有控制台不显示输入框的情况,属于bug。

    @@ -1263,7 +1420,24 @@ console.setSize(device.width / 2, device.height / 2);

    设置控制台的位置,单位像素。

    console.show();
     console.setPosition(100, 100);
    -

    print(text)#

    +

    console.setGlobalLogConfig(config)#

    +

    [v4.1.0新增]

    + +

    设置日志保存的路径和配置。例如把日志保存到"/sdcard/1.txt":

    +
    console.setGlobalLogConfig({
    +    "file": "/sdcard/1.txt"
    +});
    +

    注意该函数会影响所有脚本的日志记录。

    +

    print(text)#

    @@ -2225,6 +2399,10 @@ exec(add, {a: 1, b:2});

    停止所有正在运行的脚本并显示停止的脚本数量。包括当前脚本自身。

    engines.myEngine()#

    返回当前脚本的脚本引擎对象(ScriptEngine)

    +

    [v4.1.0新增] +特别的,该对象可以通过execArgv来获取他的运行参数,包括外部参数、intent等。例如:

    +
    log(engines.myEngine().execArgv);
    +

    普通脚本的运行参数通常为空,通过定时任务的广播启动的则可以获取到启动的intent。

    engines.all()#

    您可以通过APK编辑器来增加Auto.js以及Auto.js打包的应用的权限。

    安卓所有的权限列表参见Permissions Overview。(并没有用)

    +

    runtime.loadJar(path)#

    +
    +

    加载目标jar文件,加载成功后将可以使用该Jar文件的类。

    +
    // 加载jsoup.jar
    +runtime.loadJar("./jsoup.jar");
    +// 使用jsoup解析html
    +importClass(org.jsoup.Jsoup);
    +log(Jsoup.parse(files.read("./test.html")));
    +

    (jsoup是一个Java实现的解析Html DOM的库,可以在Jsoup下载)

    +

    runtime.loadDex(path)#

    +
    +

    加载目标dex文件,加载成功后将可以使用该dex文件的类。

    +

    因为加载jar实际上是把jar转换为dex再加载的,因此加载dex文件会比jar文件快得多。可以使用Android SDK的build tools的dx工具把jar转换为dex。

    context#

    全局变量。一个android.content.Context对象。

    注意该对象为ApplicationContext,因此不能用于界面、对话框等的创建。 @@ -3608,7 +3803,304 @@ log(colors.equals(0xFF112233, 0xFF223344));

    colors.TRANSPARENT#

    透明,颜色值 #00000000

    Images#

    -
    Stability: 2 - Stable

    images模块提供了一些手机设备中常见的图片处理函数,包括截图、读写图片、图片剪裁、找色、找图等。

    +
    Stability: 2 - Stable

    images模块提供了一些手机设备中常见的图片处理函数,包括截图、读写图片、图片剪裁、旋转、二值化、找色找图等。

    +

    该模块分为两个部分,找图找色部分和图片处理部分。

    +

    需要注意的是,image对象创建后尽量在不使用时进行回收,同时避免循环创建大量图片。因为图片是一种占用内存比较大的资源,尽管Auto.js通过各种方式(比如图片缓存机制、垃圾回收时回收图片、脚本结束时回收所有图片)尽量降低图片资源的泄漏和内存占用,但是糟糕的代码仍然可以占用大量内存。

    +

    Image对象通过调用recycle()函数来回收。例如:

    +
    // 读取图片
    +var img = images.read("./1.png");
    +//对图片进行操作
    +... 
    +// 回收图片
    +img.recycle();
    +

    例外的是,caputerScreen()返回的图片不需要回收。

    +

    图片处理#

    +

    images.read(path)#

    +
    +

    读取在路径path的图片文件并返回一个Image对象。如果文件不存在或者文件无法解码则返回null。

    +

    images.load(url)#

    +
    +

    加载在地址URL的网络图片并返回一个Image对象。如果地址不存在或者图片无法解码则返回null。

    +

    images.copy(img)#

    +
      +
    • img <Image> 图片
    • +
    • 返回 <Image>
    • +
    +

    复制一张图片并返回新的副本。该函数会完全复制img对象的数据。

    +

    images.save(image, path[, format = "png", quality = 100])#

    +
      +
    • image <Image> 图片
    • +
    • path <string> 路径
    • +
    • format <string> 图片格式,可选的值为:
        +
      • png
      • +
      • jpeg/jpg
      • +
      • webp
      • +
      +
    • +
    • quality <number> 图片质量,为0~100的整数值
    • +
    +

    把图片image以PNG格式保存到path中。如果文件不存在会被创建;文件存在会被覆盖。

    +
    //把图片压缩为原来的一半质量并保存
    +var img = images.read("/sdcard/1.png");
    +images.save(img, "/sdcard/1.jpg", "jpg", 50);
    +app.viewFile("/sdcard/1.jpg");
    +

    images.fromBase64(base64)#

    +
      +
    • base64 <string> 图片的Base64数据
    • +
    • 返回 <Image>
    • +
    +

    解码Base64数据并返回解码后的图片Image对象。如果base64无法解码则返回null

    +

    images.toBase64(img[, format = "png", quality = 100])#

    +
      +
    • image <image> 图片
    • +
    • format <string> 图片格式,可选的值为:
        +
      • png
      • +
      • jpeg/jpg
      • +
      • webp
      • +
      +
    • +
    • quality <number> 图片质量,为0~100的整数值
    • +
    • 返回 <string>
    • +
    +

    把图片编码为base64数据并返回。

    +

    images.fromBytes(bytes)#

    +
      +
    • bytes <byte[]> 字节数组
    • +
    +

    解码字节数组bytes并返回解码后的图片Image对象。如果bytes无法解码则返回null

    +

    images.toBytes(img[, format = "png", quality = 100])#

    +
      +
    • image <image> 图片
    • +
    • format <string> 图片格式,可选的值为:
        +
      • png
      • +
      • jpeg/jpg
      • +
      • webp
      • +
      +
    • +
    • quality <number> 图片质量,为0~100的整数值
    • +
    • 返回 <byte[]>
    • +
    +

    把图片编码为字节数组并返回。

    +

    images.clip(img, x, y, w, h)#

    +
      +
    • img <Image> 图片
    • +
    • x <number> 剪切区域的左上角横坐标
    • +
    • y <number> 剪切区域的左上角纵坐标
    • +
    • w <number> 剪切区域的宽度
    • +
    • h <number> 剪切区域的高度
    • +
    • 返回 <Image>
    • +
    +

    从图片img的位置(x, y)处剪切大小为w * h的区域,并返回该剪切区域的新图片。

    +
    var src = images.read("/sdcard/1.png");
    +var clip = images.clip(src, 100, 100, 400, 400);
    +images.save(clip, "/sdcard/clip.png");
    +

    images.resize(img, size[, interpolation])#

    +

    [v4.1.0新增]

    + +

    调整图片大小,并返回调整后的图片。例如把图片放缩为200*300:images.resize(img, [200, 300])

    +

    参见Imgproc.resize

    +

    images.scale(img, fx, fy[, interpolation])#

    +

    [v4.1.0新增]

    + +

    放缩图片,并返回放缩后的图片。例如把图片变成原来的一半:images.scale(img, 0.5, 0.5)

    +

    参见Imgproc.resize

    +

    images.rotate(img, degress[, x, y])#

    +

    [v4.1.0新增]

    + +

    将图片逆时针旋转degress度,返回旋转后的图片对象。

    +

    例如逆时针旋转90度为images.rotate(img, 90)

    +

    images.concat(img1, image2[, direction])#

    +

    [v4.1.0新增]

    + +

    连接两张图片,并返回连接后的图像。如果两张图片大小不一致,小的那张将适当居中。

    +

    images.grayscale(img)#

    +

    [v4.1.0新增]

    + +

    灰度化图片,并返回灰度化后的图片。

    +

    image.threshold(img, threshold, maxVal[, type])#

    +

    [v4.1.0新增]

    + +

    将图片阈值化,并返回处理后的图像。可以用这个函数进行图片二值化。例如:images.threshold(img, 100, 255, "BINARY"),这个代码将图片中大于100的值全部变成255,其余变成0,从而达到二值化的效果。如果img是一张灰度化图片,这个代码将会得到一张黑白图片。

    +

    可以参考有关博客(比如threshold函数的使用)或者OpenCV文档threshold

    +

    images.adaptiveThreshold(img, maxValue, adaptiveMethod, thresholdType, blockSize, C)#

    +

    [v4.1.0新增]

    + +

    对图片进行自适应阈值化处理,并返回处理后的图像。

    +

    可以参考有关博客(比如threshold与adaptiveThreshold)或者OpenCV文档adaptiveThreshold

    +

    images.cvtColor(img, code[, dstCn])#

    +

    [v4.1.0新增]

    + +

    对图像进行颜色空间转换,并返回转换后的图像。

    +

    可以参考有关博客(比如颜色空间转换)或者OpenCV文档cvtColor

    +

    images.inRange(img, lowerBound, upperBound)#

    +

    [v4.1.0新增]

    + +

    将图片二值化,在lowerBound~upperBound范围以外的颜色都变成0,在范围以内的颜色都变成255。

    +

    例如images.inRange(img, "#000000", "#222222")

    +

    images.interval(img, color, interval)#

    +

    [v4.1.0新增]

    + +

    将图片二值化,在color-interval ~ color+interval范围以外的颜色都变成0,在范围以内的颜色都变成255。这里对color的加减是对每个通道而言的。

    +

    例如images.interval(img, "#888888", 16),每个通道的颜色值均为0x88,加减16后的范围是[0x78, 0x98],因此这个代码将把#787878~#989898的颜色变成#FFFFFF,而把这个范围以外的变成#000000。

    +

    images.blur(img, size[, anchor, type])#

    +

    [v4.1.0新增]

    + +

    对图像进行模糊(平滑处理),返回处理后的图像。

    +

    可以参考有关博客(比如实现图像平滑处理)或者OpenCV文档blur

    +

    images.medianBlur(img, size)#

    +

    [v4.1.0新增]

    + +

    对图像进行中值滤波,返回处理后的图像。

    +

    可以参考有关博客(比如实现图像平滑处理)或者OpenCV文档blur

    +

    images.gaussianBlur(img, size[, sigmaX, sigmaY, type])#

    +

    [v4.1.0新增]

    + +

    对图像进行高斯模糊,返回处理后的图像。

    +

    可以参考有关博客(比如实现图像平滑处理)或者OpenCV文档GaussianBlur

    +

    images.matToImage(mat)#

    +

    [v4.1.0新增]

    + +

    把Mat对象转换为Image对象。

    +

    找图找色#

    images.requestScreenCapture([landscape])#

    • landscape <boolean> 布尔值, 表示将要执行的截屏是否为横屏。如果landscape为false, 则表示竖屏截图; true为横屏截图。
    • @@ -3662,90 +4154,7 @@ toast(colors.toString(color));

    返回图片image在点(x, y)处的像素的ARGB值。

    该值的格式为0xAARRGGBB,是一个"32位整数"(虽然JavaScript中并不区分整数类型和其他数值类型)。

    坐标系以图片左上角为原点。以图片左侧边为y轴,上侧边为x轴。

    -

    images.copy(img)#

    -
      -
    • img <Image> 图片
    • -
    • 返回 <Image>
    • -
    -

    复制一张图片并返回新的副本。该函数会完全复制img对象的数据。

    -

    images.save(image, path[, format = "png", quality = 100])#

    -
      -
    • image <Image> 图片
    • -
    • path <string> 路径
    • -
    • format <string> 图片格式,可选的值为:
        -
      • png
      • -
      • jpeg/jpg
      • -
      • webp
      • -
      -
    • -
    • quality <number> 图片质量,为0~100的整数值
    • -
    -

    把图片image以PNG格式保存到path中。如果文件不存在会被创建;文件存在会被覆盖。

    -
    //把图片压缩为原来的一半质量并保存
    -var img = images.read("/sdcard/1.png");
    -images.save(img, "/sdcard/1.jpg", "jpg", 50);
    -app.viewFile("/sdcard/1.jpg");
    -

    images.read(path)#

    -
    -

    读取在路径path的图片文件并返回一个Image对象。如果文件不存在或者文件无法解码则返回null。

    -

    images.load(url)#

    -
    -

    加载在地址URL的网络图片并返回一个Image对象。如果地址不存在或者图片无法解码则返回null。

    -

    images.fromBase64(base64)#

    -
      -
    • base64 <string> 图片的Base64数据
    • -
    • 返回 <Image>
    • -
    -

    解码Base64数据并返回解码后的图片Image对象。如果base64无法解码则返回null

    -

    images.toBase64(img[, format = "png", quality = 100])#

    -
      -
    • image <image> 图片
    • -
    • format <string> 图片格式,可选的值为:
        -
      • png
      • -
      • jpeg/jpg
      • -
      • webp
      • -
      -
    • -
    • quality <number> 图片质量,为0~100的整数值
    • -
    • 返回 <string>
    • -
    -

    把图片编码为base64数据并返回。

    -

    images.fromBytes(bytes)#

    -
      -
    • bytes <byte[]> 字节数组
    • -
    -

    解码字节数组bytes并返回解码后的图片Image对象。如果bytes无法解码则返回null

    -

    images.toBytes(img[, format = "png", quality = 100])#

    -
      -
    • image <image> 图片
    • -
    • format <string> 图片格式,可选的值为:
        -
      • png
      • -
      • jpeg/jpg
      • -
      • webp
      • -
      -
    • -
    • quality <number> 图片质量,为0~100的整数值
    • -
    • 返回 <byte[]>
    • -
    -

    把图片编码为字节数组并返回。

    -

    images.clip(img, x, y, w, h)#

    -
      -
    • img <Image> 图片
    • -
    • x <number> 剪切区域的左上角横坐标
    • -
    • y <number> 剪切区域的左上角纵坐标
    • -
    • w <number> 剪切区域的宽度
    • -
    • h <number> 剪切区域的高度
    • -
    • 返回 <Image>
    • -
    -

    从图片img的位置(x, y)处剪切大小为w * h的区域,并返回该剪切区域的新图片。

    -
    var src = images.read("/sdcard/1.png");
    -var clip = images.clip(src, 100, 100, 400, 400);
    -images.save(clip, "/sdcard/clip.png");
    -

    images.findColor(image, color, options)#

    +

    images.findColor(image, color, options)#

    • image <Image> 图片
    • color <number> | <string> 要寻找的颜色的RGB值。如果是一个整数,则以0xRRGGBB的形式代表RGB值(A通道会被忽略);如果是字符串,则以"#RRGGBB"代表其RGB值。
    • @@ -3923,7 +4332,94 @@ if(p){ threshold: threshold })

      该函数也可以作为全局函数使用。

      -

      Image#

      +

      images.matchTemplate(img, template, options)#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 大图片
      • +
      • template <Image> 小图片(模板)
      • +
      • options <Object> 找图选项:
          +
        • threshold <number> 图片相似度。取值范围为0~1的浮点数。默认值为0.9。
        • +
        • region <Array> 找图区域。参见findColor函数关于region的说明。
        • +
        • max <number> 找图结果最大数量,默认为5
        • +
        • level <number> 一般而言不必修改此参数。不加此参数时该参数会根据图片大小自动调整。找图算法是采用图像金字塔进行的, level参数表示金字塔的层次, level越大可能带来越高的找图效率,但也可能造成找图失败(图片因过度缩小而无法分辨)或返回错误位置。因此,除非您清楚该参数的意义并需要进行性能调优,否则不需要用到该参数。
        • +
        +
      • +
      • 返回 <MatchingResult>
      • +
      +

      在大图片中搜索小图片,并返回搜索结果MatchingResult。该函数可以用于找图时找出多个位置,可以通过max参数控制最大的结果数量。也可以对匹配结果进行排序、求最值等操作。

      +

      MatchingResult#

      +

      [v4.1.0新增]

      +

      matches#

      +
        +
      • <Array> 匹配结果的数组。
      • +
      +

      数组的元素是一个Match对象:

      +
        +
      • point <Point> 匹配位置
      • +
      • similarity <number> 相似度
      • +
      +

      例如:

      +
      var result = images.matchTemplate(img, template, {
      +    max: 100
      +});
      +result.matches.forEach(match => {
      +    log("point = " + match.point + ", similarity = " + match.similarity);
      +});
      +

      points#

      +
        +
      • <Array> 匹配位置的数组。
      • +
      +

      first()#

      +
        +
      • 返回 <Match>
      • +
      +

      第一个匹配结果。如果没有任何匹配,则返回null

      +

      last()#

      +
        +
      • 返回 <Match>
      • +
      +

      最后一个匹配结果。如果没有任何匹配,则返回null

      +

      leftmost()#

      +
        +
      • 返回 <Match>
      • +
      +

      位于大图片最左边的匹配结果。如果没有任何匹配,则返回null

      +

      topmost()#

      +
        +
      • 返回 <Match>
      • +
      +

      位于大图片最上边的匹配结果。如果没有任何匹配,则返回null

      +

      rightmost()#

      +
        +
      • 返回 <Match>
      • +
      +

      位于大图片最右边的匹配结果。如果没有任何匹配,则返回null

      +

      bottommost()#

      +
        +
      • 返回 <Match>
      • +
      +

      位于大图片最下边的匹配结果。如果没有任何匹配,则返回null

      +

      best()#

      +
        +
      • 返回 <Match>
      • +
      +

      相似度最高的匹配结果。如果没有任何匹配,则返回null

      +

      worst()#

      +
        +
      • 返回 <Match>
      • +
      +

      相似度最低的匹配结果。如果没有任何匹配,则返回null

      +

      sortBy(cmp)#

      +
        +
      • cmp <Function>|<string> 比较函数,或者是一个字符串表示排序方向。例如"left"表示将匹配结果按匹配位置从左往右排序、"top"表示将匹配结果按匹配位置从上往下排序,"left-top"表示将匹配结果按匹配位置从左往右、从上往下排序。方向包括left(左), top (上), right (右), bottom(下)。
      • +
      • <MatchingResult>
      • +
      +

      对匹配结果进行排序,并返回排序后的结果。

      +
      var result = images.matchTemplate(img, template, {
      +    max: 100
      +});
      +log(result.sortBy("top-right"));
      +

      Image#

      表示一张图片,可以是截图的图片,或者本地读取的图片,或者从网络获取的图片。

      Image.getWidth()#

      返回以像素为单位图片宽度。

      @@ -3942,6 +4438,7 @@ if(p){

    返回图片image在点(x, y)处的像素的ARGB值。

    该值的格式为0xAARRGGBB,是一个"32位整数"(虽然JavaScript中并不区分整数类型和其他数值类型)。

    坐标系以图片左上角为原点。以图片左侧边为y轴,上侧边为x轴。

    +

    ##

    Point#

    findColor, findImage返回的对象。表示一个点(坐标)。

    Point.x#

    @@ -4210,7 +4707,7 @@ sleep(media.getMusicDuration() - 30 * 1000);

    module (模块)#

    Stability: 2 - Stable

    Auto.js 有一个简单的模块加载系统。 在 Auto.js 中,文件和模块是一一对应的(每个文件被视为一个独立的模块)。

    例子,假设有一个名为 foo.js 的文件:

    -
    const circle = require('circle.js');
    +
    var circle = require('circle.js');
     console.log("半径为 4 的圆的面积是 %d", circle.area(4));
     

    在第一行中,foo.js 加载了同一目录下的 circle.js 模块。

    circle.js 文件的内容为:

    @@ -4218,7 +4715,9 @@ console.log("半径为 4 的圆的面积是 %d", circle.area(4)); var circle = {}; -circle.area = (r) => PI * r ** 2; +circle.area = function (r) { + return PI * r * r; +}; circle.circumference = (r) => 2 * PI * r; @@ -4261,6 +4760,7 @@ module.exports = function(width) {
    auto();
     

    auto.waitFor()#

    检查无障碍服务是否已经启用,如果没有启用则跳转到无障碍服务启用界面,并等待无障碍服务启动;当无障碍服务启动后脚本会继续运行。

    +

    因为该函数是阻塞的,因此除非是有协程特性,否则不能在ui模式下运行该函数,建议在ui模式下使用auto()函数。

    auto.setMode(mode)#

    • mode <string> 模式
    • @@ -4270,6 +4770,72 @@ module.exports = function(width) {
    • fast 快速模式。该模式下会启用控件缓存,从而选择器获取屏幕控件更快。对于需要快速的控件查看和操作的脚本可以使用该模式,一般脚本则没有必要使用该函数。
    • normal 正常模式,默认。
    +

    auto.setFlags(flags)#

    +

    [v4.1.0新增]

    +
      +
    • flags <string> | <Array> 一些标志,来启用和禁用某些特性,包括:
        +
      • findOnUiThread 使用该特性后,选择器搜索时会在主进程进行。该特性用于解决线程安全问题导致的次生问题,不过目前貌似已知问题并不是线程安全问题。
      • +
      • useUsageStats 使用该特性后,将会以"使用情况统计"服务的结果来检测当前正在运行的应用包名(需要授予"查看使用情况统计"权限)。如果觉得currentPackage()返回的结果不太准确,可以尝试该特性。
      • +
      • useShell 使用该特性后,将使用shell命令获取当前正在运行的应用的包名、活动名称,但是需要root权限。
      • +
      +
    • +
    +

    启用有关automator的一些特性。例如:

    +
    auto.setFlags(["findOnUiThread", "useShell"]);
    +

    auto.serivce#

    +

    [v4.1.0新增]

    + +

    获取无障碍服务。如果无障碍服务没有启动,则返回null

    +

    参见AccessibilityService

    +

    auto.windows#

    +

    [v4.1.0新增]

    + +

    当前所有窗口(AccessibilityWindowInfo)的数组,可能包括状态栏、输入法、当前应用窗口,弹出窗口、悬浮窗、分屏应用窗口等。可以分别获取每个窗口的布局信息。

    +

    该函数需要Android 5.0以上才能运行。

    +

    auto.root#

    +

    [v4.1.0新增]

    +
      +
    • <UiObject>
    • +
    +

    当前窗口的布局根元素。如果无障碍服务未启动或者WindowFilter均返回false,则会返回null

    +

    如果不设置windowFilter,则当前窗口即为活跃的窗口(获取到焦点、正在触摸的窗口);如果设置了windowFilter,则获取的是过滤的窗口中的第一个窗口。

    +

    如果系统是Android5.0以下,则始终返回当前活跃的窗口的布局根元素。

    +

    auto.rootInActiveWindow#

    +

    [v4.1.0新增]

    +
      +
    • <UiObject>
    • +
    +

    当前活跃的窗口(获取到焦点、正在触摸的窗口)的布局根元素。如果无障碍服务未启动则为null

    +

    auto.setWindowFilter(filter)#

    +

    [v4.1.0新增]

    + +

    设置窗口过滤器。这个过滤器可以决定哪些窗口是目标窗口,并影响选择器的搜索。例如,如果想要选择器在所有窗口(包括状态栏、输入法等)中搜索,只需要使用以下代码:

    +
    auto.setWindowFilter(function(window){
    +    //不管是如何窗口,都返回true,表示在该窗口中搜索
    +    return true;
    +});
    +

    又例如,当前使用了分屏功能,屏幕上有Auto.js和QQ两个应用,但我们只想选择器对QQ界面进行搜索,则:

    +
    auto.setWindowFilter(function(window){
    +    // 对于应用窗口,他的title属性就是应用的名称,因此可以通过title属性来判断一个应用
    +    return window.title == "QQ";
    +});
    +

    选择器默认是在当前活跃的窗口中搜索,不会搜索诸如悬浮窗、状态栏之类的,使用WindowFilter则可以控制搜索的窗口。

    +

    需要注意的是, 如果WindowFilter返回的结果均为false,则选择器的搜索结果将为空。

    +

    另外setWindowFilter函数也会影响auto.windowRoots的结果。

    +

    该函数需要Android 5.0以上才有效。

    +

    auto.windowRoots#

    +

    [v4.1.0新增]

    + +

    返回当前被WindowFilter过滤的窗口的布局根元素组成的数组。

    +

    如果系统是Android5.0以下,则始终返回当前活跃的窗口的布局根元素的数组。

    SimpleActionAutomator#

    Stability: 2 - Stable

    SimpleActionAutomator提供了一些模拟简单操作的函数,例如点击文字、模拟按键等。这些函数可以直接作为全局函数使用。

    click(text[, i])#

    @@ -4402,6 +4968,18 @@ sendButton.click();

    创建一个新的选择器。但一般情况不需要使用该函数,因为可以直接用相应条件的语句创建选择器。

    由于历史遗留原因,本不应该这样设计(不应该让id(), text()等作为全局函数,而是应该用By.id(), By.text()),但为了后向兼容性只能保留这个设计。

    这样的API设计会污染全局变量,后续可能会支持"去掉这些全局函数而使用By.*"的选项。

    +

    UiSelector.algorithm(algorithm)#

    +

    [v4.1.0新增]

    +
      +
    • algorithm <string> 搜索算法,可选的值有:
        +
      • DFS 深度优先算法,选择器的默认算法
      • +
      • BFS 广度优先算法
      • +
      +
    • +
    +

    指定选择器的搜索算法。例如:

    +
    log(selector().text("文本").algorithm("BFS").find());
    +

    广度优先在控件所在层次较低时,或者布局的层次不多时,通常能更快找到控件。

    UiSelector.text(str)#

    • str <string> 控件文本
    • @@ -6005,11 +6583,12 @@ setTimeout(function(){

      用户界面: UI#

      ui模块提供了编写用户界面的支持。

      -

      带有ui的脚本的第一行必须使用"ui"指定ui模式,否则脚本将不会以ui模式运行。正确示范:

      +

      带有ui的脚本的的最前面必须使用"ui";指定ui模式,否则脚本将不会以ui模式运行。正确示范:

      "ui";
       
       //脚本的其他代码
      -

      界面是由视图(View)组成的。View分成两种,控件(Widget)和布局(Layout)。控件(Widget)用来具体显示文字、图片、网页等,比如文本控件(text)用来显示文字,按钮控件(button)则可以显示一个按钮并提供点击效果,图片控件(img)则用来显示来自网络或者文件的图片,除此之外还有输入框控件(input)、进度条控件(progressbar)、单选复选框控件(checkbox)等;布局(Layout)则是装着一个或多个控件的"容器",用于控制在他里面的控件的位置,比如垂直布局(vertical)会把他里面的控件从上往下依次显示(即纵向排列),水平布局(horizontal)则会把他里面的控件从左往右依次显示(即横向排列),以及帧布局(frame),他会把他里面的控件直接在左上角显示,如果有多个控件,后面的控件会重叠在前面的控件上。

      +

    字符串"ui"的前面可以有注释、空行和空格[v4.1.0新增],但是不能有其他代码。

    +

    界面是由视图(View)组成的。View分成两种,控件(Widget)和布局(Layout)。控件(Widget)用来具体显示文字、图片、网页等,比如文本控件(text)用来显示文字,按钮控件(button)则可以显示一个按钮并提供点击效果,图片控件(img)则用来显示来自网络或者文件的图片,除此之外还有输入框控件(input)、进度条控件(progressbar)、单选复选框控件(checkbox)等;布局(Layout)则是装着一个或多个控件的"容器",用于控制在他里面的控件的位置,比如垂直布局(vertical)会把他里面的控件从上往下依次显示(即纵向排列),水平布局(horizontal)则会把他里面的控件从左往右依次显示(即横向排列),以及帧布局(frame),他会把他里面的控件直接在左上角显示,如果有多个控件,后面的控件会重叠在前面的控件上。

    我们使用xml来编写界面,并通过ui.layout()函数指定界面的布局xml。举个例子:

    "ui";
     ui.layout(
    diff --git a/app/src/main/assets/docs/app.html b/app/src/main/assets/docs/app.html
    index ca798aa3..b67caca8 100644
    --- a/app/src/main/assets/docs/app.html
    +++ b/app/src/main/assets/docs/app.html
    @@ -2,8 +2,8 @@
     
     
       
    -  App | Auto.js 3.0.0 文档
    -  
    +  App | Auto.js 4.1.0 文档
    +  
       
       
       
    @@ -61,7 +61,7 @@
     
         
    -

    Auto.js 3.0.0 文档

    +

    Auto.js 4.1.0 文档

    索引 | @@ -97,6 +97,11 @@

  • app.intent(options)
  • app.startActivity(options)
  • app.sendBroadcast(options)
  • +
  • app.startService(options)
  • +
  • app.sendBroadcast(name)
  • +
  • app.intentToShell(options)
  • +
  • app.parseUri(uri)
  • +
  • app.getUriForFile(path)
  • @@ -173,7 +178,7 @@ launch("com.tencent.mm");

    该函数也可以作为全局函数使用。

    app.viewFile(path)#

    用其他应用查看文件。文件不存在的情况由查看文件的应用处理。

    如果找不出可以查看该文件的应用,则抛出ActivityNotException

    @@ -181,7 +186,7 @@ launch("com.tencent.mm"); app.viewFile("/sdcard/1.txt");

    app.editFile(path)#

    用其他应用编辑文件。文件不存在的情况由编辑文件的应用处理。

    如果找不出可以编辑该文件的应用,则抛出ActivityNotException

    @@ -245,17 +250,36 @@ app.sendEmail({

    本模块提供了构建Intent的函数(app.intent()), 启动Activity的函数app.startActivity(), 发送广播的函数app.sendBroadcast()

    使用这些方法可以用来方便的调用其他应用。例如直接打开某个QQ号的个人卡片页,打开某个QQ号的聊天窗口等。

    -
    
    +
    var qq = "2732014414";
    +app.startActivity({ 
    +    action: "android.intent.action.VIEW", 
    +    data:"mqq://im/chat?chat_type=wpa&version=1&src_type=web&uin=" + qq, 
    +    packageName: "com.tencent.mobileqq", 
    +});
     

    app.intent(options)#

      -
    • options <Object> 选项,包括:
        -
      • action <string> 意图的Action,指意图要完成的动作,是一个字符串常量,比如"android.intent.action.SEND"。当action以"android.intent.action"开头时,可以省略前缀,直接用"SEND"代替。常见的action参见常用的意图动作
      • -
      • type <string> 意图的MimeType,表示和该意图直接相关的数据的类型,表示比如"text/plain"为纯文本类型。
      • -
      • data <string> 意图的Data,表示和该意图直接相关的数据,是一个Uri, 可以是文件路径或者Url等。例如要打开一个文件, action为"android.intent.action.VIEW", data为"file:///sdcard/1.txt"。
      • -
      • category <Array> 意图的类别。比较少用。
      • -
      • packageName <string> 目标包名
      • -
      • className <string> 目标Activity或Service等组件的名称
      • -
      • extras <Object> 以键值对构成的这个Intent的Extras(额外信息)。提供该意图的其他信息,例如发送邮件时的邮件标题、邮件正文。
      • +
      • options <Object> 选项,包括:

        +
          +
        • action <string> 意图的Action,指意图要完成的动作,是一个字符串常量,比如"android.intent.action.SEND"。当action以"android.intent.action"开头时,可以省略前缀,直接用"SEND"代替。参见Actions

          +
        • +
        • type <string> 意图的MimeType,表示和该意图直接相关的数据的类型,表示比如"text/plain"为纯文本类型。

          +
        • +
        • data <string> 意图的Data,表示和该意图直接相关的数据,是一个Uri, 可以是文件路径或者Url等。例如要打开一个文件, action为"android.intent.action.VIEW", data为"file:///sdcard/1.txt"。

          +
        • +
        • category <Array> 意图的类别。比较少用。参见Categories

          +
        • +
        • packageName <string> 目标包名

          +
        • +
        • className <string> 目标Activity或Service等组件的名称

          +
        • +
        • extras <Object> 以键值对构成的这个Intent的Extras(额外信息)。提供该意图的其他信息,例如发送邮件时的邮件标题、邮件正文。参见Extras

          +
        • +
        • flags <Array> intent的标识,字符串数组,例如["activity_new_task", "grant_read_uri_permission"]。参见Flags

          +

          [v4.1.0新增]

          +
        • +
        • root <Boolea> 是否以root权限启动、发送该intent。使用该参数后,不能使用context.startActivity()等方法,而应该直接使用诸如app.startActivity({...})的方法。

          +

          [v4.1.0新增]

          +
      @@ -267,18 +291,74 @@ var i = app.intent({ type: "image/png", data: "file:///sdcard/1.png" }); -app.startActivity(i); -

    更多信息,请百度安卓Intent或参考Android指南: Intent

    +context.startActivity(i); +

    需要注意的是,除非应用专门暴露Activity出来,否则在没有root权限的情况下使用intent是无法跳转到特定Activity、应用的特定界面的。例如我们能通过Intent跳转到QQ的分享界面,是因为QQ对外暴露了分享的Activity;而在没有root权限的情况下,我们无法通过intent跳转到QQ的设置界面,因为QQ并没有暴露这个Activity。

    +

    但如果有root权限,则在intent的参数加上"root": true即可。例如使用root权限跳转到Auto.js的设置界面为:

    +
    app.startActivity({
    +    packageName: "org.autojs.autojs",
    +    className: "org.autojs.autojs.ui.settings.SettingsActivity_",
    +    root: true
    +});
    +

    另外,关于intent的参数如何获取的问题,一些intent是意外发现并且在网络中传播的(例如跳转QQ聊天窗口是因为QQ给网页提供了跳转到客服QQ的方法),如果要自己获取活动的intent的参数,可以通过例如"intent记录","隐式启动"等应用拦截内部intent或者查询暴露的intent。其中拦截内部intent需要XPosed框架,或者可以通过反编译等手段获取参数。总之,没有简单直接的方法。

    +

    更多信息,请百度安卓Intent或参考Android指南: Intent

    app.startActivity(options)#

    根据选项构造一个Intent,并启动该Activity。

    -

    app.sendBroadcast(options)#

    +
    app.startActivity({
    +    action: "SEND",
    +    type: "text/plain",
    +    data: "file:///sdcard/1.txt"
    +});
    +

    app.sendBroadcast(options)#

    根据选项构造一个Intent,并发送该广播。

    +

    app.startService(options)#

    +
    +

    根据选项构造一个Intent,并启动该服务。

    +

    app.sendBroadcast(name)#

    +

    [v4.1.0新增]

    + +

    发送以上特定名称的广播可以触发Auto.js的布局分析,方便脚本调试。这些广播在Auto.js发送才有效,在打包的脚本上运行将没有任何效果。

    +
    app.sendBroadcast("inspect_layout_bounds");
    +

    app.intentToShell(options)#

    +

    [v4.1.0新增]

    + +

    根据选项构造一个Intent,转换为对应的shell的intent命令的参数。

    +

    例如:

    +
    shell("am start " + app.intentToShell({
    +    packageName: "org.autojs.autojs",
    +    className: "org.autojs.autojs.ui.settings.SettingsActivity_"
    +}), true);
    +

    参见intent参数的规范

    +

    app.parseUri(uri)#

    +

    [v4.1.0新增]

    + +

    解析uri字符串并返回相应的Uri对象。即使Uri格式错误,该函数也会返回一个Uri对象,但之后如果访问该对象的scheme, path等值可能因解析失败而返回null

    +

    需要注意的是,在高版本Android上,由于系统限制直接在Uri暴露文件的绝对路径,因此如果uri字符串是文件file://...,返回的Uri会是诸如content://...的形式。

    +

    app.getUriForFile(path)#

    +

    [v4.1.0新增]

    + +

    从一个文件路径创建一个uri对象。需要注意的是,在高版本Android上,由于系统限制直接在Uri暴露文件的绝对路径,因此返回的Uri会是诸如content://...的形式。

    diff --git a/app/src/main/assets/docs/assets/fonts.css b/app/src/main/assets/docs/assets/fonts.css new file mode 100644 index 00000000..40e55798 --- /dev/null +++ b/app/src/main/assets/docs/assets/fonts.css @@ -0,0 +1,48 @@ +/* latin-ext */ +@font-face { + font-family: 'Lato'; + font-style: italic; + font-weight: 400; + src: local('Lato Italic'), local('Lato-Italic'), url(fonts/S6u8w4BMUTPHjxsAUi-qJCY.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; + } + /* latin */ + @font-face { + font-family: 'Lato'; + font-style: italic; + font-weight: 400; + src: local('Lato Italic'), local('Lato-Italic'), url(fonts/S6u8w4BMUTPHjxsAXC-q.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + } + /* latin-ext */ + @font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 400; + src: local('Lato Regular'), local('Lato-Regular'), url(fonts/S6uyw4BMUTPHjxAwXjeu.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; + } + /* latin */ + @font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 400; + src: local('Lato Regular'), local('Lato-Regular'), url(fonts/S6uyw4BMUTPHjx4wXg.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + } + /* latin-ext */ + @font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 700; + src: local('Lato Bold'), local('Lato-Bold'), url(fonts/S6u9w4BMUTPHh6UVSwaPGR_p.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; + } + /* latin */ + @font-face { + font-family: 'Lato'; + font-style: normal; + font-weight: 700; + src: local('Lato Bold'), local('Lato-Bold'), url(fonts/S6u9w4BMUTPHh6UVSwiPGQ.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; + } \ No newline at end of file diff --git a/app/src/main/assets/docs/assets/fonts/S6u9w4BMUTPHh6UVSwiPGQ.woff2 b/app/src/main/assets/docs/assets/fonts/S6u9w4BMUTPHh6UVSwiPGQ.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..d88f1af8c8a003bbfe27f0f8ed091b696dc6090d GIT binary patch literal 22820 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 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/docs/assets/fonts/S6uyw4BMUTPHjx4wXg.woff2 b/app/src/main/assets/docs/assets/fonts/S6uyw4BMUTPHjx4wXg.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..b14c76cab32daeac6287bfad409cfd73c63504d5 GIT binary patch literal 23316 zcmY)VV~{R9(*+8T_Sm-e*!Emw+qP}nwr$(CZQHi7XTJM+Pt|woBtKF~Ro6;-b-L0? z$4yR@2?!YIzoLZ-g!sSqDi{bzv+e&G`(OY6TX2dcaqYqNfdY6S>7ZgvkYJ&MB1i&n zabSY@fq>aSNI*j!!3h6^U_t~7!Aju}Z9%NF#RNi}0S`8iM{pq%S>uxV8;y!UIIeS~ z>u1sD{`<|#P##?eSpWVJZ(43-a>O~HL4MRIB_r0H({S1M)w9fDTunVySnCWi8V4jC zhZGZ0(N5<`N}HMqE*@<-Z0Z1Sw56a`oCbx$4SWu-q3&&MxGJoX+!eB|Y}_{$Zk>#% zlyGK)p|@9P|ohqu<`rwNs*xEah+aRrF@ zLl{`#^aJ3-SGG?}hmUD^Cf4evsXKt}v)&gUd2-9cDcpmHK_cDxAF}f- z<|L(Gcjg_A7fh=>pzlydOX%>>l(>8DbAy>AQU*(WCQEY4E@YZ-)2FMka-&+uRI8O<2Hq~ zXq#L=AJ9~UxyvaeDJGrhQN;f>!U{Y`!66~kZrbtNnQDsj|b1RCTz!|*oCHM>$O8e z4i%+16+mnv+4jBoSwP!BugcbZF6e^d#Y+%<&=V8QCd}?tX{P)@1Xx>Ed)}xoZN8W( zMHI3)WiT(SifG~J=m_(8?<2hfm4i>*l2us9D%_B?khT^O-G6@5?yOw}Qy@JsERRv>RA&)hs*;T=7EGQ$0$yr^i)8+-q-mc9XMo@K3mvBCuToHNUigR0!8jmp%l z7wLOmuKMxUvfLZ^@#2EpKN<4;_&K8L2)!|c`;E^I4q*D|`?ZMG09~ReJ~OfY5&#TE zB~CD*7|H97*`91qS(&|F8=q<=fvL7Od70W%!w*!{-=`v7z0|rS6>>i3m

    iv6&Is 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 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/docs/canvas.html b/app/src/main/assets/docs/canvas.html index 46bfd8c1..15d58806 100644 --- a/app/src/main/assets/docs/canvas.html +++ b/app/src/main/assets/docs/canvas.html @@ -2,8 +2,8 @@ - Canvas | Auto.js 3.0.0 文档 - + Canvas | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

    -

    Auto.js 3.0.0 文档

    +

    Auto.js 4.1.0 文档

    索引 | diff --git a/app/src/main/assets/docs/console.html b/app/src/main/assets/docs/console.html index 3a12754c..30ca88cf 100644 --- a/app/src/main/assets/docs/console.html +++ b/app/src/main/assets/docs/console.html @@ -2,8 +2,8 @@ - Console | Auto.js 3.0.0 文档 - + Console | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

    -

    Auto.js 3.0.0 文档

    +

    Auto.js 4.1.0 文档

    索引 | @@ -84,10 +84,14 @@

  • console.warn([data][, ...args])
  • console.error([data][, ...args])
  • console.assert(value, message)
  • +
  • console.time([label])
  • +
  • console.timeEnd(label)
  • +
  • console.trace([data][, ...args])
  • console.input(data[, ...args])
  • console.rawInput(data[, ...args])
  • console.setSize(w, h)
  • console.setPosition(x, y)
  • +
  • console.setGlobalLogConfig(config)
  • print(text)
  • @@ -107,8 +111,8 @@ console模块中的一些函数也可以直接作为全局函数使用,例如l

    清空控制台。

    console.log([data][, ...args])#

      -
    • data
    • -
    • ...args
    • +
    • data <any>
    • +
    • ...args <any>

    打印到控制台,并带上换行符。 可以传入多个参数,第一个参数作为主要信息,其他参数作为类似于 printf(3) 中的代替值(参数都会传给 util.format())。

    const count = 5;
    @@ -120,26 +124,26 @@ console.log('count:', count);
     

    该函数也可以作为全局函数使用。

    console.verbose([data][, ...args])#

      -
    • data
    • -
    • ...args
    • +
    • data <any>
    • +
    • ...args <any>

    与console.log类似,但输出结果以灰色字体显示。输出优先级低于log,用于输出观察性质的信息。

    console.info([data][, ...args])#

      -
    • data
    • -
    • ...args
    • +
    • data <any>
    • +
    • ...args <any>

    与console.log类似,但输出结果以绿色字体显示。输出优先级高于log, 用于输出重要信息。

    console.warn([data][, ...args])#

      -
    • data
    • -
    • ...args
    • +
    • data <any>
    • +
    • ...args <any>

    与console.log类似,但输出结果以蓝色字体显示。输出优先级高于info, 用于输出警告信息。

    console.error([data][, ...args])#

      -
    • data
    • -
    • ...args
    • +
    • data <any>
    • +
    • ...args <any>

    与console.log类似,但输出结果以红色字体显示。输出优先级高于warn, 用于输出错误信息。

    console.assert(value, message)#

    @@ -150,10 +154,46 @@ console.log('count:', count);

    断言。如果value为false则输出错误信息message并停止脚本运行。

    var a = 1 + 1;
     console.assert(a == 2, "加法出错啦");
    -

    console.input(data[, ...args])#

    +

    console.time([label])#

    +

    [v4.1.0新增]

    +
      +
    • label <String> 计时器标签,可省略
    • +
    +

    启动一个定时器,用以计算一个操作的持续时间。 +定时器由一个唯一的 label 标识。 +当调用 console.timeEnd() 时,可以使用相同的 label 来停止定时器,并以毫秒为单位将持续时间输出到控制台。 +重复启动同一个标签的定时器会覆盖之前启动同一标签的定时器。

    +

    console.timeEnd(label)#

    +

    [v4.1.0新增]

    + +

    停止之前通过调用 console.time() 启动的定时器,并打印结果到控制台。 +调用 console.timeEnd() 后定时器会被删除。如果不存在标签指定的定时器则会打印 NaNms

    +
    console.time('求和');
    +var sum = 0;
    +for(let i = 0; i < 100000; i++){
    +    sum += i;
    +}
    +console.timeEnd('求和');
    +// 打印 求和: xxx ms
    +
    +

    console.trace([data][, ...args])#

    +

    [v4.1.0新增]

    +
      +
    • data <any>
    • +
    • ...args <any>
    • +
    +

    与console.log类似,同时会打印出调用这个函数所在的调用栈信息(即当前运行的文件、行数等信息)。

    +
    console.trace('Show me');
    +// 打印: (堆栈跟踪会根据被调用的跟踪的位置而变化)
    +// Show me
    +//  at <test>:7
    +
    +

    console.input(data[, ...args])#

      -
    • data
    • -
    • ...args
    • +
    • data <any>
    • +
    • ...args <any>

    与console.log一样输出信息,并在控制台显示输入框等待输入。按控制台的确认按钮后会将输入的字符串用eval计算后返回。

    部分机型可能会有控制台不显示输入框的情况,属于bug。

    @@ -164,8 +204,8 @@ toast(n + 1); //显示124

    console.rawInput(data[, ...args])#

      -
    • data
    • -
    • ...args
    • +
    • data <any>
    • +
    • ...args <any>

    与console.log一样输出信息,并在控制台显示输入框等待输入。按控制台的确认按钮后会将输入的字符串直接返回。

    部分机型可能会有控制台不显示输入框的情况,属于bug。

    @@ -191,7 +231,24 @@ console.setSize(device.width / 2, device.height / 2);

    设置控制台的位置,单位像素。

    console.show();
     console.setPosition(100, 100);
    -

    print(text)#

    +

    console.setGlobalLogConfig(config)#

    +

    [v4.1.0新增]

    +
      +
    • config <Object> 日志配置,可选的项有:
        +
      • file <string> 日志文件路径,将会把日志写入该文件中
      • +
      • maxFileSize <number> 最大文件大小,单位字节,默认为512 * 1024 (512KB)
      • +
      • rootLevel <string> 写入的日志级别,默认为"ALL"(所有日志),可以为"OFF"(关闭), "DEBUG", "INFO", "WARN", "ERROR", "FATAL"等。
      • +
      • maxBackupSize <number> 日志备份文件最大数量,默认为5
      • +
      • filePattern <string> 日志写入格式,参见PatternLayout
      • +
      +
    • +
    +

    设置日志保存的路径和配置。例如把日志保存到"/sdcard/1.txt":

    +
    console.setGlobalLogConfig({
    +    "file": "/sdcard/1.txt"
    +});
    +

    注意该函数会影响所有脚本的日志记录。

    +

    print(text)#

    diff --git a/app/src/main/assets/docs/coordinates-based-automation.html b/app/src/main/assets/docs/coordinates-based-automation.html index 2a3cd81f..4854db8f 100644 --- a/app/src/main/assets/docs/coordinates-based-automation.html +++ b/app/src/main/assets/docs/coordinates-based-automation.html @@ -2,8 +2,8 @@ - 基于坐标的触摸模拟 | Auto.js 3.0.0 文档 - + 基于坐标的触摸模拟 | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@
    -

    Auto.js 3.0.0 文档

    +

    Auto.js 4.1.0 文档

    索引 | diff --git a/app/src/main/assets/docs/device.html b/app/src/main/assets/docs/device.html index 39d288ea..865171b4 100644 --- a/app/src/main/assets/docs/device.html +++ b/app/src/main/assets/docs/device.html @@ -2,8 +2,8 @@ - Device | Auto.js 3.0.0 文档 - + Device | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

    -

    Auto.js 3.0.0 文档

    +

    Auto.js 4.1.0 文档

    索引 | diff --git a/app/src/main/assets/docs/dialogs.html b/app/src/main/assets/docs/dialogs.html index 29ae1be5..2e8d7a3b 100644 --- a/app/src/main/assets/docs/dialogs.html +++ b/app/src/main/assets/docs/dialogs.html @@ -2,8 +2,8 @@ - Dialogs | Auto.js 3.0.0 文档 - + Dialogs | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

    -

    Auto.js 3.0.0 文档

    +

    Auto.js 4.1.0 文档

    索引 | @@ -99,6 +99,9 @@

  • 事件: multi_choice
  • 事件: input
  • 事件: input_change
  • +
  • dialog.getProgress()
  • +
  • dialog.getMaxProgress()
  • +
  • dialog.getActionButton(action)
  • @@ -271,11 +274,11 @@ dialogs.select("请选择一个选项", ["选项A", "
  • itemsColor <string> | <number> 对话框列表的选项的文字颜色
  • itemsSelectMode <string> 对话框列表的选项选择模式,可以为:
    • select 普通选择模式
    • -
    • singleChoice 单选模式
    • -
    • multiChoice 多选模式
    • +
    • single 单选模式
    • +
    • multi 多选模式
  • -
  • itemsSelectedIndex <number> | <Array> 对话框列表中???
  • +
  • itemsSelectedIndex <number> | <Array> 对话框列表中预先选中的项目索引,如果是单选模式为一个索引;多选模式则为数组
  • positive <string> 对话框确定按钮的文字内容(最右边按钮)
  • positiveColor <string> | <number> 对话框确定按钮的文字颜色(最右边按钮)
  • neutral <string> 对话框中立按钮的文字内容(最左边按钮)
  • @@ -317,9 +320,9 @@ dialogs.select("请选择一个选项", ["选项A", "
    dialogs.build({
         title: "单选",
         items: ["选项1", "选项2", "选项3", "选项4"],
    -    itemsSelectMode: "singleChoice",
    +    itemsSelectMode: "single",
         itemsSelectedIndex: 3
    -}).on("item_select", (index, item)->{
    +}).on("single_choice", (index, item)=>{
         toast("您选择的是" + item);
     }).show();
     

    "处理中"对话框:

    @@ -528,7 +531,26 @@ setTimeout(()=>{ }).on("input_change", (text, dialog)=>{ toast("你输入的是" + text); }).show(); - +

    dialog.getProgress()#

    +
    +

    获取当前进度条的进度值,是一个整数

    +

    dialog.getMaxProgress()#

    +
    +

    获取当前进度条的最大进度值,是一个整数

    +

    dialog.getActionButton(action)#

    +
      +
    • action <string> 动作,包括:
        +
      • positive
      • +
      • negative
      • +
      • neutral
      • +
      +
    • +
    +
    diff --git a/app/src/main/assets/docs/documentation.html b/app/src/main/assets/docs/documentation.html index 2d07b665..3e314ef1 100644 --- a/app/src/main/assets/docs/documentation.html +++ b/app/src/main/assets/docs/documentation.html @@ -2,8 +2,8 @@ - 关于本文档 | Auto.js 3.0.0 文档 - + 关于本文档 | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@
    -

    Auto.js 3.0.0 文档

    +

    Auto.js 4.1.0 文档

    索引 | diff --git a/app/src/main/assets/docs/engines.html b/app/src/main/assets/docs/engines.html index f58ed3d8..3f941928 100644 --- a/app/src/main/assets/docs/engines.html +++ b/app/src/main/assets/docs/engines.html @@ -2,8 +2,8 @@ - Engines | Auto.js 3.0.0 文档 - + Engines | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

    -

    Auto.js 3.0.0 文档

    +

    Auto.js 4.1.0 文档

    索引 | @@ -185,6 +185,10 @@ exec(add, {a: 1, b:2});

    停止所有正在运行的脚本并显示停止的脚本数量。包括当前脚本自身。

    engines.myEngine()#

    返回当前脚本的脚本引擎对象(ScriptEngine)

    +

    [v4.1.0新增] +特别的,该对象可以通过execArgv来获取他的运行参数,包括外部参数、intent等。例如:

    +
    log(engines.myEngine().execArgv);
    +

    普通脚本的运行参数通常为空,通过定时任务的广播启动的则可以获取到启动的intent。

    engines.all()#

    • 返回 <Array>
    • diff --git a/app/src/main/assets/docs/events.html b/app/src/main/assets/docs/events.html index b3f43660..b601d5e0 100644 --- a/app/src/main/assets/docs/events.html +++ b/app/src/main/assets/docs/events.html @@ -2,8 +2,8 @@ - Events | Auto.js 3.0.0 文档 - + Events | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@
      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/files.html b/app/src/main/assets/docs/files.html index a182e972..01ffe297 100644 --- a/app/src/main/assets/docs/files.html +++ b/app/src/main/assets/docs/files.html @@ -2,8 +2,8 @@ - Files | Auto.js 3.0.0 文档 - + Files | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/floaty.html b/app/src/main/assets/docs/floaty.html index c68ae3a6..145e078f 100644 --- a/app/src/main/assets/docs/floaty.html +++ b/app/src/main/assets/docs/floaty.html @@ -2,8 +2,8 @@ - Floaty | Auto.js 3.0.0 文档 - + Floaty | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/globals.html b/app/src/main/assets/docs/globals.html index 0635fe44..1301d20e 100644 --- a/app/src/main/assets/docs/globals.html +++ b/app/src/main/assets/docs/globals.html @@ -2,8 +2,8 @@ - 全局变量与函数 | Auto.js 3.0.0 文档 - + 全局变量与函数 | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

    @@ -232,6 +234,23 @@ runtime.requestPermissions(["access_fine_location"]);

    您可以通过APK编辑器来增加Auto.js以及Auto.js打包的应用的权限。

    安卓所有的权限列表参见Permissions Overview。(并没有用)

    +

    runtime.loadJar(path)#

    +
    +

    加载目标jar文件,加载成功后将可以使用该Jar文件的类。

    +
    // 加载jsoup.jar
    +runtime.loadJar("./jsoup.jar");
    +// 使用jsoup解析html
    +importClass(org.jsoup.Jsoup);
    +log(Jsoup.parse(files.read("./test.html")));
    +

    (jsoup是一个Java实现的解析Html DOM的库,可以在Jsoup下载)

    +

    runtime.loadDex(path)#

    +
    +

    加载目标dex文件,加载成功后将可以使用该dex文件的类。

    +

    因为加载jar实际上是把jar转换为dex再加载的,因此加载dex文件会比jar文件快得多。可以使用Android SDK的build tools的dx工具把jar转换为dex。

    context#

    全局变量。一个android.content.Context对象。

    注意该对象为ApplicationContext,因此不能用于界面、对话框等的创建。

    diff --git a/app/src/main/assets/docs/http.html b/app/src/main/assets/docs/http.html index 1d49d548..d3f85e40 100644 --- a/app/src/main/assets/docs/http.html +++ b/app/src/main/assets/docs/http.html @@ -2,8 +2,8 @@ - HTTP | Auto.js 3.0.0 文档 - + HTTP | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@
    -

    Auto.js 3.0.0 文档

    +

    Auto.js 4.1.0 文档

    索引 | diff --git a/app/src/main/assets/docs/images.html b/app/src/main/assets/docs/images.html index 9e009677..7cb1f7c3 100644 --- a/app/src/main/assets/docs/images.html +++ b/app/src/main/assets/docs/images.html @@ -2,8 +2,8 @@ - colors | Auto.js 3.0.0 文档 - + colors | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

    -

    Auto.js 3.0.0 文档

    +

    Auto.js 4.1.0 文档

    索引 | @@ -100,19 +100,35 @@

  • colors.MAGENTA
  • colors.TRANSPARENT
  • Images +
  • +
  • MatchingResult
  • Image
      @@ -246,7 +277,304 @@ log(colors.equals(0xFF112233, 0xFF223344));

      colors.TRANSPARENT#

      透明,颜色值 #00000000

      Images#

      -
      Stability: 2 - Stable

      images模块提供了一些手机设备中常见的图片处理函数,包括截图、读写图片、图片剪裁、找色、找图等。

      +
      Stability: 2 - Stable

      images模块提供了一些手机设备中常见的图片处理函数,包括截图、读写图片、图片剪裁、旋转、二值化、找色找图等。

      +

      该模块分为两个部分,找图找色部分和图片处理部分。

      +

      需要注意的是,image对象创建后尽量在不使用时进行回收,同时避免循环创建大量图片。因为图片是一种占用内存比较大的资源,尽管Auto.js通过各种方式(比如图片缓存机制、垃圾回收时回收图片、脚本结束时回收所有图片)尽量降低图片资源的泄漏和内存占用,但是糟糕的代码仍然可以占用大量内存。

      +

      Image对象通过调用recycle()函数来回收。例如:

      +
      // 读取图片
      +var img = images.read("./1.png");
      +//对图片进行操作
      +... 
      +// 回收图片
      +img.recycle();
      +

      例外的是,caputerScreen()返回的图片不需要回收。

      +

      图片处理#

      +

      images.read(path)#

      +
      +

      读取在路径path的图片文件并返回一个Image对象。如果文件不存在或者文件无法解码则返回null。

      +

      images.load(url)#

      +
      +

      加载在地址URL的网络图片并返回一个Image对象。如果地址不存在或者图片无法解码则返回null。

      +

      images.copy(img)#

      +
        +
      • img <Image> 图片
      • +
      • 返回 <Image>
      • +
      +

      复制一张图片并返回新的副本。该函数会完全复制img对象的数据。

      +

      images.save(image, path[, format = "png", quality = 100])#

      +
        +
      • image <Image> 图片
      • +
      • path <string> 路径
      • +
      • format <string> 图片格式,可选的值为:
          +
        • png
        • +
        • jpeg/jpg
        • +
        • webp
        • +
        +
      • +
      • quality <number> 图片质量,为0~100的整数值
      • +
      +

      把图片image以PNG格式保存到path中。如果文件不存在会被创建;文件存在会被覆盖。

      +
      //把图片压缩为原来的一半质量并保存
      +var img = images.read("/sdcard/1.png");
      +images.save(img, "/sdcard/1.jpg", "jpg", 50);
      +app.viewFile("/sdcard/1.jpg");
      +

      images.fromBase64(base64)#

      +
        +
      • base64 <string> 图片的Base64数据
      • +
      • 返回 <Image>
      • +
      +

      解码Base64数据并返回解码后的图片Image对象。如果base64无法解码则返回null

      +

      images.toBase64(img[, format = "png", quality = 100])#

      +
        +
      • image <image> 图片
      • +
      • format <string> 图片格式,可选的值为:
          +
        • png
        • +
        • jpeg/jpg
        • +
        • webp
        • +
        +
      • +
      • quality <number> 图片质量,为0~100的整数值
      • +
      • 返回 <string>
      • +
      +

      把图片编码为base64数据并返回。

      +

      images.fromBytes(bytes)#

      +
        +
      • bytes <byte[]> 字节数组
      • +
      +

      解码字节数组bytes并返回解码后的图片Image对象。如果bytes无法解码则返回null

      +

      images.toBytes(img[, format = "png", quality = 100])#

      +
        +
      • image <image> 图片
      • +
      • format <string> 图片格式,可选的值为:
          +
        • png
        • +
        • jpeg/jpg
        • +
        • webp
        • +
        +
      • +
      • quality <number> 图片质量,为0~100的整数值
      • +
      • 返回 <byte[]>
      • +
      +

      把图片编码为字节数组并返回。

      +

      images.clip(img, x, y, w, h)#

      +
        +
      • img <Image> 图片
      • +
      • x <number> 剪切区域的左上角横坐标
      • +
      • y <number> 剪切区域的左上角纵坐标
      • +
      • w <number> 剪切区域的宽度
      • +
      • h <number> 剪切区域的高度
      • +
      • 返回 <Image>
      • +
      +

      从图片img的位置(x, y)处剪切大小为w * h的区域,并返回该剪切区域的新图片。

      +
      var src = images.read("/sdcard/1.png");
      +var clip = images.clip(src, 100, 100, 400, 400);
      +images.save(clip, "/sdcard/clip.png");
      +

      images.resize(img, size[, interpolation])#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 图片
      • +
      • size <Array> 两个元素的数组[w, h],分别表示宽度和高度;如果只有一个元素,则宽度和高度相等
      • +
      • interpolation <string> 插值方法,可选,默认为"LINEAR"(线性插值),可选的值有:

        +
          +
        • NEAREST 最近邻插值
        • +
        • LINEAR 线性插值(默认)
        • +
        • AREA 区域插值
        • +
        • CUBIC 三次样条插值
        • +
        • LANCZOS4 Lanczos插值 +参见InterpolationFlags
        • +
        +
      • +
      • 返回 <Image>

        +
      • +
      +

      调整图片大小,并返回调整后的图片。例如把图片放缩为200*300:images.resize(img, [200, 300])

      +

      参见Imgproc.resize

      +

      images.scale(img, fx, fy[, interpolation])#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 图片
      • +
      • fx <number> 宽度放缩倍数
      • +
      • fy <number> 高度放缩倍数
      • +
      • interpolation <string> 插值方法,可选,默认为"LINEAR"(线性插值),可选的值有:

        +
          +
        • NEAREST 最近邻插值
        • +
        • LINEAR 线性插值(默认)
        • +
        • AREA 区域插值
        • +
        • CUBIC 三次样条插值
        • +
        • LANCZOS4 Lanczos插值 +参见InterpolationFlags
        • +
        +
      • +
      • 返回 <Image>

        +
      • +
      +

      放缩图片,并返回放缩后的图片。例如把图片变成原来的一半:images.scale(img, 0.5, 0.5)

      +

      参见Imgproc.resize

      +

      images.rotate(img, degress[, x, y])#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 图片
      • +
      • degress <number> 旋转角度。
      • +
      • x <number> 旋转中心x坐标,默认为图片中点
      • +
      • y <number> 旋转中心y坐标,默认为图片中点
      • +
      • 返回 <Image>
      • +
      +

      将图片逆时针旋转degress度,返回旋转后的图片对象。

      +

      例如逆时针旋转90度为images.rotate(img, 90)

      +

      images.concat(img1, image2[, direction])#

      +

      [v4.1.0新增]

      +
        +
      • img1 <Image> 图片1
      • +
      • img2 <Image> 图片2
      • +
      • direction <string> 连接方向,默认为"RIGHT",可选的值有:
          +
        • LEFT 将图片2接到图片1左边
        • +
        • RIGHT 将图片2接到图片1右边
        • +
        • TOP 将图片2接到图片1上边
        • +
        • BOTTOM 将图片2接到图片1下边
        • +
        +
      • +
      • 返回 <Image>
      • +
      +

      连接两张图片,并返回连接后的图像。如果两张图片大小不一致,小的那张将适当居中。

      +

      images.grayscale(img)#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 图片
      • +
      • 返回 <Image>
      • +
      +

      灰度化图片,并返回灰度化后的图片。

      +

      image.threshold(img, threshold, maxVal[, type])#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 图片
      • +
      • threshold <number> 阈值
      • +
      • maxVal <number> 最大值
      • +
      • type <string> 阈值化类型,默认为"BINARY",参见ThresholdTypes, 可选的值:

        +
          +
        • BINARY
        • +
        • BINARY_INV
        • +
        • TRUNC
        • +
        • TOZERO
        • +
        • TOZERO_INV
        • +
        • OTSU
        • +
        • TRIANGLE
        • +
        +
      • +
      • 返回 <Image>

        +
      • +
      +

      将图片阈值化,并返回处理后的图像。可以用这个函数进行图片二值化。例如:images.threshold(img, 100, 255, "BINARY"),这个代码将图片中大于100的值全部变成255,其余变成0,从而达到二值化的效果。如果img是一张灰度化图片,这个代码将会得到一张黑白图片。

      +

      可以参考有关博客(比如threshold函数的使用)或者OpenCV文档threshold

      +

      images.adaptiveThreshold(img, maxValue, adaptiveMethod, thresholdType, blockSize, C)#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 图片
      • +
      • maxValue <number> 最大值
      • +
      • adaptiveMethod <string> 在一个邻域内计算阈值所采用的算法,可选的值有:
          +
        • MEAN_C 计算出领域的平均值再减去参数C的值
        • +
        • GAUSSIAN_C 计算出领域的高斯均值再减去参数C的值
        • +
        +
      • +
      • thresholdType <string> 阈值化类型,可选的值有:
          +
        • BINARY
        • +
        • BINARY_INV
        • +
        +
      • +
      • blockSize <number> 邻域块大小
      • +
      • C <number> 偏移值调整量
      • +
      • 返回 <Image>
      • +
      +

      对图片进行自适应阈值化处理,并返回处理后的图像。

      +

      可以参考有关博客(比如threshold与adaptiveThreshold)或者OpenCV文档adaptiveThreshold

      +

      images.cvtColor(img, code[, dstCn])#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 图片
      • +
      • code <string> 颜色空间转换的类型,可选的值有一共有205个(参见ColorConversionCodes),这里只列出几个:
          +
        • BGR2GRAY BGR转换为灰度
        • +
        • BGR2HSV BGR转换为HSV
        • +
        • ``
        • +
        +
      • +
      • dstCn <number> 目标图像的颜色通道数量,如果不填写则根据其他参数自动决定。
      • +
      • 返回 <Image>
      • +
      +

      对图像进行颜色空间转换,并返回转换后的图像。

      +

      可以参考有关博客(比如颜色空间转换)或者OpenCV文档cvtColor

      +

      images.inRange(img, lowerBound, upperBound)#

      +

      [v4.1.0新增]

      + +

      将图片二值化,在lowerBound~upperBound范围以外的颜色都变成0,在范围以内的颜色都变成255。

      +

      例如images.inRange(img, "#000000", "#222222")

      +

      images.interval(img, color, interval)#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 图片
      • +
      • color <string> | <number> 颜色值
      • +
      • interval <number> 每个通道的范围间隔
      • +
      • 返回 <Image>
      • +
      +

      将图片二值化,在color-interval ~ color+interval范围以外的颜色都变成0,在范围以内的颜色都变成255。这里对color的加减是对每个通道而言的。

      +

      例如images.interval(img, "#888888", 16),每个通道的颜色值均为0x88,加减16后的范围是[0x78, 0x98],因此这个代码将把#787878~#989898的颜色变成#FFFFFF,而把这个范围以外的变成#000000。

      +

      images.blur(img, size[, anchor, type])#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 图片
      • +
      • size <Array> 定义滤波器的大小,如[3, 3]
      • +
      • anchor <Array> 指定锚点位置(被平滑点),默认为图像中心
      • +
      • type <string> 推断边缘像素类型,默认为"DEFAULT",可选的值有:
          +
        • CONSTANT iiiiii|abcdefgh|iiiiiii with some specified i
        • +
        • REPLICATE aaaaaa|abcdefgh|hhhhhhh
        • +
        • REFLECT fedcba|abcdefgh|hgfedcb
        • +
        • WRAP cdefgh|abcdefgh|abcdefg
        • +
        • REFLECT_101 gfedcb|abcdefgh|gfedcba
        • +
        • TRANSPARENT uvwxyz|abcdefgh|ijklmno
        • +
        • REFLECT101 same as BORDER_REFLECT_101
        • +
        • DEFAULT same as BORDER_REFLECT_101
        • +
        • ISOLATED do not look outside of ROI
        • +
        +
      • +
      • 返回 <Image>
      • +
      +

      对图像进行模糊(平滑处理),返回处理后的图像。

      +

      可以参考有关博客(比如实现图像平滑处理)或者OpenCV文档blur

      +

      images.medianBlur(img, size)#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 图片
      • +
      • size <Array> 定义滤波器的大小,如[3, 3]
      • +
      • 返回 <Image>
      • +
      +

      对图像进行中值滤波,返回处理后的图像。

      +

      可以参考有关博客(比如实现图像平滑处理)或者OpenCV文档blur

      +

      images.gaussianBlur(img, size[, sigmaX, sigmaY, type])#

      +

      [v4.1.0新增]

      +
        +
      • img <Image> 图片
      • +
      • size <Array> 定义滤波器的大小,如[3, 3]
      • +
      • sigmaX <number> x方向的标准方差,不填写则自动计算
      • +
      • sigmaY <number> y方向的标准方差,不填写则自动计算
      • +
      • type <string> 推断边缘像素类型,默认为"DEFAULT",参见images.blur
      • +
      • 返回 <Image>
      • +
      +

      对图像进行高斯模糊,返回处理后的图像。

      +

      可以参考有关博客(比如实现图像平滑处理)或者OpenCV文档GaussianBlur

      +

      images.matToImage(mat)#

      +

      [v4.1.0新增]

      +
        +
      • mat <Mat> OpenCV的Mat对象
      • +
      • 返回 <Image>
      • +
      +

      把Mat对象转换为Image对象。

      +

      找图找色#

      images.requestScreenCapture([landscape])#

      • landscape <boolean> 布尔值, 表示将要执行的截屏是否为横屏。如果landscape为false, 则表示竖屏截图; true为横屏截图。
      • @@ -300,90 +628,7 @@ toast(colors.toString(color));

      返回图片image在点(x, y)处的像素的ARGB值。

      该值的格式为0xAARRGGBB,是一个"32位整数"(虽然JavaScript中并不区分整数类型和其他数值类型)。

      坐标系以图片左上角为原点。以图片左侧边为y轴,上侧边为x轴。

      -

      images.copy(img)#

      -
        -
      • img <Image> 图片
      • -
      • 返回 <Image>
      • -
      -

      复制一张图片并返回新的副本。该函数会完全复制img对象的数据。

      -

      images.save(image, path[, format = "png", quality = 100])#

      -
        -
      • image <Image> 图片
      • -
      • path <string> 路径
      • -
      • format <string> 图片格式,可选的值为:
          -
        • png
        • -
        • jpeg/jpg
        • -
        • webp
        • -
        -
      • -
      • quality <number> 图片质量,为0~100的整数值
      • -
      -

      把图片image以PNG格式保存到path中。如果文件不存在会被创建;文件存在会被覆盖。

      -
      //把图片压缩为原来的一半质量并保存
      -var img = images.read("/sdcard/1.png");
      -images.save(img, "/sdcard/1.jpg", "jpg", 50);
      -app.viewFile("/sdcard/1.jpg");
      -

      images.read(path)#

      -
      -

      读取在路径path的图片文件并返回一个Image对象。如果文件不存在或者文件无法解码则返回null。

      -

      images.load(url)#

      -
      -

      加载在地址URL的网络图片并返回一个Image对象。如果地址不存在或者图片无法解码则返回null。

      -

      images.fromBase64(base64)#

      -
        -
      • base64 <string> 图片的Base64数据
      • -
      • 返回 <Image>
      • -
      -

      解码Base64数据并返回解码后的图片Image对象。如果base64无法解码则返回null

      -

      images.toBase64(img[, format = "png", quality = 100])#

      -
        -
      • image <image> 图片
      • -
      • format <string> 图片格式,可选的值为:
          -
        • png
        • -
        • jpeg/jpg
        • -
        • webp
        • -
        -
      • -
      • quality <number> 图片质量,为0~100的整数值
      • -
      • 返回 <string>
      • -
      -

      把图片编码为base64数据并返回。

      -

      images.fromBytes(bytes)#

      -
        -
      • bytes <byte[]> 字节数组
      • -
      -

      解码字节数组bytes并返回解码后的图片Image对象。如果bytes无法解码则返回null

      -

      images.toBytes(img[, format = "png", quality = 100])#

      -
        -
      • image <image> 图片
      • -
      • format <string> 图片格式,可选的值为:
          -
        • png
        • -
        • jpeg/jpg
        • -
        • webp
        • -
        -
      • -
      • quality <number> 图片质量,为0~100的整数值
      • -
      • 返回 <byte[]>
      • -
      -

      把图片编码为字节数组并返回。

      -

      images.clip(img, x, y, w, h)#

      -
        -
      • img <Image> 图片
      • -
      • x <number> 剪切区域的左上角横坐标
      • -
      • y <number> 剪切区域的左上角纵坐标
      • -
      • w <number> 剪切区域的宽度
      • -
      • h <number> 剪切区域的高度
      • -
      • 返回 <Image>
      • -
      -

      从图片img的位置(x, y)处剪切大小为w * h的区域,并返回该剪切区域的新图片。

      -
      var src = images.read("/sdcard/1.png");
      -var clip = images.clip(src, 100, 100, 400, 400);
      -images.save(clip, "/sdcard/clip.png");
      -

      images.findColor(image, color, options)#

      +

      images.findColor(image, color, options)#

      • image <Image> 图片
      • color <number> | <string> 要寻找的颜色的RGB值。如果是一个整数,则以0xRRGGBB的形式代表RGB值(A通道会被忽略);如果是字符串,则以"#RRGGBB"代表其RGB值。
      • @@ -561,7 +806,94 @@ if(p){ threshold: threshold })

        该函数也可以作为全局函数使用。

        -

        Image#

        +

        images.matchTemplate(img, template, options)#

        +

        [v4.1.0新增]

        +
          +
        • img <Image> 大图片
        • +
        • template <Image> 小图片(模板)
        • +
        • options <Object> 找图选项:
            +
          • threshold <number> 图片相似度。取值范围为0~1的浮点数。默认值为0.9。
          • +
          • region <Array> 找图区域。参见findColor函数关于region的说明。
          • +
          • max <number> 找图结果最大数量,默认为5
          • +
          • level <number> 一般而言不必修改此参数。不加此参数时该参数会根据图片大小自动调整。找图算法是采用图像金字塔进行的, level参数表示金字塔的层次, level越大可能带来越高的找图效率,但也可能造成找图失败(图片因过度缩小而无法分辨)或返回错误位置。因此,除非您清楚该参数的意义并需要进行性能调优,否则不需要用到该参数。
          • +
          +
        • +
        • 返回 <MatchingResult>
        • +
        +

        在大图片中搜索小图片,并返回搜索结果MatchingResult。该函数可以用于找图时找出多个位置,可以通过max参数控制最大的结果数量。也可以对匹配结果进行排序、求最值等操作。

        +

        MatchingResult#

        +

        [v4.1.0新增]

        +

        matches#

        +
          +
        • <Array> 匹配结果的数组。
        • +
        +

        数组的元素是一个Match对象:

        +
          +
        • point <Point> 匹配位置
        • +
        • similarity <number> 相似度
        • +
        +

        例如:

        +
        var result = images.matchTemplate(img, template, {
        +    max: 100
        +});
        +result.matches.forEach(match => {
        +    log("point = " + match.point + ", similarity = " + match.similarity);
        +});
        +

        points#

        +
          +
        • <Array> 匹配位置的数组。
        • +
        +

        first()#

        +
          +
        • 返回 <Match>
        • +
        +

        第一个匹配结果。如果没有任何匹配,则返回null

        +

        last()#

        +
          +
        • 返回 <Match>
        • +
        +

        最后一个匹配结果。如果没有任何匹配,则返回null

        +

        leftmost()#

        +
          +
        • 返回 <Match>
        • +
        +

        位于大图片最左边的匹配结果。如果没有任何匹配,则返回null

        +

        topmost()#

        +
          +
        • 返回 <Match>
        • +
        +

        位于大图片最上边的匹配结果。如果没有任何匹配,则返回null

        +

        rightmost()#

        +
          +
        • 返回 <Match>
        • +
        +

        位于大图片最右边的匹配结果。如果没有任何匹配,则返回null

        +

        bottommost()#

        +
          +
        • 返回 <Match>
        • +
        +

        位于大图片最下边的匹配结果。如果没有任何匹配,则返回null

        +

        best()#

        +
          +
        • 返回 <Match>
        • +
        +

        相似度最高的匹配结果。如果没有任何匹配,则返回null

        +

        worst()#

        +
          +
        • 返回 <Match>
        • +
        +

        相似度最低的匹配结果。如果没有任何匹配,则返回null

        +

        sortBy(cmp)#

        +
          +
        • cmp <Function>|<string> 比较函数,或者是一个字符串表示排序方向。例如"left"表示将匹配结果按匹配位置从左往右排序、"top"表示将匹配结果按匹配位置从上往下排序,"left-top"表示将匹配结果按匹配位置从左往右、从上往下排序。方向包括left(左), top (上), right (右), bottom(下)。
        • +
        • <MatchingResult>
        • +
        +

        对匹配结果进行排序,并返回排序后的结果。

        +
        var result = images.matchTemplate(img, template, {
        +    max: 100
        +});
        +log(result.sortBy("top-right"));
        +

        Image#

        表示一张图片,可以是截图的图片,或者本地读取的图片,或者从网络获取的图片。

        Image.getWidth()#

        返回以像素为单位图片宽度。

        @@ -580,6 +912,7 @@ if(p){

      返回图片image在点(x, y)处的像素的ARGB值。

      该值的格式为0xAARRGGBB,是一个"32位整数"(虽然JavaScript中并不区分整数类型和其他数值类型)。

      坐标系以图片左上角为原点。以图片左侧边为y轴,上侧边为x轴。

      +

      ##

      Point#

      findColor, findImage返回的对象。表示一个点(坐标)。

      Point.x#

      diff --git a/app/src/main/assets/docs/index.html b/app/src/main/assets/docs/index.html index eb58ec90..770dccde 100644 --- a/app/src/main/assets/docs/index.html +++ b/app/src/main/assets/docs/index.html @@ -2,8 +2,8 @@ - Index | Auto.js 3.0.0 文档 - + Index | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@
      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/keys.html b/app/src/main/assets/docs/keys.html index 5bf46617..521833d9 100644 --- a/app/src/main/assets/docs/keys.html +++ b/app/src/main/assets/docs/keys.html @@ -2,8 +2,8 @@ - Keys | Auto.js 3.0.0 文档 - + Keys | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/media.html b/app/src/main/assets/docs/media.html index 68c9a799..ec975664 100644 --- a/app/src/main/assets/docs/media.html +++ b/app/src/main/assets/docs/media.html @@ -2,8 +2,8 @@ - Media | Auto.js 3.0.0 文档 - + Media | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/modules.html b/app/src/main/assets/docs/modules.html index 06c95226..823b5edb 100644 --- a/app/src/main/assets/docs/modules.html +++ b/app/src/main/assets/docs/modules.html @@ -2,8 +2,8 @@ - module (模块) | Auto.js 3.0.0 文档 - + module (模块) | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | @@ -83,7 +83,7 @@

      module (模块)#

      Stability: 2 - Stable

      Auto.js 有一个简单的模块加载系统。 在 Auto.js 中,文件和模块是一一对应的(每个文件被视为一个独立的模块)。

      例子,假设有一个名为 foo.js 的文件:

      -
      const circle = require('circle.js');
      +
      var circle = require('circle.js');
       console.log("半径为 4 的圆的面积是 %d", circle.area(4));
       

      在第一行中,foo.js 加载了同一目录下的 circle.js 模块。

      circle.js 文件的内容为:

      @@ -91,7 +91,9 @@ console.log("半径为 4 的圆的面积是 %d", circle.area(4)); var circle = {}; -circle.area = (r) => PI * r ** 2; +circle.area = function (r) { + return PI * r * r; +}; circle.circumference = (r) => 2 * PI * r; diff --git a/app/src/main/assets/docs/overview.html b/app/src/main/assets/docs/overview.html index d69dd815..62da9798 100644 --- a/app/src/main/assets/docs/overview.html +++ b/app/src/main/assets/docs/overview.html @@ -2,8 +2,8 @@ - 综述 | Auto.js 3.0.0 文档 - + 综述 | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@
      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/qa.html b/app/src/main/assets/docs/qa.html index 2aaf28af..bc39a66e 100644 --- a/app/src/main/assets/docs/qa.html +++ b/app/src/main/assets/docs/qa.html @@ -2,8 +2,8 @@ - Q & A | Auto.js 3.0.0 文档 - + Q & A | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | @@ -76,8 +76,9 @@

      • Q & A
      • @@ -89,35 +90,30 @@

        Q & A#

        如何定时运行脚本#

        点击脚本右边的菜单按钮->更多->定时任务即可定时运行脚本,但是必须保持Auto.js后台运行(自启动白名单、电源管理白名单等)。同时,可以在脚本的开头使用device.wakeUp()来唤醒屏幕;但是,Auto.js没有解锁屏幕的功能,因此难以在有锁屏密码的设备上达到效果。

        -

        如何把图片和脚本一起打包,或者打包多个脚本#

        -

        如果除了单脚本以外还有其他脚本、图片、音乐等资源一起打包,则需要使用项目打包功能。

        -
          -
        1. 新建一个文件夹,命名为项目名称。
        2. -
        3. 在该文件夹下新建脚本,或者移动脚本到该文件夹,命名为main.js,表示主脚本。脚本打包后将会从该脚本开始运行。
        4. -
        5. 把其他资源或脚本放在该文件夹,并通过相对路径引用。
        6. -
        7. 通过文件夹菜单的"打包"功能来打包该项目
        8. -
        +

        定时任何如何获取外部参数#

        +

        如果一个脚本是用intent"启动"的,比如定时任务中的特定事件(网络状态变化等)触发而启动的,则可以通过engines.myEngine().execArgv.intent获取启动的intent,从而获取外部参数。

        +

        如何把图片和脚本一起打包,或者打包多个脚本#

        +

        如果除了单脚本以外还有其他脚本、图片、音乐等资源一起打包,则需要使用项目功能。

        +

        点击Auto.js的"+"号,选择项目,填写项目名称、包名等信息以后,点击"√"即可新建一个项目。可以在项目中放多个脚本、模块、资源文件,点击项目工具栏的apk打包图标即可打包一个项目,点击工具栏可以重新配置项目。

        例如,主脚本要读取同一文件夹下的图片1.png,再执行找图,则可以通过images.read("./1.png")来读取,其中"./1.png"表示同一目录1.png图片;ui中的图片控件要引用同一文件夹的2.png图片则为<img src="file://2.png"/>。Auto.js内置的函数和模块都支持相对路径,但是,其他情况则需要使用files.path()函数来把相对路径转换为绝对路径。

        -

        目前Auto.js还不支持项目的图形化管理,后续会加入。

        -

        如何使打包的应用不显示主界面#

        -

        需要使用项目打包功能。

        -
          -
        1. 新建一个文件夹,命名为项目名称。
        2. -
        3. 在该文件夹下新建脚本,或者移动脚本到该文件夹,命名为main.js,表示主脚本。脚本打包后将会从该脚本开始运行。
        4. -
        5. 在该文件夹下新建一个project.json的文件,其内容如下:
          {
          -"name": "项目名称",
          -"versionName": "1.0.0",
          -"versionCode": 1,
          -"packageName": "org.autojs.example",
          -"main": "main.js",
          -"launchConfig": {
          -   "hideLogs": true
          +

          如何使打包的应用不显示主界面#

          +

          需要使用项目功能。新建项目后,修改项目下的project.json文件,增加以下条目:

          +
          "launchConfig": {
          +    "hideLogs": true
           }
          +

          例如:

          +
          {
          +  "name": "项目名称",
          +  "versionName": "1.0.0",
          +  "versionCode": 1,
          +  "packageName": "org.autojs.example",
          +  "main": "main.js",
          +  "launchConfig": {
          +      "hideLogs": true
          +  }
           }
          -
          其中,项目名称改为自己的项目名称,"org.autojs.example"改成自己的包名,下面的"launchConfig"表示启动配置,"hideLogs"表示隐藏日志。
        6. -
        7. 通过文件夹菜单的"打包"功能来打包该项目
        8. -
        -

        有关项目打包和配置的更多信息,参见项目与项目配置(待补)。

        +

      "launchConfig"表示启动配置,"hideLogs"表示隐藏日志。

      +

      参见项目与项目配置。

      Auto.js自带的模块和函数中没有的功能如何实现#

      由于Auto.js支持直接调用Android的API,对于Auto.js没有内置的函数,可以直接通过修改Android代码为JavaScript代码实现。例如旋转图片的Android代码为:

      import android.graphics.Bitmap;
      diff --git a/app/src/main/assets/docs/sensors.html b/app/src/main/assets/docs/sensors.html
      index f4c768df..92acf063 100644
      --- a/app/src/main/assets/docs/sensors.html
      +++ b/app/src/main/assets/docs/sensors.html
      @@ -2,8 +2,8 @@
       
       
         
      -  Sensors | Auto.js 3.0.0 文档
      -  
      +  Sensors | Auto.js 4.1.0 文档
      +  
         
         
         
      @@ -61,7 +61,7 @@
       
           
      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/shell.html b/app/src/main/assets/docs/shell.html index 3457d550..92521f32 100644 --- a/app/src/main/assets/docs/shell.html +++ b/app/src/main/assets/docs/shell.html @@ -2,8 +2,8 @@ - shell函数 | Auto.js 3.0.0 文档 - + shell函数 | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/storages.html b/app/src/main/assets/docs/storages.html index 382c36d2..e9cb9b39 100644 --- a/app/src/main/assets/docs/storages.html +++ b/app/src/main/assets/docs/storages.html @@ -2,8 +2,8 @@ - Storages | Auto.js 3.0.0 文档 - + Storages | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/threads.html b/app/src/main/assets/docs/threads.html index d36ade17..08dc2bfe 100644 --- a/app/src/main/assets/docs/threads.html +++ b/app/src/main/assets/docs/threads.html @@ -2,8 +2,8 @@ - Threads | Auto.js 3.0.0 文档 - + Threads | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/timers.html b/app/src/main/assets/docs/timers.html index 264743d5..e7b58674 100644 --- a/app/src/main/assets/docs/timers.html +++ b/app/src/main/assets/docs/timers.html @@ -2,8 +2,8 @@ - Timers | Auto.js 3.0.0 文档 - + Timers | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/ui.html b/app/src/main/assets/docs/ui.html index 3e830c80..784a9458 100644 --- a/app/src/main/assets/docs/ui.html +++ b/app/src/main/assets/docs/ui.html @@ -2,8 +2,8 @@ - 用户界面: UI | Auto.js 3.0.0 文档 - + 用户界面: UI | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | @@ -191,11 +191,12 @@

      用户界面: UI#

      ui模块提供了编写用户界面的支持。

      -

      带有ui的脚本的第一行必须使用"ui"指定ui模式,否则脚本将不会以ui模式运行。正确示范:

      +

      带有ui的脚本的的最前面必须使用"ui";指定ui模式,否则脚本将不会以ui模式运行。正确示范:

      "ui";
       
       //脚本的其他代码
      -

      界面是由视图(View)组成的。View分成两种,控件(Widget)和布局(Layout)。控件(Widget)用来具体显示文字、图片、网页等,比如文本控件(text)用来显示文字,按钮控件(button)则可以显示一个按钮并提供点击效果,图片控件(img)则用来显示来自网络或者文件的图片,除此之外还有输入框控件(input)、进度条控件(progressbar)、单选复选框控件(checkbox)等;布局(Layout)则是装着一个或多个控件的"容器",用于控制在他里面的控件的位置,比如垂直布局(vertical)会把他里面的控件从上往下依次显示(即纵向排列),水平布局(horizontal)则会把他里面的控件从左往右依次显示(即横向排列),以及帧布局(frame),他会把他里面的控件直接在左上角显示,如果有多个控件,后面的控件会重叠在前面的控件上。

      +

      字符串"ui"的前面可以有注释、空行和空格[v4.1.0新增],但是不能有其他代码。

      +

      界面是由视图(View)组成的。View分成两种,控件(Widget)和布局(Layout)。控件(Widget)用来具体显示文字、图片、网页等,比如文本控件(text)用来显示文字,按钮控件(button)则可以显示一个按钮并提供点击效果,图片控件(img)则用来显示来自网络或者文件的图片,除此之外还有输入框控件(input)、进度条控件(progressbar)、单选复选框控件(checkbox)等;布局(Layout)则是装着一个或多个控件的"容器",用于控制在他里面的控件的位置,比如垂直布局(vertical)会把他里面的控件从上往下依次显示(即纵向排列),水平布局(horizontal)则会把他里面的控件从左往右依次显示(即横向排列),以及帧布局(frame),他会把他里面的控件直接在左上角显示,如果有多个控件,后面的控件会重叠在前面的控件上。

      我们使用xml来编写界面,并通过ui.layout()函数指定界面的布局xml。举个例子:

      "ui";
       ui.layout(
      diff --git a/app/src/main/assets/docs/util.html b/app/src/main/assets/docs/util.html
      index 95a7ab29..b759edac 100644
      --- a/app/src/main/assets/docs/util.html
      +++ b/app/src/main/assets/docs/util.html
      @@ -2,8 +2,8 @@
       
       
         
      -  Util | Auto.js 3.0.0 文档
      -  
      +  Util | Auto.js 4.1.0 文档
      +  
         
         
         
      @@ -61,7 +61,7 @@
       
           
      -

      Auto.js 3.0.0 文档

      +

      Auto.js 4.1.0 文档

      索引 | diff --git a/app/src/main/assets/docs/widgets-based-automation.html b/app/src/main/assets/docs/widgets-based-automation.html index d0dc5fec..857f7dfd 100644 --- a/app/src/main/assets/docs/widgets-based-automation.html +++ b/app/src/main/assets/docs/widgets-based-automation.html @@ -2,8 +2,8 @@ - 基于控件的操作 | Auto.js 3.0.0 文档 - + 基于控件的操作 | Auto.js 4.1.0 文档 + @@ -61,7 +61,7 @@

  • SimpleActionAutomator
      @@ -92,6 +99,7 @@
    • UiSelector
      • selector()
      • +
      • UiSelector.algorithm(algorithm)
      • UiSelector.text(str)
      • UiSelector.textContains(str)
      • UiSelector.textStartsWith(prefix)
      • @@ -222,6 +230,7 @@
        auto();
         

        auto.waitFor()#

        检查无障碍服务是否已经启用,如果没有启用则跳转到无障碍服务启用界面,并等待无障碍服务启动;当无障碍服务启动后脚本会继续运行。

        +

        因为该函数是阻塞的,因此除非是有协程特性,否则不能在ui模式下运行该函数,建议在ui模式下使用auto()函数。

        auto.setMode(mode)#

        • mode <string> 模式
        • @@ -231,6 +240,72 @@
        • fast 快速模式。该模式下会启用控件缓存,从而选择器获取屏幕控件更快。对于需要快速的控件查看和操作的脚本可以使用该模式,一般脚本则没有必要使用该函数。
        • normal 正常模式,默认。
        +

        auto.setFlags(flags)#

        +

        [v4.1.0新增]

        +
          +
        • flags <string> | <Array> 一些标志,来启用和禁用某些特性,包括:
            +
          • findOnUiThread 使用该特性后,选择器搜索时会在主进程进行。该特性用于解决线程安全问题导致的次生问题,不过目前貌似已知问题并不是线程安全问题。
          • +
          • useUsageStats 使用该特性后,将会以"使用情况统计"服务的结果来检测当前正在运行的应用包名(需要授予"查看使用情况统计"权限)。如果觉得currentPackage()返回的结果不太准确,可以尝试该特性。
          • +
          • useShell 使用该特性后,将使用shell命令获取当前正在运行的应用的包名、活动名称,但是需要root权限。
          • +
          +
        • +
        +

        启用有关automator的一些特性。例如:

        +
        auto.setFlags(["findOnUiThread", "useShell"]);
        +

        auto.serivce#

        +

        [v4.1.0新增]

        + +

        获取无障碍服务。如果无障碍服务没有启动,则返回null

        +

        参见AccessibilityService

        +

        auto.windows#

        +

        [v4.1.0新增]

        + +

        当前所有窗口(AccessibilityWindowInfo)的数组,可能包括状态栏、输入法、当前应用窗口,弹出窗口、悬浮窗、分屏应用窗口等。可以分别获取每个窗口的布局信息。

        +

        该函数需要Android 5.0以上才能运行。

        +

        auto.root#

        +

        [v4.1.0新增]

        +
          +
        • <UiObject>
        • +
        +

        当前窗口的布局根元素。如果无障碍服务未启动或者WindowFilter均返回false,则会返回null

        +

        如果不设置windowFilter,则当前窗口即为活跃的窗口(获取到焦点、正在触摸的窗口);如果设置了windowFilter,则获取的是过滤的窗口中的第一个窗口。

        +

        如果系统是Android5.0以下,则始终返回当前活跃的窗口的布局根元素。

        +

        auto.rootInActiveWindow#

        +

        [v4.1.0新增]

        +
          +
        • <UiObject>
        • +
        +

        当前活跃的窗口(获取到焦点、正在触摸的窗口)的布局根元素。如果无障碍服务未启动则为null

        +

        auto.setWindowFilter(filter)#

        +

        [v4.1.0新增]

        + +

        设置窗口过滤器。这个过滤器可以决定哪些窗口是目标窗口,并影响选择器的搜索。例如,如果想要选择器在所有窗口(包括状态栏、输入法等)中搜索,只需要使用以下代码:

        +
        auto.setWindowFilter(function(window){
        +    //不管是如何窗口,都返回true,表示在该窗口中搜索
        +    return true;
        +});
        +

        又例如,当前使用了分屏功能,屏幕上有Auto.js和QQ两个应用,但我们只想选择器对QQ界面进行搜索,则:

        +
        auto.setWindowFilter(function(window){
        +    // 对于应用窗口,他的title属性就是应用的名称,因此可以通过title属性来判断一个应用
        +    return window.title == "QQ";
        +});
        +

        选择器默认是在当前活跃的窗口中搜索,不会搜索诸如悬浮窗、状态栏之类的,使用WindowFilter则可以控制搜索的窗口。

        +

        需要注意的是, 如果WindowFilter返回的结果均为false,则选择器的搜索结果将为空。

        +

        另外setWindowFilter函数也会影响auto.windowRoots的结果。

        +

        该函数需要Android 5.0以上才有效。

        +

        auto.windowRoots#

        +

        [v4.1.0新增]

        + +

        返回当前被WindowFilter过滤的窗口的布局根元素组成的数组。

        +

        如果系统是Android5.0以下,则始终返回当前活跃的窗口的布局根元素的数组。

        SimpleActionAutomator#

        Stability: 2 - Stable

        SimpleActionAutomator提供了一些模拟简单操作的函数,例如点击文字、模拟按键等。这些函数可以直接作为全局函数使用。

        click(text[, i])#

        @@ -363,6 +438,18 @@ sendButton.click();

        创建一个新的选择器。但一般情况不需要使用该函数,因为可以直接用相应条件的语句创建选择器。

        由于历史遗留原因,本不应该这样设计(不应该让id(), text()等作为全局函数,而是应该用By.id(), By.text()),但为了后向兼容性只能保留这个设计。

        这样的API设计会污染全局变量,后续可能会支持"去掉这些全局函数而使用By.*"的选项。

        +

        UiSelector.algorithm(algorithm)#

        +

        [v4.1.0新增]

        +
          +
        • algorithm <string> 搜索算法,可选的值有:
            +
          • DFS 深度优先算法,选择器的默认算法
          • +
          • BFS 广度优先算法
          • +
          +
        • +
        +

        指定选择器的搜索算法。例如:

        +
        log(selector().text("文本").algorithm("BFS").find());
        +

        广度优先在控件所在层次较低时,或者布局的层次不多时,通常能更快找到控件。

        UiSelector.text(str)#