ADOBE AIR HTML 开发人员指南


ADOBE AIR HTML 开发人员指南®®上次更新 2011/10/13 法律声明 法律声明 有关法律声明,请参阅 http://help.adobe.com/zh_CN/legalnotices/index.html。iii 上次更新 2011/10/13 目录 第 1 章 : 关于 HTML 环境 HTML 环境概述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 AIR 和 WebKit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 第 2 章 : 在 AIR 中进行 HTML 和 JavaScript 编程 创建基于 HTML 的 AIR 应用程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 示例应用程序和安全启示 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 避免与安全相关的 JavaScript 错误 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 通过 JavaScript 访问 AIR API 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 关于 AIR 中的 URL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 在 HTML 中嵌入 SWF 内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 在 HTML 页中使用 ActionScript 库 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 转换 Date 和 RegExp 对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 跨脚本访问不同安全沙箱中的内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 第 3 章 : 处理 AIR 中与 HTML 相关的事件 HTMLLoader 事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 AIR 类 - 事件处理与 HTML DOM 中其他事件处理的不同之处 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Adobe AIR 事件对象 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 使用 JavaScript 处理运行时事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 第 4 章 : 为 AIR HTML 容器编写脚本 HTMLLoader 对象的显示属性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 访问 HTML 历史记录列表 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 设置在加载 HTML 内容时使用的用户代理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 设置用于 HTML 内容的字符编码 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 为 HTML 内容定义类似于浏览器的用户界面 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 第 5 章 : 使用矢量 矢量基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 创建矢量 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 向矢量中插入元素 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 检索值和删除矢量元素 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 Vector 对象的属性和方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 示例:使用需要矢量的 AIR API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 第 6 章 : AIR 安全性 AIR 安全性基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 安装和更新 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Adobe AIR 中的 HTML 安全性 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63ivADOBE AIR HTML 开发人员指南 目录 上次更新 2011/10/13 通过脚本访问不同域中的内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 写入磁盘 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 安全使用不受信任的内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 开发人员的最佳安全做法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 代码签名 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 第 7 章 : 使用 AIR 本机窗口 AIR 中的本机窗口的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 创建窗口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 管理窗口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 侦听窗口事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 显示全屏窗口 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 第 8 章 : AIR 中的显示屏幕 AIR 中的显示屏幕的基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 枚举屏幕 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 第 9 章 : 使用菜单 菜单基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 创建本机菜单 (AIR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 关于 HTML 中的上下文菜单 (AIR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 显示弹出本机菜单 (AIR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 处理菜单事件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 本机菜单示例:窗口和应用程序菜单 (AIR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 使用 MenuBuilder 框架 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 第 10 章 : AIR 中的任务栏图标 关于任务栏图标 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 停靠栏图标 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 系统任务栏图标 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 Window 任务栏图标和按钮 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 第 11 章 : 使用文件系统 使用 AIR 文件系统 API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 第 12 章 : AIR 中的拖放 HTML 中的拖放 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 将数据拖出 HTML 元素 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 将数据拖入 HTML 元素 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 示例:覆盖默认的 HTML 拖入行为 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 在非应用程序 HTML 沙箱中处理文件放置 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 放置文件释放 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160vADOBE AIR HTML 开发人员指南 目录 上次更新 2011/10/13 第 13 章 : 复制和粘贴 复制粘贴基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 读取和写入系统剪贴板 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 AIR 中的 HTML 复制和粘贴 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 剪贴板数据格式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 第 14 章 : 在 AIR 中使用本地 SQL 数据库 关于本地 SQL 数据库 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 创建和修改数据库 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 操作 SQL 数据库数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 使用同步和异步数据库操作 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 对 SQL 数据库使用加密 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 使用 SQL 数据库的策略 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 第 15 章 : 加密的本地存储区 将数据添加到加密本地存储区 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 访问加密的本地存储区中的数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 从加密的本地存储区中删除数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 第 16 章 : 使用字节数组 读取并写入 ByteArray . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 ByteArray 示例:读取 .zip 文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 第 17 章 : 在 AIR 中添加 PDF 内容 检测 PDF 功能 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 加载 PDF 内容 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 编写 PDF 内容的脚本 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232 对 AIR 中的 PDF 内容的已知限制 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 第 18 章 : 处理声音 声音处理基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 了解声音体系结构 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 加载外部声音文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236 处理嵌入的声音 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 处理声音流文件 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 处理动态生成的音频 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 播放声音 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 处理声音元数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 访问原始声音数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 捕获声音输入 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248viADOBE AIR HTML 开发人员指南 目录 上次更新 2011/10/13 第 19 章 : 客户端系统环境 客户端系统环境基础知识 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 使用 System 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 使用 Capabilities 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 第 20 章 : AIR 应用程序的调用和终止 应用程序调用 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 捕获命令行参数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255 用户登录时调用 AIR 应用程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 从浏览器调用 AIR 应用程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 应用程序终止 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 第 21 章 : 处理 AIR 运行时和操作系统信息 管理文件关联 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 获取运行时版本和修补级别 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 检测 AIR 功能 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 跟踪用户当前状态 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 第 22 章 : 套接字 TCP 套接字 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 UDP 套接字 (AIR) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 IPv6 地址 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 第 23 章 : HTTP 通信 加载外部数据 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 Web 服务请求 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277 在其他应用程序中打开 URL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 向服务器发送 URL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 第 24 章 : 与其他 Flash Player 和 AIR 实例通信 关于 LocalConnection 类 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 在两个应用程序之间发送消息 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 连接到不同域中的内容和 AIR 应用程序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 第 25 章 : 针对 JavaScript 开发人员的 ActionScript 基础知识 ActionScript 和 JavaScript 之间的差异:概述 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 ActionScript 3.0 数据类型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 ActionScript 3.0 类、包和命名空间 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 ActionScript 3.0 函数中的必需参数和默认值 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 ActionScript 3.0 事件侦听器 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292 第 26 章 : 本地数据库中的 SQL 支持 支持的 SQL 语法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293 数据类型支持 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310viiADOBE AIR HTML 开发人员指南 目录 上次更新 2011/10/13 第 27 章 : SQL 错误详细消息、 ID 和参数1 上次更新 2011/10/13 第 1 章 : 关于 HTML 环境 Adobe AIR 1.0 和更高版本 AIR 和 Safari Web 浏览器均使用 WebKit (www.webkit.org) 分析、布局和呈现 HTML 和 JavaScript 内容。AIR 的内置主 机类和对象为传统上与桌面应用程序关联的功能提供了一个 API。这些功能包括读取和写入文件以及管理窗口。 Adobe AIR 还继承了 Adobe® Flash® Player 的 API,其中包括声音和二进制套接字等功能。 重要说明:Adobe AIR 运行时的新版本可能包含 WebKit 的更新版本。AIR 新版本中的 WebKit 更新可能会对已部署的 AIR 应用程序造成意外更改。这些更改可能会影响应用程序中 HTML 内容的行为或外观。例如, WebKit 呈现中的改进或更正可 能会更改应用程序用户界面中元素的布局。为此,我们强烈建议您在应用程序中提供一个更新机制。如果因 AIR 中包含的 WebKit 版本发生更改而需要更新应用程序, AIR 更新机制可提示用户安装应用程序的新版本。 下表列出了所使用的 WebKit 版本与 AIR 中使用的 WebKit 版本相同的 Safari Web 浏览器版本: 您始终可以通过检查由 HTMLLoader 对象返回的默认用户代理字符串来确定 WebKit 的已安装版本: air.trace( window.htmlLoader.userAgent ); 请记住,AIR 中使用的 WebKit 版本与开放源版本不同。AIR 中不支持某些功能,并且 AIR 版本可以包括在相应 WebKit 版 本中尚不可用的安全性和错误修复功能。请参阅 第 13 页的 “AIR 中不支持的 WebKit 功能 ”。 在 HTML 内容中使用 AIR API 是完全可选的。您可以完全使用 HTML 和 JavaScript 编写 AIR 应用程序。大多数现有 HTML 应用程序只需少量更改即可运行(假定它们使用的 HTML、 CSS、 DOM 和 JavaScript 功能与 WebKit 兼容)。 AIR 授予您对应用程序外观的完全控制权限。您可以使应用程序的外观类似于本机桌面应用程序。还可以关闭由操作系统提供 的窗口镶边,并实现您自己的用于移动窗口、调整窗口大小和关闭窗口的控件。您甚至可以在没有窗口的情况下运行。 由于 AIR 应用程序直接在桌面上运行,且具有对文件系统的完全访问权限,因此,对应的安全模型比典型 Web 浏览器的安全 模型更加严格。在 AIR 中,只有从应用程序安装目录加载的内容才会被放置到应用程序沙箱 中。应用程序沙箱具有最高级别 的权限,且允许访问 AIR API。AIR 根据其他内容的来源将这些内容放置到隔离沙箱中。从文件系统加载的文件放置到本地沙 箱中。使用 http: 或 https: 协议从网络加载的文件则根据远程服务器的域放置到相应沙箱中。禁止这些非应用程序沙箱中的内 容访问任何 AIR API,且其运行方式与在典型 Web 浏览器中几乎一样。 如果应用 Alpha、缩放或透明度设置,则 AIR 中的 HTML 内容不显示 SWF 或 PDF 内容。有关详细信息,请参阅第 42 页的 “ 在 HTML 页中加载 SWF 或 PDF 内容时的注意事项 ” 和第 76 页的 “ 窗口透明度 ”。 更多帮助主题 Webkit DOM 参考 Safari HTML 参考 Safari CSS 参考 www.webkit.org AIR 版本 Safari 版本 1.0 2.04 1.1 3.04 1.5 4.0 测试版 2.0 4.03 2.5 4.03 2.6 4.03 2.7 4.03 3 5.0.32ADOBE AIR HTML 开发人员指南 关于 HTML 环境 上次更新 2011/10/13 HTML 环境概述 Adobe AIR 1.0 和更高版本 Adobe AIR 使用 HTML 渲染器、文档对象模型和 JavaScript 解释程序提供与浏览器完全相似的 JavaScript 环境。 JavaScript 环境通过 AIR HTMLLoader 类表示。在 HTML 窗口中,HTMLLoader 对象包含所有 HTML 内容,而该对象 又包含在 NativeWindow 对象中。通过 NativeWindow 对象,应用程序可以为用户桌面上显示的本机操作系统窗口的属性和 行为撰写脚本。 关于 JavaScript 环境及其与 AIR 主机之间的关系 Adobe AIR 1.0 和更高版本 下图演示了 JavaScript 环境和 AIR 运行时环境的关系。虽然只显示了一个本机窗口,但是一个 AIR 应用程序可以包含多个窗 口。(并且一个窗口可以包含多个 HTMLLoader 对象。) JavaScript 环境具有其自己的 Document 和 Window 对象。JavaScript 代码可以通过 runtime、nativeWindow 和 htmlLoader 属性与 AIR 运行时环 境交互。 ActionScript 代码可以通过 HTMLLoader 对象的 window 属性与 JavaScript 环境交互,该属性是对 JavaScript Window 对象的引用。此外, ActionScript 和 JavaScript 对象均可以侦听由 AIR 和 JavaScript 对象调度的事件。 runtime 属性提供了对 AIR API 类的访问权限,使您可以新建 AIR 对象和访问类(也称为静态)成员。若要访问 AIR API, 请向 runtime 属性添加该类的名称和包。例如,若要创建 File 对象,您将使用以下语句: var file = new window.runtime.filesystem.File(); AIR 䖤㸠ᯊ⦃๗ NativeWindow HTMLLoader JavaScript ⦃๗ window window document body h1 div p table head htmlLoader nativeWindow 䖤㸠ᯊ3ADOBE AIR HTML 开发人员指南 关于 HTML 环境 上次更新 2011/10/13 注: AIR SDK 提供了一个 JavaScript 文件,即 AIRAliases.js,该文件为最常用的 AIR 类定义了更便于使用的别名。导入该文 件时,您可以使用 air.Class 简短形式替换 window.runtime.package.Class。例如,您可以使用 new air.File() 创建 File 对象。 NativeWindow 对象提供了用于控制桌面窗口的属性。您可以使用 window.nativeWindow 属性从 HTML 页内部访问包含的 NativeWindow 对象。 HTMLLoader 对象提供了用于控制内容的加载方式和呈现方式的属性、方法和事件。您可以使用 window.htmlLoader 属性从 HTML 页内部访问父 HTMLLoader 对象。 重要说明: 仅当作为应用程序的一部分安装的页作为顶级文档加载时,该页才具有 htmlLoader、 nativeWindow 或 runtime 属 性。将文档加载到 frame 或 iframe 中时不会添加这些属性。(只要子文档与父文档位于相同安全沙箱中,子文档即可访问父文 档的这些属性。例如,加载到 frame 中的文档可以使用 parent.runtime 访问其父级的 runtime 属性。) 关于安全性 Adobe AIR 1.0 和更高版本 AIR 根据原始域在安全沙箱中执行所有代码。应用程序内容限制为从应用程序安装目录加载的内容,该内容放置到应用程序 沙 箱中。只有在此沙箱中运行的 HTML 和 JavaScript 才能访问运行时环境和 AIR API。同时,在页 load 事件的所有处理函数返 回之后,将在应用程序沙箱中阻止 JavaScript 的大多数动态计算和执行操作。 通过将应用程序页加载到 frame 或 iframe 中,并对 frame 设置特定于 AIR 的 sandboxRoot 和 documentRoot 属性,可以将该 应用程序页映射到非应用程序沙箱中。通过将 sandboxRoot 值设置为实际远程域,您可以使沙箱中的内容跨脚本访问该域中的 内容。当加载远程内容或撰写远程内容脚本时(例如,在 mash-up 应用程序中),使用上述方法映射页非常有用。 允许应用程序和非应用程序内容相互跨脚本访问的另一方法是创建沙箱桥,这也是向 AIR API 授予非应用程序内容访问权限 的唯一方法。使用父级到子级 桥,子 frame、 iframe 或窗口中的内容能够访问在应用程序沙箱中定义的指定方法和属性。反 之,使用子级到父级 桥,应用程序内容能够访问在子级的沙箱中定义的指定方法和属性。通过设置窗口对象的 parentSandboxBridge 和 childSandboxBridge 属性可以建立沙箱桥。有关详细信息,请参阅 第 63 页的 “Adobe AIR 中的 HTML 安全性 ” 以及 第 10 页的 “HTML frame 和 iframe 元素 ”。 关于插件和嵌入对象 Adobe AIR 1.0 和更高版本 AIR 支持 Adobe® Acrobat® 插件。用户必须安装有 Acrobat 或 Adobe® Reader® 8.1 (或更高版本)才能显示 PDF 内容。 HTMLLoader 对象提供了用于查看用户系统是否可以显示 PDF 的属性。 SWF 文件内容也可以在 HTML 环境中显示,但 AIR 中构建有此功能,因此无需使用外部插件。 AIR 中不支持任何其他 WebKit 插件。 更多帮助主题 第 63 页的 “Adobe AIR 中的 HTML 安全性 ” 第 4 页的 “HTML 沙箱 ” 第 10 页的 “HTML frame 和 iframe 元素 ” 第 8 页的 “JavaScript Window 对象 ” 第 5 页的 “XMLHttpRequest 对象 ” 第 231 页的 “ 在 AIR 中添加 PDF 内容 ”4ADOBE AIR HTML 开发人员指南 关于 HTML 环境 上次更新 2011/10/13 AIR 和 WebKit Adobe AIR 1.0 和更高版本 Adobe AIR 中使用开放源代码 WebKit 引擎,该引擎也用于 Safari Web 浏览器。 AIR 添加了若干扩展功能,以便允许访问 运行时类和对象,并增强了安全性。此外, WebKit 自身还针对 HTML、CSS 和 JavaScript 添加了 W3C 标准中不包括的功 能。 此处仅包含 AIR 新增功能和最显著的 WebKit 扩展功能;有关非标准 HTML、 CSS 和 JavaScript 的其他文档,请参阅 www.webkit.org 和 developer.apple.com。有关标准信息,请参阅 W3C 网站。 Mozilla 还提供了有关 HTML、 CSS 和 DOM 主题的重要一般参考 (当然, WebKit 引擎不同于 Mozilla 引擎)。 AIR 中的 JavaScript Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 AIR 对通用 JavaScript 对象的典型行为进行了若干更改。其中,很多更改都是为了在 AIR 中更方便地编写安全应用程序。同 时,这些行为差异表示某些通用 JavaScript 编码模式和使用这些模式的现有 Web 应用程序在 AIR 中可能始终不会按预期方式 执行。有关更正这些问题类型的信息,请参阅第 20 页的 “ 避免与安全相关的 JavaScript 错误 ”。 HTML 沙箱 Adobe AIR 1.0 和更高版本 AIR 根据内容的原始位置将该内容放置到隔离沙箱中。沙箱规则与大多数 Web 浏览器实现的具有相同原始位置的策略一致, 并且与 Adobe Flash Player 实现的沙箱规则一致。此外, AIR 还提供了一个包含并保护应用程序内容的新应用程序 沙箱类 型。有关在开发 AIR 应用程序时可能遇到的沙箱类型的详细信息,请参阅安全性沙箱。 只有在应用程序沙箱中运行的 HTML 和 JavaScript 才能访问运行时环境和 AIR API。但同时,出于安全原因,动态计算和执 行各种形式的 JavaScript 在应用程序沙箱内大幅受限。无论您的应用程序实际上是否从服务器直接加载信息,这些限制都将发 挥作用。(即使是文件内容、粘贴的字符串和直接用户输入也可能不可靠。) 页内容的原始位置确定要将该内容放置到哪个沙箱。只能将从应用程序目录( app: URL 方案引用的安装目录)加载的内容放 置到应用程序沙箱中。从文件系统加载的内容则放置到与本地文件系统内容交互的 沙箱或受信任的本地 沙箱中,以便访问本地 文件系统上的内容(而不是远程内容),并与其进行交互。从网络加载的内容则放置到与其原始域对应的远程沙箱中。 若要使应用程序页与远程沙箱中的内容自由交互,则可以将该页映射到远程内容所在的相同域中。例如,如果编写显示 Internet 服务的映射数据的应用程序,则可以将加载和显示该服务内容的应用程序页映射到该服务域中。用于将页映射到远程 沙箱和域的属性是 frame 和 iframe HTML 元素的新增属性。 若要使非应用程序沙箱中的内容安全地使用 AIR 功能,则可以设置父沙箱桥。若要使应用程序内容安全地调用其他沙箱中的内 容的方法并访问其属性,则可以设置子沙箱桥。此处所述的安全性意味着远程内容不能意外获取对未明确公开的对象、属性或 方法的引用。通过沙箱桥只能传递简单数据类型、函数和匿名对象。但是,您仍然必须避免明确公开潜在的危险函数。例如, 如果公开的接口允许远程内容读取或写入用户系统中任意位置的文件,则可能会使远程内容严重危害用户。 JavaScript eval() 函数 Adobe AIR 1.0 和更高版本 完成加载页之后,将在应用程序沙箱中限制使用 eval() 函数。在某些情况下允许使用该函数,以便可以安全地分析 JSON 格式 数据,但是,生成可执行语句的任何计算将生成错误。第 65 页的 “ 对不同沙箱中的内容的代码限制 ” 介绍了允许使用 eval() 函 数的情况。 5ADOBE AIR HTML 开发人员指南 关于 HTML 环境 上次更新 2011/10/13 函数构造函数 Adobe AIR 1.0 和更高版本 在应用程序沙箱中,可以在完成加载页之前使用函数构造函数。在所有页 load 事件处理函数完成之后,无法创建新的函数。 加载外部脚本 Adobe AIR 1.0 和更高版本 应用程序沙箱中的 HTML 页无法使用 script 标签从应用程序目录外部加载 JavaScript 文件。为使应用程序中的页能够从应用 程序目录外部加载脚本,必须将该页映射到非应用程序沙箱。 XMLHttpRequest 对象 Adobe AIR 1.0 和更高版本 AIR 提供了应用程序可用于执行数据请求的 XMLHttpRequest (XHR) 对象。下面的示例演示简单数据请求: xmlhttp = new XMLHttpRequest(); xmlhttp.open("GET", "http:/www.example.com/file.data", true); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { //do something with data... } } xmlhttp.send(null); 与浏览器不同,AIR 允许在应用程序沙箱中运行的内容请求任何域中的数据。对于包含 JSON 字符串的 XHR 结果,除非该结 果还包含可执行代码,否则可以计算出该结果的数据对象。如果 XHR 结果中存在可执行语句,则会引发错误,且计算尝试失 败。 若要防止从远程源意外注入代码,在完成加载页之前执行同步 XHR 时将返回空结果。异步 XHR 将始终在加载页之后返回。 默认情况下, AIR 阻止在非应用程序沙箱中执行跨域 XMLHttpRequest。应用程序沙箱中的父窗口可以选择在包含非应用程 序沙箱内容的子 frame 中允许跨域请求,方法是在包含非应用程序沙箱内容的 frame 或 iframe 元素中将 AIR 添加的 allowCrossDomainXHR 属性设置为 true: 由于 sandboxRoot 属性重新映射 www.example.com 地址的根 URL,因此所有请求都将从应用程序目录加载,而不是从远程 服务器加载。无论请求是派生自页导航还是 XMLHttpRequest,都将重新映射这些请求。6ADOBE AIR HTML 开发人员指南 关于 HTML 环境 上次更新 2011/10/13 若要避免意外阻止对远程服务器的数据请求,请将 sandboxRoot 映射到远程 URL 的子目录,而不是根目录。该目录不一定存 在。例如,若要允许从远程服务器加载对 www.example.com 的请求,而不是从应用程序目录加载,请将上面的 iframe 更改 为以下内容: ui.html 页可以使用以下脚本标签从本地的 sandbox 文件夹加载 javascript 文件: 它还可以使用以下脚本标签从远程服务器的目录加载内容: sandboxRoot URL 将遮盖远程服务器上位于相同 URL 中的所有内容。在上例中,您不能访问位于 www.example.com/local/ (或其子目录中)中的任何远程内容,因为 AIR 会将请求重新映射到本地应用程序目录:无论是页面导航、 XMLHttpRequest 还是采用其他内容加载手段所派生的请求,都会重新映射。 设置沙箱桥接口 Adobe AIR 1.0 和更高版本 如果应用程序沙箱中的内容必须访问非应用程序沙箱中的内容所定义的属性或方法,或者如果非应用程序内容必须访问应用程 序沙箱中的内容所定义的属性或方法,则可以使用沙箱桥。使用任何子级文档的 window 对象的 childSandboxBridge 和 parentSandboxBridge 属性可创建沙箱桥。 建立子级沙箱桥 Adobe AIR 1.0 和更高版本 childSandboxBridge 属性允许子级文档向父级文档中的内容公开接口。若要公开接口,需将 childSandbox 属性设置为子级文档 中的函数或对象。然后,可以从父级文档中的内容访问该对象或函数。以下示例显示了子级文档中运行的脚本如何向其父级文 档公开包含函数和属性的对象: var interface = {}; interface.calculatePrice = function(){ return ".45 cents"; } interface.storeID = "abc" window.childSandboxBridge = interface; 如果此子级内容加载到 iframe (分配的 ID 为 “child”),则可以通过读取 frame 的 childSandboxBridge 属性从父级内容来访 问接口: var childInterface = document.getElementById("child").contentWindow.childSandboxBridge; air.trace(childInterface.calculatePrice()); //traces ".45 cents" air.trace(childInterface.storeID)); //traces "abc"32ADOBE AIR HTML 开发人员指南 在 AIR 中进行 HTML 和 JavaScript 编程 上次更新 2011/10/13 建立父级沙箱桥 Adobe AIR 1.0 和更高版本 parentSandboxBridge 属性允许父级文档向子级文档中的内容公开接口。若要公开接口,父级文档需将子级文档的 parentSandbox 属性设置为父级文档中定义的函数或对象。然后,可以从子级文档中的内容访问该对象或函数。以下示例显示 了父级 frame 中运行的脚本如何向其子级文档公开包含函数的对象: var interface = {}; interface.save = function(text){ var saveFile = air.File("app-storage:/save.txt"); //write text to file } document.getElementById("child").contentWindow.parentSandboxBridge = interface; 使用此接口,子级 frame 中的内容可以将文本保存到名为 save.txt 的文件,但对文件系统不具备任何其他访问权利。子级内容 可以调用 save 函数,如下所示: var textToSave = "A string."; window.parentSandboxBridge.save(textToSave); 应用程序内容向其他沙箱公开的接口应越窄越好。应考虑到非应用程序内容本身并不可靠,因为它可能遭到意外或恶意代码注 入。必须采取适当的防护措施,以防止误用通过父级沙箱桥公开的接口。 在页面加载过程中访问父级沙箱桥 Adobe AIR 1.0 和更高版本 为了使子级文档中的脚本能够访问父级沙箱桥,必须先设置沙箱桥,然后才能运行脚本。创建新页 DOM 之后,在分析任何脚 本或添加 DOM 元素之前,Window、frame 和 iframe 对象将调度 dominitialize 事件。可以使用 dominitialize 事件按照适当 的页面构造顺序尽早建立沙箱桥,以便页面中定义的所有脚本均能访问该沙箱桥。 以下示例说明如何创建父级沙箱桥,以响应从子级 frame 调度的 dominitialize 事件: 属性 说明 sandboxRoot 用于确定在其中放置 frame 内容的沙箱和域的 URL。必须使用 file:、 http: 或 https: URL 方案。 documentRoot 从中加载 frame 内容的 URL。必须使用 file:、 app: 或 app-storage: URL 方案。65ADOBE AIR HTML 开发人员指南 AIR 安全性 上次更新 2011/10/13 在不同沙箱或域的父级和子级 frame 之间设置桥 Adobe AIR 1.0 和更高版本 AIR 将 childSandboxBridge 和 parentSandboxBridge 属性添加到任何子级 frame 的 window 对象中。使用这些属性,您可以定 义用作父级和子级 frame 之间的接口的桥。每个桥都指向一个方向: childSandboxBridge — childSandboxBridge 属性允许子级 frame 向父级 frame 中的内容公开接口。若要公开接口,需将 childSandbox 属性设置为子级 frame 中的函数或对象。然后,可以从父级 frame 中的内容访问该对象或函数。以下示例显示了 子级 frame 中运行的脚本如何向其父级 frame 公开包含函数和属性的对象: var interface = {}; interface.calculatePrice = function(){ return .45 + 1.20; } interface.storeID = "abc" window.childSandboxBridge = interface; 如果此子级内容位于分配的 ID 为 "child" 的 iframe 中,则可以通过读取 frame 的 childSandboxBridge 属性从父级内容来访问 接口: var childInterface = document.getElementById("child").childSandboxBridge; air.trace(childInterface.calculatePrice()); //traces "1.65" air.trace(childInterface.storeID)); //traces "abc" parentSandboxBridge — parentSandboxBridge 属性允许父级 frame 向子级 frame 中的内容公开接口。若要公开接口,需将子级 frame 的 parentSandbox 属性设置为父级 frame 中的函数或对象。然后,可以从子级 frame 中的内容访问该对象或函数。以下 示例显示了父级 frame 中运行的脚本如何向其子级 frame 公开包含 save 函数的对象: var interface = {}; interface.save = function(text){ var saveFile = air.File("app-storage:/save.txt"); //write text to file } document.getElementById("child").parentSandboxBridge = interface; 使用此接口,子级 frame 中的内容可以将文本保存到名为 save.txt 的文件。但对文件系统不具备任何其他访问权限。通常,应 用程序内容向其他沙箱公开的接口应越窄越好。子级内容可以调用 save 函数,如下所示: var textToSave = "A string."; window.parentSandboxBridge.save(textToSave); 如果子级内容尝试设置 parentSandboxBridge 对象的属性,则运行时会引发 SecurityError 异常。如果父级内容尝试设置 childSandboxBridge 对象的属性,则运行时会引发 SecurityError 异常。 对不同沙箱中的内容的代码限制 Adobe AIR 1.0 和更高版本 在 第 63 页的 “Adobe AIR 中的 HTML 安全性 ” 主题的简介中已介绍过,运行时强制执行规则,并提供克服 HTML 和 JavaScript 中可能的安全漏洞的机制。本主题列出了这些限制。如果代码尝试调用这些受限制的 API,则运行时将发出错 误:“Adobe AIR runtime security violation for JavaScript code in the application security sandbox”(应用程序安全沙 箱中存在针对 JavaScript 代码的 Adobe AIR 运行时安全侵犯)。 有关详细信息,请参阅第 20 页的 “ 避免与安全相关的 JavaScript 错误 ”。66ADOBE AIR HTML 开发人员指南 AIR 安全性 上次更新 2011/10/13 使用 JavaScript eval() 函数及类似技术的限制 Adobe AIR 1.0 和更高版本 对于应用程序安全沙箱中的 HTML 内容,加载代码后(即在调度 body 元素的 onload 事件以及 onload 处理函数完成执行 后),使用可将字符串动态转换为可执行代码的 API 时存在一些限制。这是为了阻止应用程序从非应用程序源(例如潜在不安 全网络域)意外插入(及执行)代码。 例如,如果应用程序使用远程源中的字符串数据来写入 DOM 元素的 innerHTML 属性,则字符串中包括的可执行 (JavaScript) 代码可能会执行不安全操作。但是,在加载内容时将远程字符串插入 DOM 不存在风险。 使用 JavaScript eval() 函数时存在一个限制。在加载应用程序沙箱中的代码且处理 onload 事件处理函数之后,只能通过有限 的方式使用 eval() 函数。以下规则适用于在从应用程序安全沙箱中加载代码之后 使用 eval() 函数: • 允许表达式中包含文本。例如: eval("null"); eval("3 + .14"); eval("'foo'"); • 允许使用对象文本,如下所示: { prop1: val1, prop2: val2 } • 禁止 使用 setter/getter 对象文本,如下所示: { get prop1() { ... }, set prop1(v) { ... } } • 允许使用数组文本,如下所示: [ val1, val2, val3 ] • 禁止 表达式中包含属性读取,如下所示: a.b.c • 禁止 调用函数。 • 禁止 禁止对函数进行定义。 • 禁止 设置任何属性。 • 禁止 使用函数文本。 但是,加载代码时,在 onload 事件之前和执行 onload 事件处理函数过程中,这些限制不适用于应用程序安全沙箱中的内容。 例如,加载代码后,以下代码会导致运行时引发异常: eval("alert(44)"); eval("myFunction(44)"); eval("NativeApplication.applicationID"); 如果应用程序沙箱中允许使用代码,则动态生成的代码(例如在调用 eval() 函数时生成的代码)将导致安全风险。例如,应用 程序可能意外执行了从网络域中加载的字符串,而该字符串可能包含恶意代码。例如,这些代码可能会删除或修改用户计算机 上的文件。也可能会将本地文件的内容报告给某个不受信任的网络域。 生成动态代码的方式如下所示: • 调用 eval() 函数。 • 使用 innerHTML 属性或 DOM 函数插入加载应用程序目录外部的脚本的 script 标签。 • 使用 innerHTML 属性或 DOM 函数插入具有内联代码的 script 标签(而不是通过 src 属性加载脚本)。 • 设置 script 标签的 src 属性可以加载应用程序目录外部的 JavaScript 文件。 • 使用 javascript URL 方案(如 href="javascript:alert('Test')" 所示)。67ADOBE AIR HTML 开发人员指南 AIR 安全性 上次更新 2011/10/13 • 使用 setInterval() 或 setTimout() 函数,其中,第一个参数(用于定义要异步运行的函数)为要求值的字符串而不是函数名 (如 setTimeout('x = 4', 1000) 所示)。 • 调用 document.write() 或 document.writeln()。 加载内容时,应用程序安全沙箱中的代码只能使用这些方法。 这些限制不会 阻止将 eval() 和 JSON 对象文本一起使用。这样便可以在 JSON JavaScript 库中使用应用程序内容。但是会限制 您使用重载的 JSON 代码(通过事件处理函数)。 对于其他 Ajax 框架和 JavaScript 代码库,需检查框架或库中的代码是否在限制动态生成的代码时起作用。如果不起作用,则 需包括在非应用程序安全沙箱中使用框架或库的所有内容。有关详细信息,请参阅 AIR 中的 JavaScript 限制和第 70 页的 “ 通 过脚本访问应用程序和非应用程序内容 ”。 Adobe 维护一个已知的支持应用程序安全沙箱的 Ajax 框架列表,其网址为 http://www.adobe.com/cn/products/air/develop/ajax/features/。 与应用程序安全沙箱中的内容不同,非应用程序安全沙箱中的 JavaScript 内容随时都可以 调用 eval() 函数来执行动态生成的代 码。 访问 AIR API 的限制(针对非应用程序沙箱) Adobe AIR 1.0 和更高版本 非应用程序沙箱中的 JavaScript 代码无法访问 window.runtime 对象,也无法执行 AIR API。如果非应用程序安全沙箱中的内 容调用以下代码,则应用程序会引发 TypeError 异常: try { window.runtime.flash.system.NativeApplication.nativeApplication.exit(); } catch (e) { alert(e); } 异常类型为 TypeError (未定义的值),由于非应用程序沙箱中的内容无法识别 window.runtime 对象,因此将其认为是未定 义的值。 可以使用脚本桥将运行时功能公开给非应用程序沙箱中的内容。有关详细信息,请参阅第 70 页的 “ 通过脚本访问应用程序和 非应用程序内容 ”。 使用 XMLHttpRequest 调用的限制 Adobe AIR 1.0 和更高版本 应用程序安全沙箱中的 HTML 内容无法使用同步 XMLHttpRequest 方法,在加载 HTML 内容和执行 onLoad 事件期间从应 用程序沙箱外部加载数据。 默认情况下,不允许非应用程序安全沙箱中的 HTML 内容使用 JavaScript XMLHttpRequest 对象从非调用请求的域加载数 据。 frame 或 iframe 标签可以包括 allowcrosscomainxhr 属性。如果将此属性设置为任何非空值,则会允许帧或 iframe 中的内 容使用 JavaScript XMLHttpRequest 对象从域(注意不是调用请求的代码的域)加载数据: 有关详细信息,请参阅第 68 页的 “ 通过脚本访问不同域中的内容 ”。68ADOBE AIR HTML 开发人员指南 AIR 安全性 上次更新 2011/10/13 加载 CSS、 frame、 iframe 和 img 元素的限制(针对非应用程序沙箱中的内容) Adobe AIR 1.0 和更高版本 远程(网络)安全沙箱中的 HTML 内容只能从远程沙箱(网络 URL)加载 CSS、 frame、 iframe 和 img 内容。 只能与本地文件系统内容交互的沙箱、只能与远程内容交互的沙箱或受信任的本地沙箱中的 HTML 内容只能从本地沙箱(而 不是应用程序或远程沙箱)加载 CSS、 frame、 iframe 和 img 内容。 调用 JavaScript window.open() 方法的限制 Adobe AIR 1.0 和更高版本 如果通过调用 JavaScript window.open() 方法创建的窗口中显示了非应用程序安全沙箱中的内容,则窗口的标题将以主(启 动)窗口的标题开头,后跟一个冒号字符。无法使用代码将窗口的标题部分从屏幕上删除。 非应用程序安全沙箱中的内容只能成功调用 JavaScript window.open() 方法来响应用户与鼠标或键盘交互而触发的事件。这会 阻止非应用程序内容创建可能被欺骗使用的窗口(例如用于仿冒攻击)。此外,鼠标或键盘事件的事件处理函数无法将 window.open() 方法设置为在延迟(例如调用 setTimeout() 函数)后执行。 远程(网络)沙箱中的内容只能使用 window.open() 方法打开远程网络沙箱中的内容。无法使用 window.open() 方法打开应用 程序或本地沙箱中的内容。 只能与本地文件系统内容交互的沙箱、只能与远程内容交互的沙箱或受信任的本地沙箱中的内容(请参阅安全沙箱)只可使用 window.open() 方法打开本地沙箱中的内容。无法使用 window.open() 打开应用程序或远程沙箱中的内容。 调用受限代码时出现的错误 Adobe AIR 1.0 和更高版本 如果由于这些安全限制而限制在沙箱中使用所调用的代码,则运行时将发出 JavaScript 错误: “Adobe AIR runtime security violation for JavaScript code in the application security sandbox” (应用程序安全沙箱中存在针对 JavaScript 代码的 Adobe AIR 运行时安全侵犯)。 有关详细信息,请参阅第 20 页的 “ 避免与安全相关的 JavaScript 错误 ”。 从字符串中加载 HTML 内容时对沙箱的保护 Adobe AIR 1.0 和更高版本 通过 HTMLLoader 类的 loadString() 方法,可以在运行时创建 HTML 内容。但是,如果从不安全的 Internet 来源加载数 据,则用作 HTML 内容的数据可能已损坏。由于此原因,默认情况下,使用 loadString() 方法创建的 HTML 不放置在应用程 序沙箱中,并且无权访问 AIR API。但是,将 HTMLLoader 对象的 placeLoadStringContentInApplicationSandbox 属性设置 为 true,即可将使用 loadString() 方法创建的 HTML 放置在应用程序沙箱中。有关详细信息,请参阅从字符串加载 HTML 内 容。 通过脚本访问不同域中的内容 Adobe AIR 1.0 和更高版本 AIR 应用程序在安装时会被授予特殊权限。不要将相同权限泄露给其他内容(包括不属于应用程序的远程文件和本地文件), 这一点很重要。69ADOBE AIR HTML 开发人员指南 AIR 安全性 上次更新 2011/10/13 关于 AIR 沙箱桥 Adobe AIR 1.0 和更高版本 通常,一个域中的内容无法调用其他域中的脚本。 但是仍存在这样一些情况:主 AIR 应用程序要求远程域中的内容对主 AIR 应用程序中的脚本具有受控访问权限,反之亦然。 为此,运行时提供了沙箱桥机制,沙箱桥充当两个沙箱之间的通道。沙箱桥可以在远程安全沙箱和应用程序安全沙箱之间提供 显式交互。 沙箱桥公开了以下两个对象,已加载和要加载的脚本都可以访问这两个对象: • parentSandboxBridge 对象允许要加载的内容将属性和函数公开给已加载的内容中的脚本。 • childSandboxBridge 对象允许已加载的内容将属性和函数公开给要加载的内容中的脚本。 通过沙箱桥公开的对象按值而不是按引用进行传递。所有数据都会序列化。这意味着由桥的一端公开的对象无法由另一端设 置,并且公开的对象为无类型对象。此外,只能公开简单对象和函数;不能公开复杂对象。 如果子级内容尝试设置 parentSandboxBridge 对象的属性,则运行时会引发 SecurityError 异常。同样,如果父级内容尝试 设置 childSandboxBridge 对象的属性,则运行时也会引发 SecurityError 异常。 沙箱桥示例 (HTML) Adobe AIR 1.0 和更高版本 在 HTML 内容中,会将 parentSandboxBridge 和 childSandboxBridge 属性添加到子级文档的 JavaScript window 对象中。有 关如何在 HTML 内容中设置桥函数的示例,请参阅第 31 页的 “ 设置沙箱桥接口 ”。 限制 API 公开 Adobe AIR 1.0 和更高版本 公开沙箱桥时,公开限制沙箱桥滥用程度的高级别 API 非常重要。请注意,调用桥实施的内容可能会被破坏(例如,通过插 入代码)。因此 (举例来说),通过桥公开 readFile(path) 方法(读取任意文件的内容)易于受到滥用。最好公开未使用路径且 读取特定文件的 readApplicationSetting() API。一旦应用程序部分受到损坏,语义方法越多,就越能限制应用程序产生的破 坏。 更多帮助主题 第 30 页的 “ 跨脚本访问不同安全沙箱中的内容 ” 写入磁盘 Adobe AIR 1.0 和更高版本 在 Web 浏览器中运行的应用程序只能与用户的本地文件系统进行有限的交互。 Web 浏览器会实施安全策略,用于确保用户的 计算机不会由于加载 Web 内容而被破坏。例如,通过 Flash Player 在浏览器中运行的 SWF 文件无法直接与用户计算机中的文 件进行交互。可以将共享对象和 Cookie 写入用户的计算机,以便维护用户首选项和其他数据,但文件系统交互将受到此限 制。由于 AIR 应用程序安装在本地,因此它们具有不同的安全协议,其中包括在本地文件系统间进行读取和写入的功能。 这一灵活性要求开发人员担负较高的责任。意外的应用程序不安全因素不仅会危害应用程序的功能,而且会危害用户计算机的 完整性。为此,开发人员应阅读第 71 页的 “ 开发人员的最佳安全做法 ”。70ADOBE AIR HTML 开发人员指南 AIR 安全性 上次更新 2011/10/13 AIR 开发人员可以使用多个 URL 方案协议来访问文件并将文件写入本地文件系统: 注: AIR 应用程序无法使用 app: URL 方案修改内容。此外,由于管理员设置,只可以读取应用程序目录。 除非用户计算机存在管理员限制,否则 AIR 应用程序有权写入用户硬盘上的任意位置。建议开发人员使用 app-storage:/ 路径作 为与其应用程序相关的本地存储。从应用程序写入 app-storage:/ 的文件将放在标准位置中: • 在 Mac OS 中:应用程序的存储目录为 //Local Store/,其中 表示用户的首选文件夹。通常为 /Users//Library/Preferences • 在 Windows 中:应用程序的存储目录为 \\Local Store\,其中 表示用户的 CSIDL_APPDATA 特殊文件夹。通常为 C:\Documents and Settings\\Application Data • 在 Linux 中为 //Local Store/,其中 为 /home//.appdata 如果应用程序设计用于与用户文件系统中的现有文件进行交互,请确保阅读第 71 页的 “ 开发人员的最佳安全做法 ”。 安全使用不受信任的内容 Adobe AIR 1.0 和更高版本 未分配给应用程序沙箱的内容可以为应用程序提供其他脚本功能,但前提是满足运行时的安全条件。本主题介绍 AIR 安全协议 以及非应用程序内容。 通过脚本访问应用程序和非应用程序内容 Adobe AIR 1.0 和更高版本 通过脚本访问应用程序和非应用程序内容的 AIR 应用程序具有更复杂的安全安排。只允许不在应用程序沙箱中的文件使用沙箱 桥来访问应用程序沙箱中的文件的属性和方法。沙箱桥充当应用程序内容与非应用程序内容之间的通道,在两个文件之间提供 显式交互。如果使用正确,沙箱桥会提供额外的安全层,从而限制非应用程序内容访问属于应用程序内容的对象引用。 通过示例可以更好地说明沙箱桥的优点。假设 AIR 音乐商店应用程序需要为希望创建自己的 SWF 文件的广告商提供 API,商 店应用程序可以使用这些文件进行通信。该商店需要为广告商提供在商店中查找艺术家和光盘的方法,另外出于安全原因,还 需要将某些方法和属性与第三方 SWF 文件进行隔离。 沙箱桥可以提供此功能。默认情况下,在运行时从外部加载到 AIR 应用程序的内容无法访问主应用程序中的任何方法或属性。 通过自定义沙箱桥,开发人员可以在不公开这些方法或属性的情况下为远程内容提供服务。将沙箱桥视为受信任内容和不受信 任内容之间的通道,在加载方和被加载方内容之间提供通信而不公开对象引用。 有关如何安全使用沙箱桥的详细信息,请参阅第 68 页的 “ 通过脚本访问不同域中的内容 ”。 URL 方案 说明 app:/ 应用程序目录的别名。从此路径访问的文件被分配到应用程序沙箱中,并由运行时授予完全权限。 app-storage:/ 本地存储目录的别名,由运行时进行标准化。从此路径访问的文件被分配到非应用程序沙箱中。 file:/// 表示用户硬盘的根目录的别名。如果从此路径访问的文件位于应用程序目录中,则该文件会被分配到应用程序沙箱中,否 则将被分配到非应用程序沙箱中。71ADOBE AIR HTML 开发人员指南 AIR 安全性 上次更新 2011/10/13 开发人员的最佳安全做法 Adobe AIR 1.0 和更高版本 虽然 AIR 应用程序是使用 Web 技术构建的,但开发人员应知道这些应用程序并非在浏览器安全沙箱中运行,这一点很重要。 这意味着,可以构建会对本地系统有意或无意产生损害的 AIR 应用程序。AIR 会尝试最大程度降低此风险,但仍存在一些可能 引入漏洞的方式。本主题介绍了重要的潜在不安全因素。 将文件导入应用程序安全沙箱的风险 Adobe AIR 1.0 和更高版本 位于应用程序目录中的文件会被分配到应用程序沙箱中,并具有运行时的完全权限。建议将写入本地文件系统的应用程序写入 app-storage:/ 中。此目录与用户计算机上的应用程序文件位于不同的位置,因此这些文件不会分配到应用程序沙箱中,并且安 全风险的程度会降低。建议开发人员考虑以下问题: • 仅在必要时才在 AIR 文件(位于安装的应用程序中)中包含文件。 • 仅在脚本文件的行为被完全理解和信任时才在 AIR 文件(位于安装的应用程序中)中包含该脚本文件。 • 不要向应用程序目录中写入内容或修改其中的内容。运行时会阻止应用程序通过引发 SecurityError 异常,写入或修改使用 app:/ URL 方案的文件和目录。 • 不要将网络源中的数据用作可能引起代码异常的 AIR API 的方法的参数。其中包括使用 Loader.loadBytes() 方法和 JavaScript eval() 函数。 使用外部源确定路径的风险 Adobe AIR 1.0 和更高版本 使用外部数据或内容可能会破坏 AIR 应用程序。因此,使用网络或文件系统中的数据时应特别小心。信任最终由开发人员及其 构建的网络连接进行保障,但加载外部数据本身就具有风险,不应在敏感操作中使用此输入。建议开发人员不要执行以下操 作: • 使用网络源中的数据确定文件名 • 使用网络源中的数据构建应用程序用来发送私人信息的 URL 使用、存储或传输不安全凭据的风险 Adobe AIR 1.0 和更高版本 将用户凭据存储在用户的本地文件系统中将引入可能破坏这些凭据的风险。建议开发人员考虑以下问题: • 如果凭据必须存储在本地,请在写入本地文件系统时对凭据进行加密。运行时通过 EncryptedLocalStore 类提供了对每个 安装的应用程序都唯一的加密存储。有关详细信息,请参阅第 218 页的 “ 加密的本地存储区 ”。 • 除非网络源可信并且使用 HTTPS: 或传输层安全 (TLS) 协议进行传输,否则不要将未加密的用户凭据传输到网络源。 • 永远不要在创建凭据时指定默认密码,应让用户自己创建密码。保留默认值不变的用户将其凭据暴露在已了解默认密码的攻 击者面前。72ADOBE AIR HTML 开发人员指南 AIR 安全性 上次更新 2011/10/13 降级攻击的风险 Adobe AIR 1.0 和更高版本 在安装应用程序过程中,运行时会检查以确保应用程序的版本不是当前安装的版本。如果应用程序已经安装,则运行时会比较 版本字符串与已安装的版本。如果此字符串不同,则用户可以选择升级安装。运行时不保证新安装的版本比旧版本新,仅保证 版本不同。攻击者可能会向用户分发旧版本以避开安全漏洞。因此,建议开发人员在运行应用程序时检查版本。最好让应用程 序检查网络中是否存在所需更新。这样,即使攻击者让用户运行旧版本,该旧版本也会识别出需要更新。此外,为应用程序使 用明确的版本控制方案将使欺骗用户安装降级版本变得更加困难。 代码签名 Adobe AIR 1.0 和更高版本 所有 AIR 安装程序文件都需要进行代码签名。代码签名是一种加密过程,用于确认指定的软件源是否正确。可使用由外部证书 颁发机构 (CA) 颁发的证书或您自己创建的自签名证书对 AIR 应用程序进行签名。强烈建议从已知的 CA 获得商业证书,这样 的证书可以保证用户安装的是您提供的应用程序,而不是赝品。但是,可以使用 SDK 中的 adt 或者使用 Flash、Flash Builder 或使用 adt 生成证书的其他应用程序来创建自签名的证书。自签名证书不保证安装的应用程序为正版,它只能用于测试即将公 开发行的应用程序。73 上次更新 2011/10/13 第 7 章 : 使用 AIR 本机窗口 Adobe AIR 1.0 和更高版本 使用 Adobe® AIR® 本机窗口 API 提供的类可创建和管理桌面窗口。 AIR 中的本机窗口的基础知识 Adobe AIR 1.0 和更高版本 有关在 AIR 中使用本机窗口的快速介绍和代码示例,请参阅 Adobe Developer Connection 中的以下快速入门文章: • 自定义窗口的外观 AIR 提供易于使用的跨平台窗口 API,以便使用 Flash®、 Flex™ 和 HTML 编程技术创建本机操作系统窗口。 使用 AIR 可使您在开发应用程序的外观时具有广泛的自由度。您创建的窗口可以类似于标准的桌面应用程序,也就是在 Mac 上运行时与 Apple 风格相媲美、在 Windows 上运行时符合 Microsoft 惯例以及在 Linux 上与窗口管理器协调一致,所有这些 的实现都不需要撰写平台专用的代码。此外,无论应用程序运行于何处,都可以使用 Flex 框架提供的可设置外观、可扩展的镶 边树立您自己的风格。由于完全支持针对桌面进行透明度和 Alpha 混合,因此甚至可以用矢量图和位图绘制您自己的窗口镶 边。是否厌倦了矩形窗口?现在可以绘制圆形窗口。 AIR 中的窗口 Adobe AIR 1.0 和更高版本 AIR 支持三个不同的 API 来处理窗口: • 面向 ActionScript 的 NativeWindow 类提供最底层的窗口 API。在使用 ActionScript 和 Flash Professional 创作的应 用程序中使用 NativeWindow。考虑扩展 NativeWindow 类,以使应用程序中使用的窗口专用化。 • 在 HTML 环境中,可以使用 JavaScript Window 类,就像在基于浏览器的 Web 应用程序中的那样。对 JavaScript Window 方法的调用将转移到基础本机窗口对象。 • Flex 框架 mx:WindowedApplication 和 mx:Window 类为 NativeWindow 类提供 Flex“ 包装 ”。用 Flex 创建 AIR 应 用程序时,WindowedApplication 组件将代替 Application 组件,并且必须始终使用前者作为您的 Flex 应用程序的初始 窗口。 ActionScript 窗口 使用 NativeWindow 类创建窗口时,会直接使用 Flash Player 舞台并显示列表。若要向 NativeWindow 添加视觉对象,请 将该对象添加到窗口舞台的显示列表或添加到舞台上的另一个显示对象容器。 HTML 窗口 在创建 HTML 窗口时,可使用 HTML、 CSS 和 JavaScript 来显示内容。若要向 HTML 窗口添加可视对象,请将该内容添 加到 HTML DOM。HTML 窗口是一种特殊类别的 NativeWindow。AIR 主机定义 HTML 窗口中的 nativeWindow 属性, 该属性提供对基础 NativeWindow 实例的访问。使用此属性可以访问此处所述的 NativeWindow 属性、方法和事件。 注: JavaScript Window 对象还具有用于脚本访问包含窗口的方法,例如 moveTo() 和 close()。如果多个方法均可用,您可以 使用其中简便易用的方法。74ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 Flex Framework 窗口 Flex Framework 定义其自己的窗口组件。 mx:WindowedApplication 和 mx:Window 组件无法在框架外部使用,因此无 法在基于 HTML 的 AIR 应用程序中使用。 初始应用程序窗口 应用程序的第一个窗口是由 AIR 自动为您创建的。AIR 使用应用程序描述符文件的 initialWindow 元素中指定的参数设置该窗 口的属性和内容。 如果根内容是 SWF 文件,则 AIR 将创建 NativeWindow 实例,加载 SWF 文件并将其添加到窗口舞台。如果根内容是 HTML 文件,则 AIR 将创建 HTML 窗口并加载 HTML。 本机窗口类 Adobe AIR 1.0 和更高版本 本机窗口 API 包含以下类: 本机窗口事件流 Adobe AIR 1.0 和更高版本 本机窗口调度事件,以便通知感兴趣的组件将要发生或已发生重要更改。对于许多与窗口相关的事件的调度是成对进行的。第 一个事件警告即将发生更改。第二个事件通知已完成更改。可以取消警告事件,但不能取消通知事件。以下序列说明在用户单 击窗口的最大化按钮后发生的事件流: 1 NativeWindow 对象调度 displayStateChanging 事件。 2 如果已注册的侦听器均未取消该事件,则窗口将最大化。 3 NativeWindow 对象调度 displayStateChange 事件。 此外, NativeWindow 对象还调度对窗口大小和位置进行相关更改的事件。窗口不调度这些相关更改的警告事件。相关事 件包括: a move 事件,如果窗口的左上角由于最大化操作而发生移动,则调度该事件。 b resize 事件,如果窗口大小由于最大化操作而发生更改,则调度该事件。 在最小化、还原、关闭、移动窗口和调整窗口大小时, NativeWindow 对象调度相似序列的事件。 包类 flash.display • NativeWindow • NativeWindowInitOptions • NativeWindowDisplayState • NativeWindowResize • NativeWindowSystemChrome • NativeWindowType flash.events • NativeWindowBoundsEvent • NativeWindowDisplayStateEvent75ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 在通过窗口镶边或其他操作系统控制的机制启动更改时,仅调度警告事件。在调用窗口方法以更改窗口大小、位置或显示状 态时,窗口仅调度通知更改的事件。如果需要,可以使用窗口 dispatchEvent() 方法调度警告事件,然后检查在继续进行更 改之前是否取消了警告事件。 有关窗口 API 类、方法、属性和事件的详细信息,请参阅针对 HTML 开发人员的 Adobe AIR API 参考。 控制本机窗口样式和行为的属性 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 以下属性控制窗口的基本外观和行为: • type • systemChrome • transparent • owner 创建窗口时,在传递到 window 构造函数的 NativeWindowInitOptions 对象上设置这些属性。 AIR 从应用程序描述符中读 取初始应用程序窗口的属性(不包括 type 属性,该属性无法在应用程序描述符中设置且始终设置为 normal)。窗口创建后将无 法更改这些属性。 这些属性的一些设置互不兼容:在 transparent 为 true 或 type 为 lightweight 时, systemChrome 无法设置为 standard。 窗口类型 Adobe AIR 1.0 和更高版本 AIR 窗口类型组合本机操作系统的镶边属性和可见性属性来创建三种功能类型的窗口。使用 NativeWindowType 类中定义的 常量可引用代码中的类型名称。 AIR 提供以下窗口类型: 窗口镶边 Adobe AIR 1.0 和更高版本 窗口镶边是一组使用户可以在桌面环境中操作窗口的控件。镶边元素包括标题栏、标题栏按钮、边框和调整大小手柄。 系统镶边 可以将 systemChrome 属性设置为 standard 或 none。选择 standard 系统镶边可为窗口提供一组由用户的操作系统创建和设置样 式的标准控件。选择 none 可为窗口提供您自己的镶边。使用 NativeWindowSystemChrome 类中定义的常量可引用代码中 的系统镶边设置。 系统镶边由系统管理。应用程序无法直接访问控件本身,但在使用控件时可以响应调度的事件。对窗口使用标准镶边时, transparent 属性必须设置为 false, type 属性必须设置为 normal 或 utility。 类型 说明 Normal 典型窗口。普通窗口使用标准尺寸样式的镶边,并显示在 Windows 的任务栏中和 Mac OS X 的窗口菜单中。 Utility 工具面板。实用程序窗口使用较细的系统镶边,而且不显示在 Windows 的任务栏中和 Mac OS X 的窗口菜单中。 Lightweight 简单窗口没有镶边,而且不显示在 Windows 的任务栏中和 Mac OS X 的窗口菜单中。此外, Windows 中的简单窗口 没有 “ 系统 ”(Alt+Space) 菜单。简单窗口适用于通知气泡和控件,例如用于打开短期显示区域的组合框。在使用的 type 为简单时, systemChrome 必须设置为 none。76ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 自定义镶边 创建不带系统镶边的窗口时,您必须添加自己的镶边控件才能处理用户和该窗口之间的交互。还可以根据需要随意创建透明的 非矩形窗口。 窗口透明度 Adobe AIR 1.0 和更高版本 若要允许窗口与桌面或其他窗口进行 Alpha 混合,请将该窗口的 transparent 属性设置为 true。必须在创建窗口之前设置 transparent 属性,否则将无法更改该属性。 透明窗口没有默认背景。不包含应用程序所绘制对象的任何窗口区域都不可见。如果所显示对象的 Alpha 设置小于 1,则该对 象下方的任何内容都会显示出来,包括同一窗口中的其他显示对象、其他窗口和桌面。 在希望创建具有不规则形状边框、 “ 淡出 ” 边框或显示为不可见的边框的应用程序时,透明窗口非常有用。然而,呈现经过 Alpha 混合的较大区域可能会很慢,因此应谨慎使用该效果。 重要说明: 在 Linux 中,不能穿过完全透明的像素传递鼠标事件。 应避免用完全透明的大型区域创建窗口,因为可能会在无法 察觉的情况下阻止用户访问其他窗口或其桌面上的项目。 在 Mac OS X 和 Windows 中,可以穿过完全透明的像素传递鼠标事 件。 不能对具有系统镶边的窗口使用透明度。此外,透明窗口中不能显示 HTML 中的 SWF 和 PDF 内容。有关详细信息,请参阅 第 42 页的 “ 在 HTML 页中加载 SWF 或 PDF 内容时的注意事项 ”。 静态 NativeWindow.supportsTransparency 属性可报告窗口透明度是否可用。在不支持透明度时,应用程序将与黑色背景合成。 在这些情况下,应用程序的任何透明区域都显示为不透明的黑色。这种做法可以很好地应对万一此属性测试失败而需要回退的 情况。例如,您可以向用户显示警告对话框,或显示矩形非透明用户界面。 请注意, Mac 和 Windows 操作系统始终支持透明度。支持 Linux 操作系统需要使用合成窗口管理器,但即使有合成窗口管 理器处于活动状态,透明度也可能因用户显示选项或硬件配置而不可用。 HTML 应用程序窗口中的透明度 Adobe AIR 1.0 和更高版本 默认情况下,即使包含窗口是透明的, HTML 窗口和 HTMLLoader 对象中所显示的 HTML 内容的背景也是不透明的。若 要关闭为 HTML 内容显示的默认背景,请将 paintsDefaultBackground 属性设置为 false。以下示例创建 HTMLLoader 并关闭 默认背景: var htmlView:HTMLLoader = new HTMLLoader(); htmlView.paintsDefaultBackground = false; 此示例使用 JavaScript 来关闭 HTML 窗口的默认背景: window.htmlLoader.paintsDefaultBackground = false; 如果 HTML 文档中的元素设置背景颜色,则该元素的背景不透明。不支持设置局部透明度(或不透明度)值。但是,可以使 用透明 PNG 格式的图形作为页面或页面元素的背景以实现相似的视觉效果。 窗口所有权 一个窗口可以拥有 一个或多个其他窗口。这些拥有的窗口始终显示在主窗口的前面,随主窗口一起最小化和还原,并在关闭主 窗口时关闭。窗口所有权无法转让给其他窗口,也无法删除窗口所有权。一个窗口只能归一个主窗口所有,但该窗口可拥有任 意数量的其他窗口。77ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 使用窗口所有权,可以更加轻松地管理工具调色板和对话框所使用的窗口。例如,如果在文档窗口中显示与之关联的 “ 保存 ” 对话框,使文档窗口拥有该对话框可使该对话框自动显示在文档窗口前面。 • NativeWindow.owner • Christian Cantrell:AIR 2.6 中的专属窗口 可视窗口目录 Adobe AIR 1.0 和更高版本 下表说明了窗口属性设置的不同组合在 Mac OS X、 Windows 和 Linux 操作系统中的视觉效果: 窗口设置 Mac OS X Microsoft Windows Linux* Type:normal SystemChrome:standard Transparent:false Type:utility SystemChrome:standard Transparent:false78ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 *Ubuntu (带有 Compiz 窗口管理器) 注: AIR 不支持以下系统镶边元素:Mac OS X 工具栏、 Mac OS X 代理图标、 Windows 标题栏图标以及替代系统镶边。 创建窗口 Adobe AIR 1.0 和更高版本 AIR 自动创建应用程序的第一个窗口,但您可以创建所需的任何其他窗口。若要创建本机窗口,请使用 NativeWindow 构造 函数方法。 若要创建 HTML 窗口,请使用 HTMLLoader createRootWindow() 方法或者从 HTML 文档中调用 JavaScript window.open() 方法。创建的窗口是一个 NativeWindow 对象,其显示列表中包含 HTMLLoader 对象。 HTMLLoader 对 象解释并显示窗口的 HTML 内容和 JavaScript 内容。您可以使用 window.nativeWindow 属性从 JavaScript 访问基础 NativeWindow 对象的属性。(只有在 AIR 应用程序沙箱中运行的代码可以访问此属性。) Type:Any SystemChrome:none Transparent:false Type:Any SystemChrome:none Transparent:true mxWindowedApplication 或 mx:Window Type:Any SystemChrome:none Transparent:true 窗口设置 Mac OS X Microsoft Windows Linux*79ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 初始化窗口时(包括初始应用程序窗口),您应考虑在不可见状态下创建窗口、加载内容或执行任何图形更新,然后使该窗口 可见。此过程可防止用户看到任何不和谐的可视更改。您可以指定应用程序的初始窗口应在不可见状态下创建,方法是在应用 程序描述符中指定 false 标签(或通过完全忽略此标签,因为 false 是默认值)。默认情况下,新 NativeWindow 不可见。使用 HTMLLoader createRootWindow() 方法创建 HTML 窗口时,可以将 visible 参数设置为 false。 调用 NativeWindow activate() 方法或将 visible 属性设置为 true 以使窗口可见。 指定窗口初始化属性 Adobe AIR 1.0 和更高版本 创建桌面窗口后,无法更改本机窗口的初始化属性。这些不可改变的属性及其默认值包括: 在应用程序描述符文件中设置 AIR 所创建的初始窗口的属性。 AIR 应用程序主窗口的 type 值始终是 normal。(可以在描述 符文件中指定其他窗口属性,例如 visible、 width 和 height,但可以随时更改这些属性。) 使用 NativeWindowInitOptions 类可设置应用程序创建的其他本机窗口和 HTML 窗口的属性。在创建窗口时,必须将指定 窗口属性的 NativeWindowInitOptions 对象传递到 NativeWindow 构造函数或 HTMLLoader createRootWindow() 方法。 以下代码为实用程序窗口创建 NativeWindowInitOptions 对象: var options = new air.NativeWindowInitOptions(); options.systemChrome = air.NativeWindowSystemChrome.STANDARD; options.type = air.NativeWindowType.UTILITY options.transparent = false; options.resizable = false; options.maximizable = false; 当 transparent 为 true 或 type 为 lightweight 时,不支持 将 systemChrome 设置为 standard。 注: 无法为使用 JavaScript window.open() 函数创建的窗口设置初始化属性。但是,您可以通过实现自己的 HTMLHost 类来 覆盖这些窗口的创建方式。有关详细信息,请参阅第 52 页的 “ 处理对 window.open() 的 JavaScript 调用 ”。 创建初始应用程序窗口 Adobe AIR 1.0 和更高版本 对应用程序的初始窗口使用标准 HTML 页。此页是从应用程序安装目录中加载的并放入应用程序沙箱中。该页用作应用程序 的初始入口点。 在应用程序启动时, AIR 将创建窗口、设置 HTML 环境并加载 HTML 页。在分析任何脚本或向 HTML DOM 添加任何元 素之前, AIR 将 runtime、 htmlLoader 和 nativeWindow 属性添加到 JavaScript Window 对象。可以使用这些属性从 JavaScript 中访问运行时类。 nativeWindow 属性使您可以直接访问桌面窗口的属性和方法。 属性 默认值 systemChrome standard type normal transparent false owner null maximizable true minimizable true resizable true80ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 以下示例说明用 HTML 所构建 AIR 应用程序的主页的基本框架:该页等待 JavaScript 窗口 load 事件,然后显示本机窗口。 注: 此示例中引用的 AIRAliases.js 文件是一个脚本文件,它为常用内置 AIR 类定义方便的别名变量。该文件位于 AIR SDK 的 frameworks 目录内。 创建 NativeWindow Adobe AIR 1.0 和更高版本 若要创建 NativeWindow,请将 NativeWindowInitOptions 对象传递到 NativeWindow 构造函数: var options = new air.NativeWindowInitOptions(); options.systemChrome = air.NativeWindowSystemChrome.STANDARD; options.transparent = false; var newWindow = new air.NativeWindow(options); 在将 visible 属性设置为 true 或调用 activate() 方法后,才显示该窗口。 创建窗口后,可以使用舞台属性和 Flash 显示列表技术来初始化其属性和将内容加载到该窗口中。 几乎在所有情况下,都应将新本机窗口的舞台 scaleMode 属性设置为 noScale(使用 StageScaleMode.NO_SCALE 常量)。 Flash 缩放模式旨在用于应用程序作者事先不知道应用程序显示区高宽比的情况。使用这些缩放模式,作者可以选择最少的内容损 失:剪辑内容、拉伸或压缩内容或者用空白空间进行填充。由于您控制 AIR (窗口帧)中的显示区,因此可以在不损失内容的 情况下使窗口大小适合内容或者使内容大小适合窗口。 HTML 窗口的缩放模式自动设置为 noScale。 注: 若要确定当前操作系统中允许的最大窗口大小和最小窗口大小,请使用以下静态 NativeWindow 属性: var maxOSSize = air.NativeWindow.systemMaxSize; var minOSSize = air.NativeWindow.systemMinSize; 创建 HTML 窗口 Adobe AIR 1.0 和更高版本 若要创建 HTML 窗口,可以调用 JavaScript Window.open() 方法,也可以调用 AIR HTMLLoader 类的 createRootWindow() 方法。 任何安全沙箱中的 HTML 内容都可以使用标准 JavaScript Window.open() 方法。如果内容在应用程序沙箱外部运行,则只能 调用 open() 方法来响应用户交互,例如鼠标单击或按键。在调用 open() 时,将创建具有系统镶边的窗口以在指定 URL 处显示 内容。例如: newWindow = window.open("xmpl.html", "logWindow", "height=600, width=400, top=10, left=10");81ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 注: 可以在 ActionScript 中扩展 HTMLHost 类以自定义用 JavaScript window.open() 函数创建的窗口。请参阅第 45 页的 “ 关于扩展 HTMLHost 类 ”。 应用程序安全沙箱中的内容可以访问更强大的窗口创建方法 HTMLLoader.createRootWindow()。使用此方法,可以指定新窗口 的所有创建选项。例如,以下 JavaScript 代码创建不具有大小为 300x400 像素的系统镶边的简单类型窗口: var options = new air.NativeWindowInitOptions(); options.systemChrome = "none"; options.type = "lightweight"; var windowBounds = new air.Rectangle(200,250,300,400); newHTMLLoader = air.HTMLLoader.createRootWindow(true, options, true, windowBounds); newHTMLLoader.load(new air.URLRequest("xmpl.html")); 注: 如果新窗口加载的内容位于应用程序安全沙箱外部,则 window 对象没有以下 AIR 属性:runtime、 nativeWindow 或 htmlLoader。 如果创建透明窗口,则不一定总能显示加载到该窗口的 HTML 中嵌入的 SWF 内容。对于用于引用 SWF 文件的 object 或 embed 标签,必须将它们的 wmode 参数设置为 opaque 或 transparent。 wmode 的默认值为 window,因此默认情况下,透明 窗口中不显示 SWF 内容。无论设置哪种 wmode 值,透明窗口中都无法显示 PDF 内容。(在早于 AIR 1.5.2 的版本中,透明 窗口中也无法显示 SWF 内容。) 使用 createRootWindow() 方法创建的窗口与打开窗口相互独立。JavaScript Window 对象的 parent 和 opener 属性为 null。打 开窗口可以使用 createRootWindow() 函数返回的 HTMLLoader 引用来访问新窗口的 Window 对象。在前一个示例的上下文 中,语句 newHTMLLoader.window 引用所创建窗口的 JavaScript Window 对象。 注: 可以从 JavaScript 和 ActionScript 中调用 createRootWindow() 函数。 创建 mx:Window Adobe AIR 1.0 和更高版本 若要创建 mx:Window,可以将 mx:Window 用作根标签创建 MXML 文件,也可以直接调用 Window 类构造函数。 下例通过调用 Window 构造函数来创建和显示 mx:Window: var newWindow:Window = new Window(); newWindow.systemChrome = NativeWindowSystemChrome.NONE; newWindow.transparent = true; newWindow.title = "New Window"; newWindow.width = 200; newWindow.height = 200; newWindow.open(true); 向窗口添加内容 Adobe AIR 1.0 和更高版本 向 AIR 窗口添加内容的方式取决于窗口类型。例如,使用 MXML 和 HTML,您能够以声明方式定义窗口的基本内容。可以 在应用程序 SWF 文件中嵌入资源,也可以从单独的应用程序文件中加载这些资源。 Flex、Flash 和 HTML 内容都可以动态创 建和动态添加到窗口。 在加载包含 JavaScript 的 SWF 内容或 HTML 内容时,必须考虑 AIR 安全模型。应用程序安全沙箱中的任何内容(即与应用 程序一起安装且可用 app: URL 方案加载的内容)具有对所有 AIR API 的完全访问权限。从此沙箱外部加载的任何内容均无法 访问 AIR API。应用程序沙箱外部的 JavaScript 内容无法使用 JavaScript Window 对象的 runtime、 nativeWindow 或 htmlLoader 属性。82ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 为允许安全的跨脚本访问,可以使用沙箱桥在应用程序内容和非应用程序内容之间提供有限的接口。在 HTML 内容中,还可 以将应用程序的页面映射到非应用程序沙箱中以允许该页面上的代码跨脚本访问外部内容。请参阅 第 60 页的 “AIR 安全性 ”。 将 HTML 内容加载到 NativeWindow 中 若要将 HTML 内容加载到 NativeWindow 中,可以将 HTMLLoader 对象添加到窗口舞台并将 HTML 内容加载到 HTMLLoader 中,也可以使用 HTMLLoader.createRootWindow() 方法创建已包含 HTMLLoader 对象的窗口。以下示例在 本机窗口舞台上的 300 x 500 像素的显示区域内显示 HTML 内容: //newWindow is a NativeWindow instance var htmlView:HTMLLoader = new HTMLLoader(); htmlView.width = 300; htmlView.height = 500; //set the stage so display objects are added to the top-left and not scaled newWindow.stage.align = "TL"; newWindow.stage.scaleMode = "noScale"; newWindow.stage.addChild( htmlView ); //urlString is the URL of the HTML page to load htmlView.load( new URLRequest(urlString) ); 若要将 HTML 页加载到 Flex 应用程序中,可以使用 Flex HTML 组件。 如果窗口使用透明度(即窗口的 transparent 属性为 true),则不会显示 HTML 文件中的 SWF 内容,除非将用于引用 SWF 文件的 object 或 embed 标签的 wmode 参数设置为 opaque 或 transparent。wmode 的默认值为 window,因此默认情况下,透 明窗口中不显示 SWF 内容。无论使用哪种 wmode 值,透明窗口中都不显示 PDF 内容。 另外,如果缩放、旋转 HTMLLoader 控件或将 HTMLLoader alpha 属性设置为 1.0 之外的任何值,则不会显示 SWF 内容 和 PDF 内容。 将 SWF 内容添加为 HTML 窗口上的覆盖图 由于 HTML 窗口包含在 NativeWindow 实例中,因此可以将 Flash 显示对象添加到显示列表中 HTML 层的上方或下方。 若要将显示对象添加到 HTML 层的上方,请使用 window.nativeWindow.stage 属性的 addChild() 方法。addChild() 方法将分层 的内容添加到窗口中任何现有内容的上方。 若要将显示对象添加到 HTML 层的下方,请使用 window.nativeWindow.stage 属性的 addChildAt() 方法,为 index 参数传入值 零。将对象放在零索引处会将现有内容(包括 HTML 显示)上移一层并在底部插入新内容。为使在 HTML 页下方分层的内 容可见,必须将 HTMLlLoader 对象的 paintsDefaultBackground 属性设置为 false。此外,该页中设置背景颜色的任何元素都将 不是透明的。例如,如果设置页面 body 元素的背景颜色,则该页的所有内容都将不是透明的。 以下示例说明如何将 Flash 显示对象作为覆盖图或衬垫层添加到 HTML 页。该示例创建两个简单的 shape 对象,在 HTML 内容下方和上方各添加一个 shape 对象。该示例还基于 enterFrame 事件更新形状位置。83ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 Bouncers

de Finibus Bonorum et Malorum

Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.

This paragraph has a background color.

At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga.

此示例简要介绍了 AIR 中跨越 JavaScript 和 ActionScript 之间边界的一些高级技术。如果您不熟悉如何使用 ActionScript 显示对象,请参阅《 Adobe ActionScript 3.0 开发人员指南》中的显示编程。 注: 若要访问 JavaScript Window 对象的运行时 nativeWindow 和 htmlLoader 属性,则必须从应用程序目录中加载 HTML 页。这种情况始终适用于基于 HTML 的应用程序中的根页面,但可能不适用于其他内容。此外,加载到框架(即使 在应用程序沙箱中)中的文档不接收这些属性,但可以访问父级文档的那些属性。 示例:创建本机窗口 Adobe AIR 1.0 和更高版本 以下示例说明如何创建本机窗口: function createNativeWindow() { //create the init options var options = new air.NativeWindowInitOptions(); options.transparent = false; options.systemChrome = air.NativeWindowSystemChrome.STANDARD; options.type = air.NativeWindowType.NORMAL; //create the window var newWindow = new air.NativeWindow(options); newWindow.title = "A title"; newWindow.width = 600; newWindow.height = 400; //activate and show the new window newWindow.activate(); } 管理窗口 Adobe AIR 1.0 和更高版本 使用 NativeWindow 类的属性和方法可管理桌面窗口的外观、行为和生命周期。 85ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 注: 当使用 Flex 框架时,通常最好使用框架类来管理窗口行为。通过 mx:WindowedApplication 类和 mx:Window 类可访 问大多数 NativeWindow 属性和方法。 获取 NativeWindow 实例 Adobe AIR 1.0 和更高版本 若要操作窗口,必须首先获取窗口实例。可以从以下任一位置获取窗口实例: • 用于创建窗口的本机窗口构造函数: var nativeWin = new air.NativeWindow(initOptions); • 窗口中显示对象的 stage 属性: var nativeWin = window.htmlLoader.stage.nativeWindow; • 由窗口调度的本机窗口事件的 target 属性: function onNativeWindowEvent(event) { var nativeWin = event.target; } • 窗口中显示的 HTML 页的 nativeWindow 属性: var nativeWin = window.nativeWindow; • NativeApplication 对象的 activeWindow 和 openedWindows 属性: var win = NativeApplication.nativeApplication.activeWindow; var firstWindow = NativeApplication.nativeApplication.openedWindows[0]; NativeApplication.nativeApplication.activeWindow 引用应用程序的活动窗口(但如果该活动窗口不是此 AIR 应用程序的窗 口,则返回 null)。 NativeApplication.nativeApplication.openedWindows 数组包含 AIR 应用程序中尚未关闭的所有窗口。 由于 Flex mx:WindowedApplication 和 mx:Window 对象都是显示对象,因此使用 stage 属性即可轻松地在 MXML 文件 中引用应用程序窗口,如下所示: Change Window Display State

AIR window display state commands

调整窗口大小和移动窗口 Adobe AIR 1.0 和更高版本 在窗口使用系统镶边时,该镶边提供用于调整窗口大小和在桌面范围内移动窗口的拖动控件。如果窗口不使用系统镶边,则必 须添加您自己的控件以允许用户调整窗口大小和移动窗口。 注: 若要调整窗口大小或移动窗口,必须首先获取对 NativeWindow 实例的引用。有关如何获取窗口引用的信息,请参阅 第 85 页的 “ 获取 NativeWindow 实例 ”。 调整窗口大小 若要使用户可以交互地调整窗口大小,请使用 NativeWindow startResize() 方法。如果此方法是从 mouseDown 事件中调用 的,则调整大小操作由鼠标驱动并在操作系统收到 mouseUp 事件时完成。在调用 startResize() 时,传入用于指定所调整窗口大 小的起始边或角的参数。 若要以编程方式设置窗口大小,请将窗口的 width、 height 或 bounds 属性设置为所需尺寸。设置范围时,可以同时更改窗口的 大小和位置。但是,无法保证发生更改的顺序。某些 Linux 窗口管理器不允许窗口扩展到桌面屏幕范围之外。在这些情况下, 即使更改的最终效果以其他方式产生了合法的窗口,最终窗口大小也可能因属性的设置顺序而受到限制。例如,如果同时更改 靠近屏幕底部的窗口的高度和 Y 轴位置,那么在 Y 轴位置更改之前应用高度更改时,可能不会进行完整的高度更改。 注: 在 Linux 中,更改窗口属性是异步进行的。如果在程序的一行中调整窗口大小,并在下一行读取尺寸,则这些尺寸仍将受 旧的设置影响。在所有平台上,当调整窗口大小时, NativeWindow 对象将调度 resize 事件。如果您需要根据窗口的新大小或 状态执行某种动作(如设置窗口中控件的布局),始终在 resize 事件处理函数中执行。请参阅第 91 页的 “ 侦听窗口事件 ”。90ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 移动窗口 要移动窗口而不调整其大小,请使用 NativeWindow startMove() 方法。与 startResize() 方法相似,在从 mouseDown 事件调用 startMove() 方法时,移动过程由鼠标驱动并在操作系统收到 mouseUp 事件时完成。 有关 startResize() 和 startMove() 方法的详细信息,请参阅针对 HTML 开发人员的 Adobe AIR API 参考。 若要以编程方式移动窗口,将窗口的 x、 y 或 bounds 属性设置为所需的位置。设置范围时,可以同时更改窗口的大小和位置。 注: 在 Linux 中,更改窗口属性是异步进行的。如果在程序的一行中移动窗口,并在下一行读取该位置,则对值的读取仍将受 旧的设置影响。在所有平台上,当更改位置时, NativeWindow 对象将调度 move 事件。如果您需要根据窗口的新位置执行某 种动作,始终在 move 事件处理函数中执行。请参阅第 91 页的 “ 侦听窗口事件 ”。 示例:调整窗口大小和移动窗口 Adobe AIR 1.0 和更高版本 以下示例说明如何对窗口启动调整大小和移动操作: Move and Resize the Window
Drag to resize
Drag to resize
Drag to move
Drag to resize
Drag to resize
侦听窗口事件 Adobe AIR 1.0 和更高版本 若要侦听窗口调度的事件,请向窗口实例注册侦听器。例如,若要侦听 closing 事件,请按如下方式向窗口实例注册侦听器: window.nativeWindow.addEventListener(air.Event.CLOSING, onClosingEvent); 在调度事件时, target 属性引用发送该事件的窗口。 大多数窗口事件都有两条相关消息。第一条消息发出即将发生窗口更改(可以取消)的信号通知,第二条消息发出更改已发生 的信号通知。例如,在用户单击窗口的关闭按钮后,将调度 closing 事件消息。如果侦听器未取消该事件,则窗口将关闭并且 close 事件将调度到所有侦听器。 通常,仅在已使用系统镶边触发事件时才调度 closing 等警告事件。例如,调用 window close() 方法不会自动调度 closing 事 件,而只调度 close 事件。但是,您可以构造 closing 事件对象并使用 window dispatchEvent() 方法来调度它。 调度 Event 对象的窗口事件包括: 调度 NativeWindowBoundsEvent 对象的窗口事件包括: 事件 说明 activate 在窗口收到焦点时调度。 deactivate 在窗口失去焦点时调度 closing 在窗口即将关闭时调度。仅当在按下系统镶边关闭按钮时或者在 Mac OS X 中调用 Quit 命令时,此事件才自动发生。 close 在窗口关闭时调度。 事件 说明 moving 在窗口左上角由于移动窗口、调整窗口大小或更改窗口显示状态而更改位置的前一刻调度。92ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 对于 NativeWindowBoundsEvent 事件,可以使用 beforeBounds 和 afterBounds 属性确定即将进行更改或完成更改之前和之 后的窗口范围。 调度 NativeWindowDisplayStateEvent 对象的窗口事件包括: 对于 NativeWindowDisplayStateEvent 事件,可以使用 beforeDisplayState 和 afterDisplayState 属性确定即将进行更改或完成 更改之前和之后的窗口显示状态。 在某些 Linux 窗口管理器中,将具有最大化大小设置的窗口最大化时并不调度显示状态更改事件。(窗口设置为最大化显示状 态,但并不调整其大小。) 显示全屏窗口 Adobe AIR 1.0 和更高版本 将 Stage 的 displayState 属性设置为 StageDisplayState.FULL_SCREEN_INTERACTIVE 会使窗口进入全屏模式,在此模式下允 许键盘输入。(在浏览器中运行的 SWF 内容中,不允许键盘输入)。若要退出全屏模式,用户需要按 Esc 键。 注: 如果为窗口设置了最大大小,某些 Linux 窗口管理器不会更改窗口尺寸以适应屏幕(但会删除窗口的系统镶边)。 例如,以下 Flex 代码定义用于设置简单全屏端点的简单 AIR 应用程序: move 在左上角更改位置之后调度。 resizing 在窗口宽度或高度由于调整大小或显示状态更改而发生更改的前一刻调度。 resize 在窗口更改大小之后调度。 事件 说明 displayStateChanging 在窗口显示状态更改的前一刻调度。 displayStateChange 在窗口显示状态更改之后调度。 事件 说明93ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 以下用于 Flash 的 ActionScript 示例模拟简单全屏文本端点: import flash.display.Sprite; import flash.display.StageDisplayState; import flash.text.TextField; import flash.text.TextFormat; public class FullScreenTerminalExample extends Sprite { public function FullScreenTerminalExample():void { var terminal:TextField = new TextField(); terminal.multiline = true; terminal.wordWrap = true; terminal.selectable = true; terminal.background = true; terminal.backgroundColor = 0x00333333; this.stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE; addChild(terminal); terminal.width = 550; terminal.height = 400; terminal.text = "Welcome to the dumb terminal application. Press the ESC key to exit.\n_"; var tf:TextFormat = new TextFormat(); tf.font = "Courier New"; tf.color = 0x00CCFF00; tf.size = 12; terminal.setTextFormat(tf); terminal.setSelection(terminal.text.length - 1, terminal.text.length); } } 以下 HTML 页模拟全屏文本端点:94ADOBE AIR HTML 开发人员指南 使用 AIR 本机窗口 上次更新 2011/10/13 Fullscreen Mode

Welcome to the dumb terminal app. Press the ESC key to exit...

95 上次更新 2011/10/13 第 8 章 : AIR 中的显示屏幕 Adobe AIR 1.0 和更高版本 使用 Adobe® AIR® Screen 类访问关于连接到计算机或设备的显示屏幕的信息。 更多帮助主题 flash.display.Screen AIR 中的显示屏幕的基础知识 Adobe AIR 1.0 和更高版本 屏幕 API 只包含单个 Screen 类,该类提供用于获取系统屏幕信息的静态成员以及用于描述特定屏幕的实例成员。 计算机系统可以连接多台监视器或显示器,这些监视器或显示器对应于虚拟空间中排列的多个桌面屏幕。 AIR Screen 类提供 有关这些屏幕、屏幕的相对排列及其可用空间的信息。如果多台监视器映射到同一屏幕,则只存在一个屏幕。如果屏幕的尺寸 大于监视器的显示区域,则无法确定当前可以看到屏幕的哪个部分。 屏幕表示独立的桌面显示区域。屏幕被描述为虚拟桌面内部的矩形。被指定为主显示屏的屏幕的左上角是虚拟桌面坐标系的原 点。用于描述屏幕的所有值均以像素为单位提供。 在此屏幕排列中,虚拟桌面中存在两个屏幕。主屏幕 (#1) 左上角的坐标始终是 (0,0)。如果屏幕排列更改为指定屏幕 #2 作为主屏幕,则屏幕 #1 的坐标将变 为负值。报告屏幕的可用范围时将排除菜单栏、任务栏和停靠栏。 有关屏幕 API 类、方法、属性和事件的详细信息,请参阅针对 HTML 开发人员的 Adobe AIR API 参考。 屏幕范围 虚拟屏幕 可用范围96ADOBE AIR HTML 开发人员指南 AIR 中的显示屏幕 上次更新 2011/10/13 枚举屏幕 Adobe AIR 1.0 和更高版本 可以使用以下屏幕方法和属性枚举虚拟桌面的屏幕: 不要保存 Screen 类方法和属性返回的值。用户或操作系统可随时更改可用屏幕及其排列方式。 以下示例使用屏幕 API 在多个屏幕间移动窗口,以响应箭头键的按键操作。该示例获取 screens 数组并将其在垂直或水平方向 排序(取决于所按的箭头键),以便将窗口移动到下一个屏幕。代码随后将遍历排序后的数组,将每个屏幕与当前屏幕的坐标 进行比较。该示例调用 Screen.getScreensForRectangle(),传入窗口范围,以便识别窗口的当前屏幕。 Screen Hopper

Use the arrow keys to move the window between monitors.

99 上次更新 2011/10/13 第 9 章 : 使用菜单 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在 Adobe® AIR® 中,使用本机菜单 API 中的类定义应用程序、窗口、上下文和弹出菜单。 菜单基础知识 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 有关在 AIR 应用程序中创建本机菜单的快速介绍和代码示例,请参阅 Adobe Developer Connection 上的以下快速入门文 章: • 向 AIR 应用程序添加本机菜单 通过本机菜单类,可以访问运行您的应用程序的操作系统的本机菜单功能。 NativeMenu 对象可用于应用程序菜单( Mac OS X 中提供)、窗口菜单( Windows 和 Linux 中提供)、上下文菜单和弹出菜单。 在 AIR 外,您可以使用上下文菜单类修改上下文菜单,当用户右键单击或按住 Cmd 键单击应用程序的中的对象时, Flash Player 会自动显示上下文菜单。( AIR 应用程序不会自动显示上下文菜单。) 菜单类 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 菜单类包括: 菜单类型 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 AIR 支持以下类型的菜单: 上下文菜单 右键单击或按住 Command 键单击 SWF 内容中的交互式对象或 HTML 内容中的文档元素时,作为响应,上下文 菜单会打开。 在 Flash Player 运行时中,上下文菜单自动显示。您可以使用 ContextMenu 类和 ContextMenuItem 类向此菜单中添加您 自己的命令。您也可以删除一些(非全部)内置命令。 在 AIR 运行时中,可以使用 NativeMenu 类或 ContextMenu 类创建上下文菜单。在 AIR 中的 HTML 内容中,您可以使用 Webkit HTML 和 JavaScript API 向 HTML 元素添加上下文菜单。 包类 flash.display • NativeMenu • NativeMenuItem flash.events • Event100ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 应用程序菜单(仅限 AIR) 应用程序菜单是应用于整个应用程序的全局菜单。 Mac OS X 支持应用程序菜单,但 Windows 或 Linux 不支持。 在 Mac OS X 上,操作系统自动创建应用程序菜单。可以使用 AIR 菜单 API 将项目和子菜单添加到标准菜单 中。可以添加用于处理现有菜单命令的侦听器。还可以删除现有项目。 窗口菜单(仅限 AIR) 窗口菜单与单个窗口关联,并显示在标题栏的下方。通过创建 NativeMenu 对象并将它分配给 NativeWindow 对象的 menu 属性,可以向窗口添加菜单。 Windows 和 Linux 操作系统支持窗口菜单,但 Mac OS X 不支 持。本机窗口菜单只能与有系统镶边的窗口一起使用。 停靠栏和系统任务栏图标菜单(仅限 AIR) 这些图标菜单类似于上下文菜单,分配给 Mac OS X 停靠栏或 Windows 和 Linux 任务栏上通知区域中的应用程序图标。 停靠栏图标菜单和系统任务栏图标菜单使用 NativeMenu 类。在 Mac OS X 上,菜单中 的项目添加到标准操作系统项目的上方。 Windows 或 Linux 中没有标准菜单。 弹出菜单(仅限 AIR) AIR 弹出菜单类似于上下文菜单,但不一定与特定应用程序对象或组件关联。通过调用任何 NativeMenu 对象的 display() 方法,可以使弹出菜单在窗口中的任何位置显示。 自定义菜单 本机菜单完全由操作系统调出,因此存在于 Flash 和 HTML 呈现模型以外。您可以不使用本机菜单,而总是使用 MXML、 ActionScript 或 JavaScript 创建自己的自定义非本机菜单(仅 AIR)。这些菜单必须在应用程序内容中完全呈现。 默认菜单(仅 AIR) 以下默认菜单由操作系统或内置 AIR 类提供: • Mac OS X 上的应用程序菜单 • Mac OS X 上的停靠栏图标菜单 • HTML 内容中的所选文本和图像的上下文菜单 • TextField 对象(或扩展 TextField 的对象)中的所选文本的上下文菜单 本机菜单结构 (AIR) Adobe AIR 1.0 和更高版本 本机菜单本质上是分层的。 NativeMenu 对象包含子级 NativeMenuItem 对象。表示子菜单的 NativeMenuItem 对象又可 以包含 NativeMenu 对象。结构中的顶级或根级的菜单对象表示应用程序菜单和窗口菜单的菜单栏。(上下文、图标和弹出菜 单没有菜单栏)。101ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 下图说明了一个典型菜单的结构。根菜单表示菜单栏,它包含的两个菜单项引用 “File” (文件)子菜单和 “Edit” (编辑)子 菜单。在此结构中, “File” (文件)子菜单包含两个命令项和一个引用项,该引用项引用 “Open Recent” (打开最近的项目) 子菜单,而该子菜单本身又包含三个项目。 “Edit” (编辑)子菜单包含三个命令和一个分隔符。 定义子菜单同时需要 NativeMenu 和 NativeMenuItem 对象。 NativeMenuItem 对象定义在父菜单中显示的标签,并允许 用户打开子菜单。NativeMenu 对象充当子菜单中的项目的容器。NativeMenuItem 对象通过 NativeMenuItem 的 submenu 属性引用 NativeMenu 对象。 若要查看创建此菜单的代码示例,请参阅第 108 页的 “ 本机菜单示例:窗口和应用程序菜单 (AIR)”。 菜单的事件 Adobe AIR 1.0 和更高版本 NativeMenu 和 NativeMenuItem 对象均调度 preparing、 displaying 和 select 事件: Preparing:每当对象即将开始用户交互时,该菜单及其菜单项会将 preparing 事件调度到任何注册的侦听器。交互包括打开菜 单或使用键盘快捷键选择项目。 注: preparing 事件仅适用于 Adobe AIR 2.6 和更高版本。 Displaying: 在显示菜单的前一刻,菜单及其菜单项将 displaying 事件调度到任何注册的侦听器。 preparing 和 displaying 事件允许您在向用户显示菜单内容或项目外观之前对其进行更新。例如,在 “ 打开最近的文件 ” 菜单的 displaying 事件的侦听器中,可以更改菜单项以反映最近查看过的文档的当前列表。 如果您删除了一个其键盘快捷键会触发 preparing 事件的菜单项,则将实际取消菜单交互,并且将不会调度 select 事件。 NativeMenu 根菜单 NativeMenuItem “文件” NativeMenu NativeMenuItem NativeMenuItem NativeMenuItem NativeMenu NativeMenuItem “GreatGatsby.pdf” NativeMenuItem “WarAndPeace.pdf” NativeMenuItem “Iliad.pdf” NativeMenuItem NativeMenu NativeMenuItem NativeMenuItem NativeMenuItem NativeMenuItem File 菜单 “New” “Save” “Open Recent” Open Recent 菜单 “Edit” Edit 菜单 “Copy” “Paste” 分隔线 “Preferences”102ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 该事件的 target 和 currentTarget 属性均为在其上注册了侦听器的对象:菜单本身或其中的一个项目。 preparing 事件将在 displaying 事件之前调度。通常,您只会侦听这两个事件中的一个,而不会同时侦听二者。 Select: 当用户选择命令项时,项目会将 select 事件调度到任何注册的侦听器。不能选择子菜单和分隔符项,因此永远不会调 度 select 事件。 select 事件从菜单项上升到它的包含菜单,然后上升到根菜单。可以直接在项目上侦听 select 事件,也可以在菜单结构的更高位 置侦听。在菜单上侦听 select 事件时,可以使用该事件的 target 属性识别所选项。当事件沿菜单层次结构上升时,该事件对象 的 currentTarget 属性可识别当前菜单对象。 注: ContextMenu 和 ContextMenuItem 对象调度 menuItemSelect 和 menuSelect 事件以及 select、preparing 和 displaying 事 件。 本机菜单命令的等效键 (AIR) Adobe AIR 1.0 和更高版本 可以为菜单命令分配等效键(有时称为快捷键)。当按下键或组合键时,菜单项会将 select 事件调度到任何注册的侦听器。包 含该项目的菜单必须是应用程序菜单的一部分,或者是要调用的命令的活动窗口菜单的一部分。 等效键有两部分,一部分是表示主键的字符串,另一部分是一组必须同时按下的功能键。若要分配主键,请将菜单项 keyEquivalent 属性设置为该键的单字符字符串。如果使用大写字母,则 Shift 键会自动添加到功能键组中。 在 Mac OS X 上,默认功能键是 Command 键 (Keyboard.COMMAND)。在 Windows 和 Linux 中,是 Control 键 (Keyboard.CONTROL)。这些默认键会自动添加到功能键组中。若要分配其他功能键,请将包含所需键代码的新键组分配给 keyEquivalentModifiers 属性。默认键组将被覆盖。无论使用默认功能键还是分配自己的功能键组,如果分配给 keyEquivalent 属性的字符串是大写字母,则会添加 Shift 键。用于功能键的键代码的常量在 Keyboard 类中定义。 所分配的等效键字符串将自动显示在菜单项名称的旁边。格式取决于用户的操作系统和系统首选项。 注: 在 Windows 操作系统上,如果将 Keyboard.COMMAND 值分配给功能键组,则菜单中不显示等效键。但是,必须使用 Ctrl 键才能激活菜单命令。 以下示例分配 Ctrl+Shift+G 作为菜单项的等效键: var item = new air.NativeMenuItem("Ungroup"); item.keyEquivalent = "G"; 此示例通过直接设置功能键组将 Ctrl+Shift+G 分配为等效键: var item = new air.NativeMenuItem("Ungroup"); item.keyEquivalent = "G"; item.keyEquivalentModifiers = [air.Keyboard.CONTROL]; 注: 等效键仅为应用程序菜单和窗口菜单触发。如果将等效键添加到上下文或弹出菜单,则等效键将显示在菜单标签中,但永 远不会调用关联的菜单命令。 助记键 (AIR) Adobe AIR 1.0 和更高版本 助记键是菜单的操作系统键盘接口的一部分。 Linux、 Mac OS X 和 Windows 都允许用户通过键盘打开菜单并选择命令,但 有一些细微的区别。 在 Mac OS X 中,用户键入菜单或命令的第一个或前两个字母,然后按 Return 键。 mnemonicIndex 属性将被忽略。103ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 在 Windows 上,仅一个字母是有效的。默认情况下,有效字母是标签中的第一个字符,但是,如果将助记键分配给菜单项, 则有效字符将成为所指定的字母。如果一个菜单中的两个项有相同的有效字符(无论是否分配了助记键),则用户的键盘与菜 单的交互稍有改变。用户必须将该字母按下所需的次数来突出显示所需项,然后按 Enter 完成选择,而不是仅按单个字母就能 选择菜单或命令。为了保持一致的行为,应向窗口菜单中的每个菜单项都分配一个唯一的助记键。 在 Linux 中不提供默认的助记键。 必须指定菜单项的 mnemonicIndex 属性的值才能提供助记键。 指定助记键字符作为标签字符串中的索引。标签中第一个字符的索引是 0。因此,若要使用 “r” 作为带 “Format” 标签的菜单 项的助记键,可以将 mnemonicIndex 属性设置为等于 2。 var item = new air.NativeMenuItem("Format"); item.mnemonicIndex = 2; 菜单项状态 Adobe AIR 1.0 和更高版本 菜单项有两个状态属性:checked 和 enabled。 checked 设置为 true 将在项目标签旁边显示选中标记。 var item = new air.NativeMenuItem("Format"); item.checked = true; enabled 在 true 和 false 之间切换值可以控制是否启用命令。禁用的项目将在视觉上 “ 灰显 ”,并且不调度 select 事件。 var item = new air.NativeMenuItem("Format"); item.enabled = false; 将对象附加到菜单项 Adobe AIR 1.0 和更高版本 使用 NativeMenuItem 类的 data 属性可以引用每个项目中的任意对象。例如,在 “Open Recent” (打开最近的项目)菜单 中,可以将每个文档的 File 对象分配给每个菜单项。 var file = air.File.applicationStorageDirectory.resolvePath("GreatGatsby.pdf") var menuItem = docMenu.addItem(new air.NativeMenuItem(file.name)); menuItem.data = file; 创建本机菜单 (AIR) Adobe AIR 1.0 和更高版本 本主题描述如何创建 AIR 所支持的各种类型的本机菜单。 创建根菜单对象 Adobe AIR 1.0 和更高版本 若要创建 NativeMenu 对象来充当菜单的根,请使用 NativeMenu 构造函数: var root = new air.NativeMenu(); 对于应用程序菜单和窗口菜单,根菜单表示菜单栏,并且应当只包含打开子菜单的项目。上下文菜单和弹出菜单没有菜单栏, 因此根菜单可以包含命令和分隔线以及子菜单。104ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 在创建菜单之后,可以添加菜单项。除非使用菜单对象的 addItemAt() 方法在给定索引处添加项目,否则项目以添加顺序出现 在菜单中。 将菜单分配为应用程序、窗口、或图标菜单,或将其显示为弹出菜单,如以下几节所示: 设置应用程序菜单或窗口菜单 您的代码中应包含应用程序菜单(受 Mac OS 支持)和窗口菜单(受其他操作系统支持),这很重要 var root = new air.NativeMenu(); if (air.NativeApplication.supportsMenu) { air.NativeApplication.nativeApplication.menu = root; } else if (NativeWindow.supportsMenu) { nativeWindow.menu = root; } 注: Mac OS 定义了一个菜单,其中包含可用于每个应用程序的标准项目。将新 NativeMenu 对象分配给 NativeApplication 对象的 menu 属性可以替换标准菜单。还可以使用标准菜单,而不是替换它。 Adobe Flex 提供了 FlexNativeMenu 类,用于方便地创建跨平台工作的菜单。如果您使用的是 Flex 框架,请使用 FlexNativeMenu 类,而不要使用 NativeMenu 类。 设置停靠栏图标菜单或系统托盘图标菜单 air.NativeApplication.nativeApplication.icon.menu = root; 注: Mac OS X 为应用程序停靠栏图标定义了标准菜单。在将新 NativeMenu 分配给 DockIcon 对象的 menu 属性时,该菜 单中的项目将显示在标准项目之上。不能删除、访问或修改标准菜单项。 以弹出方式显示菜单 root.display(window.nativeWindow.stage, x, y); 更多帮助主题 开发跨平台 AIR 应用程序 创建子菜单 Adobe AIR 1.0 和更高版本 若要创建子菜单,请将 NativeMenuItem 对象添加到父菜单,然后将定义子菜单的 NativeMenu 对象分配给该项目的 submenu 属性。 AIR 提供了两种方式来创建子菜单项及其关联的菜单对象: 可以使用 addSubmenu() 方法在一个步骤中创建菜单项及其相关的菜单对象: var editMenuItem = root.addSubmenu(new air.NativeMenu(), "Edit"); 也可以创建菜单项,然后单独将菜单对象分配给其 submenu 属性: var editMenuItem = root.addItem("Edit", false); editMenuItem.submenu = new air.NativeMenu();105ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 创建菜单命令 Adobe AIR 1.0 和更高版本 若要创建菜单命令,请将 NativeMenuItem 对象添加到菜单,然后添加一个事件侦听器来引用实现菜单命令的函数: var copy = new air.NativeMenuItem("Copy", false); copy.addEventListener(air.Event.SELECT, onCopyCommand); editMenu.addItem(copy); 可以在命令项本身上侦听 select 事件(如本例中所示),也可以在父菜单对象上侦听 select 事件。 注: 表示子菜单和分隔线的菜单项不调度 select 事件,因此不能用作命令。 创建菜单分隔线 Adobe AIR 1.0 和更高版本 若要创建分隔线,请创建 NativeMenuItem,并在构造函数中将 isSeparator 参数设置为 true。然后,将分隔符项目添加到菜 单中的正确位置: var separatorA = new air.NativeMenuItem("A", true); editMenu.addItem(separatorA); 不显示为分隔符指定的标签(如果有)。 关于 HTML 中的上下文菜单 (AIR) Adobe AIR 1.0 和更高版本 在使用 HTMLLoader 对象显示的 HTML 内容中, contextmenu 事件可用于显示上下文菜单。默认情况下,当用户调用所选 文本上的上下文菜单事件时(通过右键单击或命令单击文本),将自动显示上下文菜单。若要防止打开默认菜单,可以侦听 contextmenu 事件并调用事件对象的 preventDefault() 方法: function showContextMenu(event){ event.preventDefault(); } 然后可以使用 DHTML 技术或通过显示 AIR 本机上下文菜单来显示自定义上下文菜单。以下示例通过调用菜单的 display() 方 法响应 HTML contextmenu 事件,来显示本机上下文菜单:106ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13

Custom context menu.

显示弹出本机菜单 (AIR) Adobe AIR 1.0 和更高版本 通过调用菜单的 display() 方法,可以随时随地在窗口上方显示任何 NativeMenu 对象。此方法需要对舞台的引用;因此,只 有应用程序沙箱中的内容可以将菜单显示为弹出菜单。 以下方法显示由名为 popupMenu 的 NativeMenu 对象定义的菜单来响应鼠标单击: function onMouseClick(event) { popupMenu.display(window.nativeWindow.stage, event.clientX, event.clientY); } 注: 不需要显示此菜单直接响应事件。任何方法都可以调用 display() 函数。 处理菜单事件 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 当用户选择菜单时,或用户选择菜单项时,菜单将调度事件。107ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 菜单类的事件摘要 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 将事件侦听器添加到菜单或个别项目来处理菜单事件。 选择菜单事件 Adobe AIR 1.0 和更高版本 若要处理菜单项上的单击,请将 select 事件的事件侦听器添加到 NativeMenuItem 对象: var menuCommandX = new NativeMenuItem("Command X"); menuCommand.addEventListener(air.Event.SELECT, doCommandX) 因为 select 事件会上升到包含菜单,所以还可以在父菜单上侦听 select 事件。在菜单级别上侦听时,可以使用事件对象的 target 属性来确定选择了哪个菜单命令。以下示例跟踪所选命令的标签: var colorMenuItem = new air.NativeMenuItem("Choose a color"); var colorMenu = new air.NativeMenu(); colorMenuItem.submenu = colorMenu; var red = new air.NativeMenuItem("Red"); var green = new air.NativeMenuItem("Green"); var blue = new air.NativeMenuItem("Blue"); colorMenu.addItem(red); colorMenu.addItem(green); colorMenu.addItem(blue); if(air.NativeApplication.supportsMenu){ air.NativeApplication.nativeApplication.menu.addItem(colorMenuItem); air.NativeApplication.nativeApplication.menu.addEventListener(air.Event.SELECT, colorChoice); } else if (air.NativeWindow.supportsMenu){ var windowMenu = new air.NativeMenu(); window.nativeWindow.menu = windowMenu; windowMenu.addItem(colorMenuItem); windowMenu.addEventListener(air.Event.SELECT, colorChoice); } function colorChoice(event) { var menuItem = event.target; air.trace(menuItem.label + " has been selected"); } Object 调度的事件 NativeMenu (AIR) Event.PREPARING (Adobe AIR 2.6 和更高版本) Event.DISPLAYING Event.SELECT (从子项目和子菜单传播) NativeMenuItem (AIR) Event.PREPARING (Adobe AIR 2.6 和更高版本) Event.SELECT Event.DISPLAYING (从父菜单传播)108ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 如果正在使用 ContextMenuItem 类,则可以侦听 select 事件或 menuItemSelect 事件。menuItemSelect 事件可以提供有关拥有 此上下文菜单的对象的其他信息,但不能上升到包含菜单。 显示菜单事件 Adobe AIR 1.0 和更高版本 若要处理菜单的打开,可以为 displaying 事件添加一个侦听器,在显示菜单之前将调度该侦听器。可以使用 displaying 事件更 新菜单,例如,通过添加或删除项目,或通过更新个别项目的启用或选中状态。还可以从 ContextMenu 对象侦听 menuSelect 事件。 在 AIR 2.6 和更高版本中,可以使用 preparing 事件来更新菜单,以响应显示菜单或使用键盘快捷键选择项目。 本机菜单示例:窗口和应用程序菜单 (AIR) Adobe AIR 1.0 和更高版本 以下示例创建在第 100 页的 “ 本机菜单结构 (AIR)” 中显示的菜单。 此菜单在设计上可同时用于 Windows (仅支持窗口菜单)和 Mac OS X (仅支持应用程序菜单)。为进行区分, MenuExample 类构造函数将检查 NativeWindow 和 NativeApplication 类的静态 supportsMenu 属性。如果 NativeWindow.supportsMenu 为 true,则该构造函数将为窗口创建 NativeMenu 对象,然后创建和添加 “File” (文件)和 “Edit” (编辑)子菜单。如果 NativeApplication.supportsMenu 为 true,则该构造函数将创建 “File” (文件)和 “Edit” (编 辑)菜单,并将它们添加到 Mac OS X 操作系统所提供的现有菜单中。 本示例还将说明菜单事件的处理过程。select 事件在项目级别以及菜单级别进行处理。从包含所选项的菜单到根菜单的菜单链中 的每个菜单都将响应 select 事件。 displaying 事件与 “Open Recent” (最近打开的项目)菜单一起使用。在打开菜单之前,将 以最新的 Documents 数组(在此示例中实际上不发生更改)刷新菜单中的项目。尽管此示例中不显示,但还可以在个别项目 上侦听 displaying 事件。 AIR menus 使用 MenuBuilder 框架 Adobe AIR 1.0 和更高版本 除了标准菜单类以外,Adobe AIR 还包括一个菜单生成器 JavaScript 框架,使开发人员创建菜单更加容易。 MenuBuilder 框 架允许以声明方式定义 XML 或 JSON 格式的菜单结构。它还提供了帮助器方法,可以创建对 AIR 应用程序可用的任何菜单类 型。若要查看如何在 AIR 中使用本机菜单的完整列表,请参阅 第 99 页的 “ 菜单基础知识 ”。 使用 MenuBuilder 框架创建菜单 Adobe AIR 1.0 和更高版本 MenuBuilder 框架允许使用 XML 或 JSON 定义菜单的结构。该框架包含的方法可以用于加载和分析包含菜单结构的文件。 一旦加载了菜单结构,就可以用其他方法指定如何在应用程序中使用菜单。此方法允许将菜单设置为 Mac OS X 应用程序菜 单、窗口菜单或上下文菜单。 MenuBuilder 框架未内置在运行时环境中。若要使用该框架,请在应用程序代码中包括 Adobe AIR SDK 中附带的 AIRMenuBuilder.js 文件,如下所示: MenuBuilder 框架在设计上运行于应用程序沙箱中。无法从经典沙箱调用此框架方法。111ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 供开发人员使用的所有框架方法都被定义为 air.ui.Menu 类上的类方法。 MenuBuilder 基本工作流程 Adobe AIR 1.0 和更高版本 通常,不管要创建的菜单类型是什么,使用 MenuBuilder 框架创建菜单时都需要执行三个步骤: 1 定义菜单结构:创建一个文件,其中包含定义菜单结构的 XML 或 JSON。对于某些菜单类型,顶级菜单项是菜单(例如, 在窗口菜单或应用程序菜单中)。对于其他菜单类型,顶级项目是单个菜单命令(比如在上下文菜单中)。若要查看定义菜 单结构的格式的详细信息,请参阅第 113 页的 “ 定义 MenuBuilder 菜单结构 ”。 2 加载菜单结构: 调用合适的 Menu 类方法( Menu.createFromXML() 或 Menu.createFromJSON())以加载菜单结构文件,并 将其转换为实际的菜单对象。两种方法都返回一个 NativeMenu 对象,然后可以将此对象传递给该框架的菜单设置方法之 一。 3 分配菜单:按照菜单的使用方式调用合适的 Menu 类方法。选项是: • Menu.setAsMenu(),用于窗口菜单或应用程序菜单 • Menu.setAsContextMenu(),将该菜单显示为 DOM 元素的上下文菜单 • Menu.setAsIconMenu(),将该菜单设置为系统任务栏或停靠栏图标的上下文菜单 确定何时执行代码很重要。尤其是,必须在创建实际操作系统窗口之前分配窗口菜单。任何将菜单设置为窗口菜单的 setAsMenu() 调用都必须直接在 HTML 页中执行,而不是在 onload 或其他事件处理函数中执行。在操作系统打开窗口之前, 必须运行创建菜单的代码。同时,任何引用 DOM 元素的 setAsContextMenu() 调用都必须在创建此 DOM 元素之后发生。最 安全的方法是将包含菜单分配代码的
This block of text is context menu enabled. Right click or Command- click on the text to view the context menu.
116ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 示例:JSON MenuBuilder 数据源 Adobe AIR 1.0 和更高版本 以下示例使用 MenuBuilder 框架以 JSON 数组作为数据源定义一个文本区域的上下文菜单。有关在 XML 中指定相同菜单结 构的应用程序,请参阅第 115 页的 “ 示例:XML MenuBuilder 数据源 ”。 此应用程序由两个文件组成。 第一个文件是菜单数据源,在名为 “textContextMenu.js” 的文件中。 [ {label: "MenuItem A"}, {label: "MenuItem B", type: "check", toggled: "true"}, {label: "MenuItem C", enabled: "false"}, {type: "separator"}, {label: "MenuItem D", items: [ {label: "SubMenuItem D-1"}, {label: "SubMenuItem D-2"}, {label: "SubMenuItem D-3"} ] } ] 第二个文件是应用程序用户界面的源代码(在 application.xml 文件中指定为初始窗口的 HTML 文件): JSON-based menu data source example
This block of text is context menu enabled. Right click or Command- click on the text to view the context menu.
117ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 用 MenuBuilder 添加菜单键盘功能 Adobe AIR 1.0 和更高版本 操作系统本机菜单支持使用快捷键,这些快捷键也可在 Adobe AIR 中使用。可以在菜单数据源中指定的两类快捷键是菜单命 令等效键和助记键。 指定菜单等效键 Adobe AIR 1.0 和更高版本 可以为窗口或应用程序的菜单命令指定等效键(有时称为快捷键)。当按下键或组合键时, NativeMenuItem 将调度 select 事 件,并调用在数据源中指定的任何 onSelect 事件处理函数。行为与用户选择菜单项相同。 有关菜单等效键的完整详细信息,请参阅第 102 页的 “ 本机菜单命令的等效键 (AIR)”。 通过使用 MenuBuilder 框架,可以在数据源的相应节点中指定菜单项的等效键。如果数据源有 keyEquivalent 字段,则 MenuBuilder 框架使用该值作为等效键字符。 还可以指定作为等效组合键的一部分的功能键。若要添加功能键,请将 altKey、ctrlKey、cmdKey 或 shiftKey 字段指定为 true。 所指定的一个或多个键将成为等效组合键的一部分。默认情况下,对 Windows 指定 Ctrl 键,对 Mac OS X 指定 Command 键。若要覆盖此默认行为,请包括设置为 false 的 defaultKeyEquivalentModifiers 字段。 以下示例显示基于 XML 的菜单数据源(在名为 “keyEquivalentMenu.xml” 的文件中包含等价键)的数据结构: 以下示例应用程序从 “keyEquivalentMenu.xml” 加载菜单结构,并使用它作为应用程序的窗口菜单或应用程序菜单的结构: XML-based menu with key equivalents example 118ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 指定菜单项助记键 Adobe AIR 1.0 和更高版本 菜单项助记键是与菜单项关联的键。如果在显示此菜单时按下该键,将触发此菜单项命令。行为与用户用鼠标选择菜单项相 同。通常,操作系统通过对菜单项名称中的字符添加下划线来指示菜单项助记键。 有关助记键的详细信息,请参阅第 102 页的 “ 助记键 (AIR)”。 对于 MenuBuilder 框架,则指定菜单项助记键的最简单方式是在菜单项的 label 字段中包括下划线字符 (_)。请将下划线放在 紧靠充当该菜单项助记键的字母左侧。例如,如果在使用 MenuBuilder 框架加载的数据源中使用以下 XML 节点,则此命令 的助记键是第二个单词的第一个字符(字母 “A”): 创建 NativeMenu 对象时,下划线不包括在标签中。而是以下划线后面的字符作为菜单项的助记键。若要在菜单项的名称中包 括文本下划线字符,请使用两个下划线字符( “__”)。此序列将在菜单项标签中将转换为一个下划线。 作为在 label 字段中使用下划线字符的替代选择,可以为助记键字符提供整数索引位置。可以在菜单项数据源对象或 XML 元素 的 mnemonicIndex 字段中指定索引。 处理 MenuBuilder 菜单事件 Adobe AIR 1.0 和更高版本 与 NativeMenu 的用户交互是事件驱动的。当用户选择菜单项或打开菜单或子菜单时, NativeMenuItem 对象将调度一个事 件。使用通过 MenuBuilder 框架创建的 NativeMenu 对象,可以将事件侦听器注册到各个 NativeMenuItem 对象或 NativeMenu。订阅和响应这些事件时,就好像您已经以手动方式而不是使用 MenuBuilder 框架创建了 NativeMenu 和 NativeMenuItem 对象。有关详细信息,请参阅第 101 页的 “ 菜单的事件 ”。 MenuBuilder 框架补充了标准事件处理过程,从而使您可以在菜单数据源中为菜单项指定 select 事件处理函数。如果在菜单项 数据源中指定 onSelect 字段,则当用户选择菜单项时,将调用所指定的函数。例如,假设以下 XML 节点包含在使用 MenuBuilder 框架加载的数据源中。当选择菜单项时,将调用名为 doSave() 的函数: 用于 XML 数据源时,onSelect 字段是 String。使用 JSON 数组时,此字段可以是有函数名称的 String。此外,仅对 JSON 数 组,该字段还可以是对作为对象的函数的变量引用。但是,如果 JSON 数组使用 Function 变量引用,则必须在发生 onload 事 件处理函数或 JavaScript 安全违规之前或在此期间创建菜单。在所有情况中,必须在全局作用域内定义所指定的函数。 调用所指定的函数时,运行时会向它传递两个参数。第一个参数是由 select 事件调度的事件对象。它是 Event 类的实例。传递 给此函数的第二个参数是匿名对象,其中包含用于创建菜单项的数据。此对象有以下属性。每个属性的值均与原始数据结构中 的值匹配,如果未在原始数据结构中设置该属性,则其值为 null: • altKey • cmdKey • ctrlKey • defaultKeyEquivalentModifiers • enabled • keyEquivalent • label • mnemonicIndex • onSelect119ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 • shiftKey • toggled • type 以下示例用于实验 NativeMenu 事件。该示例包括两个菜单。窗口和应用程序菜单使用 XML 数据源创建。由
  • 元 素所表示的项目列表的上下文菜单使用 JSON 数组数据源创建。当用户选择菜单项时,屏幕上的文本区域将显示有关每个事件 的信息。 以下代码是应用程序的源代码: Menu event handling example
      120ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13
    • List item 1
    • List item 2
    • List item 3
    Choose menu commands. Information about the events displays here.
    | 以下代码是主菜单( “mainMenu.xml”)的数据源: 以下代码是上下文菜单( “listContextMenu.js”)的数据源; [ {label: "Move Item Up", onSelect: "moveItemUp"}, {label: "Move Item Down", onSelect: "moveItemDown"} ] 以下代码包含 printObject.js 文件中的代码。在本例中,该文件包括 printObject() 函数,该函数由应用程序使用,但它不影响 菜单的操作。121ADOBE AIR HTML 开发人员指南 使用菜单 上次更新 2011/10/13 function printObject(obj) { if (!obj) { if (typeof obj == "undefined") { return "[undefined]"; }; if (typeof obj == "object") { return "[null]"; }; return "[false]"; } else { if (typeof obj == "boolean") { return "[true]"; }; if (typeof obj == "object") { if (typeof obj.length == "number") { var ret = []; for (var i=0; i ", printObject(obj[k])]); } if (hadChildren) { return ["{\n", ret.join(",\n"), "\n}"].join(""); } } } if (typeof obj == "function") { return "[Function]"; } return String(obj); } }122 上次更新 2011/10/13 第 10 章 : AIR 中的任务栏图标 Adobe AIR 1.0 和更高版本 很多操作系统都提供有任务栏(例如 Mac OS X 停靠栏),任务栏中可包含表示应用程序的图标。 Adobe® AIR® 提供了一个 接口,可以通过 NativeApplication.nativeApplication.icon 属性与应用程序任务栏图标进行交互。 更多帮助主题 flash.desktop.NativeApplication flash.desktop.DockIcon flash.desktop.SystemTrayIcon 关于任务栏图标 Adobe AIR 1.0 和更高版本 AIR 会自动创建 NativeApplication.nativeApplication.icon 对象。对象类型可以为 DockIcon 或 SystemTrayIcon,具体取决于 操作系统。可以使用 NativeApplication.supportsDockIcon 和 NativeApplication.supportsSystemTrayIcon 属性来确定 AIR 在当 前操作系统上支持哪些 InteractiveIcon 子类。InteractiveIcon 基类提供了 width、height 和 bitmaps 属性,可以使用这些属性 来更改图标所使用的图像。但是,在错误操作系统上访问特定于 DockIcon 或 SystemTrayIcon 的属性会生成运行时错误。 若要设置或更改图标所使用的图像,请创建一个包含一个或多个图像的数组,然后将该数组分配给 NativeApplication.nativeApplication.icon.bitmaps 属性。在不同操作系统上,任务栏图标的大小会有所不同。为了避免因缩放而 导致图像质量降级,可以向 bitmaps 数组中添加多个不同大小的图像。如果提供多个图像, AIR 会选择大小与任务栏图标的当 前显示大小最接近的图像,仅在需要时进行缩放。以下示例使用两个图像来设置任务栏图标的图像: air.NativeApplication.nativeApplication.icon.bitmaps = [bmp16x16.bitmapData, bmp128x128.bitmapData]; 若要更改图标图像,请将包含新图像的数组分配给 bitmaps 属性。通过响应 enterFrame 或 timer 事件来更改图像,可以为图标 添加动画效果。 若要从 Windows 和 Linux 的通知区域中删除图标,或者恢复 Mac OS X 中的默认图标外观,请将 bitmaps 设置为空数组: air.NativeApplication.nativeApplication.icon.bitmaps = []; 停靠栏图标 Adobe AIR 1.0 和更高版本 AIR 在 NativeApplication.supportsDockIcon 为 true 时支持停靠栏图标。NativeApplication.nativeApplication.icon 属性表示停靠 栏上的应用程序图标(而不是窗口的停靠栏图标)。 注: AIR 不支持更改 Mac OS X 停靠栏上的窗口图标。此外,对应用程序的停靠栏图标所做的更改只有当应用程序运行时才会 应用,应用程序终止时图标将还原为其正常外观。123ADOBE AIR HTML 开发人员指南 AIR 中的任务栏图标 上次更新 2011/10/13 停靠栏图标菜单 Adobe AIR 1.0 和更高版本 通过创建包含命令的 NativeMenu 对象并将其分配给 NativeApplication.nativeApplication.icon.menu 属性,可以向标准停靠栏 菜单中添加命令。菜单中的项目显示在标准停靠栏图标菜单项的上方。 回弹停靠栏 Adobe AIR 1.0 和更高版本 通过调用 NativeApplication.nativeApplication.icon.bounce() 方法,可以回弹停靠栏图标。如果将 bounce() priority 参数设置为 informational,则图标将回弹一次。如果将该参数设置为 critical,则图标将始终保持回弹状态,直到用户激活该应用程序。 用作 priority 参数的常量由 NotificationType 类定义。 注: 如果应用程序已经处于活动状态,则不会回弹图标。 停靠栏图标事件 Adobe AIR 1.0 和更高版本 单击停靠栏图标后, NativeApplication 对象将调度 invoke 事件。如果应用程序尚未运行,则系统将启动该应用程序。否则, invoke 事件将传送到正在运行的应用程序实例。 系统任务栏图标 Adobe AIR 1.0 和更高版本 当 NativeApplication.supportsSystemTrayIcon 为 true 时, AIR 支持系统任务栏图标(目前只有 Windows 和大多数 Linux 发 行版是这种情况)。在 Windows 和 Linux 中,系统任务栏图标显示在任务栏的通知区域中。 默认情况下不显示任何图标。要 显示图标,请将包含 BitmapData 对象的数组分配给图标的 bitmaps 属性。若要更改图标图像,请将包含新图像的数组分配给 bitmaps。若要删除图标,请将 bitmaps 设置为 null。 系统任务栏图标菜单 Adobe AIR 1.0 和更高版本 通过创建 NativeMenu 对象并将其分配给 NativeApplication.nativeApplication.icon.menu 属性,可以向系统任务栏图标中添加 菜单(操作系统不会提供任何默认菜单)。右键单击图标即可访问系统任务栏图标菜单。 系统任务栏图标工具提示 Adobe AIR 1.0 和更高版本 通过设置 tooltip 属性可以向图标添加工具提示: air.NativeApplication.nativeApplication.icon.tooltip = "Application name";124ADOBE AIR HTML 开发人员指南 AIR 中的任务栏图标 上次更新 2011/10/13 系统任务栏图标事件 Adobe AIR 1.0 和更高版本 NativeApplication.nativeApplication.icon 属性引用的 SystemTrayIcon 对象可以为 click、 mouseDown、 mouseUp、 rightClick、 rightMouseDown 和 rightMouseUp 事件调度 ScreenMouseEvent。可以组合使用这些事件和图标菜单,以便用户 能够在您的应用程序没有可见窗口时与应用程序进行交互。 示例:创建不带任何窗口的应用程序 Adobe AIR 1.0 和更高版本 以下示例创建了一个具有系统任务栏图标但没有可见窗口的 AIR 应用程序。(在应用程序描述符中,不得将应用程序的 visible 属性设置为 true,否则窗口在应用程序启动时可见。) 注: 使用 Flex WindowedApplication 组件时,必须将 WindowedApplication 标记的 visible 属性设置为 false。该属性取代 了应用程序描述符中的设置。 注: 该示例假设应用程序的 icons 子目录中存在名为 AIRApp_16.png 和 AIRApp_128.png 的图像文件。(示例图标文件包含在 AIR SDK 中,您可以将这些文件复制到项目文件夹中。)125ADOBE AIR HTML 开发人员指南 AIR 中的任务栏图标 上次更新 2011/10/13 Window 任务栏图标和按钮 Adobe AIR 1.0 和更高版本 窗口的图标化表示形式通常显示在任务栏或停靠栏的窗口区域中,以便用户能够轻松访问后台窗口或最小化的窗口。 Mac OS X 停靠栏会为您的应用程序显示一个图标,并为每个最小化的窗口分别显示一个图标。 Microsoft Windows 和 Linux 任务栏 显示一个按钮,其中包含您的应用程序中每个普通类型窗口的程序图标和标题。 加亮显示任务栏窗口按钮 Adobe AIR 1.0 和更高版本 如果窗口位于后台,则可以通知用户发生了与该窗口相关的需要关注的事件。在 Mac OS X 中,可以通过回弹应用程序的停靠 栏图标来通知用户(如第 123 页的 “ 回弹停靠栏 ” 中所述)。在 Windows 和 Linux 中,可以通过调用 NativeWindow 实例 的 notifyUser() 方法来加亮显示窗口的任务栏按钮。传递给该方法的 type 参数用于确定通知的紧急程度: • NotificationType.CRITICAL:在用户将窗口置于前台之前,窗口图标一直闪烁。 • NotificationType.INFORMATIONAL:通过更改颜色来加亮显示窗口图标。 注: 在 Linux 中,仅支持信息性类型的通知。向 notifyUser() 函数传递任何一种类型值都会产生相同的效果。 以下语句加亮显示窗口的任务栏按钮: window.nativeWindow.notifyUser(air.NotificationType.INFORMATIONAL); 在不支持窗口级别通知的操作系统中,调用 NativeWindow.notifyUser() 方法将不起作用。使用 NativeWindow.supportsNotification 属性可确定是否支持窗口通知。 创建不带任务栏按钮或图标的窗口 Adobe AIR 1.0 和更高版本 在 Windows 操作系统中,使用 utility 或 lightweight 类型创建的窗口不会显示在任务栏中。不可见窗口也不会显示在任务栏 中。 由于初始窗口必定为 normal 类型,因此要创建不会在任务栏中显示任何窗口的应用程序,必须关闭初始窗口或保持初始窗口 不可见。若要关闭应用程序中的所有窗口而不终止应用程序,请在关闭最后一个窗口之前,将 NativeApplication 对象的 autoExit 属性设置为 false。如果只是需要使初始窗口变得不可见,请向应用程序描述符文件的 元素添加 false (且不要将 visible 属性设置为 true 或调用窗口的 activate() 方法)。 在应用程序打开的新窗口中,将传递给窗口构造函数的 NativeWindowInitOption 对象的 type 属性设置为 NativeWindowType.UTILITY 或 NativeWindowType.LIGHTWEIGHT。 在 Mac OS X 中,最小化的窗口显示在停靠任务栏中。通过隐藏窗口而不是最小化窗口可以避免显示最小化的图标。以下示例 侦听 nativeWindowDisplayState 更改事件,并在窗口最小化时取消该事件。处理函数会改为将窗口的 visible 属性设置为 false: function preventMinimize(event){ if(event.afterDisplayState == air.NativeWindowDisplayState.MINIMIZED){ event.preventDefault(); event.target.visible = false; } } 如果将 visible 属性设置为 false 后窗口最小化到 Mac OS X 停靠栏中,则无法删除该停靠栏图标。用户仍可单击图标来重新显 示窗口。126 上次更新 2011/10/13 第 11 章 : 使用文件系统 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 Adobe® AIR® 文件系统 API 提供了对主机的文件系统的完全访问权限。使用这些类,您可以访问和管理目录和文件、创建目 录和文件、向文件中写入数据等。 更多帮助主题 flash.filesystem.File flash.filesystem.FileStream 使用 AIR 文件系统 API Adobe AIR 1.0 和更高版本 Adobe AIR 文件系统 API 包括以下类: • 文件 • FileMode • FileStream 借助该文件系统 API,您可以执行以下操作(以及其他更多操作): • 复制、创建、删除和移动文件和目录 • 获取有关文件和目录的信息 • 读写文件 AIR 文件基础知识 Adobe AIR 1.0 和更高版本 有关在 AIR 中使用文件系统的快速介绍和代码示例,请参阅 Adobe Developer Connection 中的以下快速入门文章: • 构建文本文件编辑器 • 构建目录搜索应用程序 • 从 XML 首选参数文件中读取和写入 您可以使用 Adobe AIR 提供的类访问、创建和管理文件和文件夹。这些类包含在 flash.filesystem 包中,用法如下所示: 您可以使用 Adobe AIR 提供的类访问、创建和管理文件和文件夹。这些类包含在 runtime.flash.filesystem 包中,用法如下 所示:127ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 File 类中的一些方法具有同步版本和异步版本: • File.copyTo() 和 File.copyToAsync() • File.deleteDirectory() 和 File.deleteDirectoryAsync() • File.deleteFile() 和 File.deleteFileAsync() • File.getDirectoryListing() 和 File.getDirectoryListingAsync() • File.moveTo() 和 File.moveToAsync() • File.moveToTrash() 和 File.moveToTrashAsync() 另外,FileStream 操作是以同步方式运行还是以异步方式运行取决于 FileStream 对象打开文件的方式:是通过调用 open() 方 法还是通过调用 openAsync() 方法。 使用异步版本可以启动在后台运行的进程,然后在完成时(或出现错误事件时)调度事件。在运行异步后台进程的同时可以执 行其他代码。使用操作的异步版本时,必须使用调用该函数的 File 或 FileStream 对象的 addEventListener() 方法设置事件侦听 器函数。 使用同步版本可以编写较简单的代码,而无需设置事件侦听器。不过,由于在执行同步方法的同时无法执行其他代码,可能会 延迟重要的进程(如显示对象呈现和动画)。 使用 AIR 中的 File 对象 Adobe AIR 1.0 和更高版本 File 对象是指向文件系统中文件或目录的指针。 File 类扩展了 FileReference 类。 Adobe® Flash® Player 和 AIR 中提供的 FileReference 类表示指向文件的指针。 File 类添 加了一些属性和方法,出于安全方面的考虑,在 Flash Player 中 (在浏览器中运行的 SWF 文件中)未公开这些属性和方法。 关于 File 类 Adobe AIR 1.0 和更高版本 您可以使用 File 类执行以下操作: • 获取特殊目录的路径,包括用户目录、用户的文档目录、应用程序的启动目录以及应用程序目录 • 复制文件和目录 • 移动文件和目录 • 删除文件和目录(或将它们移到垃圾桶) • 列出目录中包含的文件和目录 • 创建临时文件和文件夹 File 类 说明 File File 对象表示文件或目录的路径。您可以使用 file 对象创建指向文件或文件夹的指针,启动与文件或文件夹的交 互。 FileMode FileMode 类定义 FileStream 类的 open() 和 openAsync() 方法的 fileMode 参数中使用的字符串常量。这些方 法的 fileMode 参数确定文件打开后 FileStream 对象可用的功能,包括写入、读取、追加和更新功能。 FileStream FileStream 对象用于打开文件以进行读取和写入。创建了指向新文件或现有文件的 File 对象后,可以将该指针 传递到 FileStream 对象,以便您可以打开该文件并读取或写入数据。 128ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 当 File 对象指向文件路径后,您可以通过 FileStream 类使用该 File 对象读取和写入文件数据。 File 对象可以指向尚不存在的文件或目录的路径。创建文件或目录时可以使用这种 File 对象。 File 对象的路径 Adobe AIR 1.0 和更高版本 每个 File 对象具有两个属性,各属性可分别定义该对象的路径: File 类包括用于指向 Mac OS、 Windows 和 Linux 中的标准目录的静态属性。这些属性包括: • File.applicationStorageDirectory — 每个已安装的 AIR 应用程序独有的存储目录。此目录适用于存储动态应用程序资源和用 户首选项。考虑在其他位置存储大量数据。 • File.applicationDirectory — 安装应用程序的目录(还存储任何安装的资源)。在有些操作系统上,应用程序存储在一个软 件包文件中而不是物理目录中。在这种情况下,可能无法使用本机路径访问内容。应用程序目录是只读的。 • File.desktopDirectory— 用户的桌面目录。如果平台不定义桌面目录,则使用文件系统上的另一个位置。 • File.documentsDirectory— 用户的文档目录。如果平台不定义文档目录,则使用文件系统上的另一个位置。 • File.userDirectory — 用户目录。如果平台不定义用户目录,则使用文件系统上的另一个位置。 注: 当平台不定义桌面、文档或用户目录的标准位置时, File.documentsDirectory、 File.desktopDirectory 和 File.userDirectory 可以引用同一个目录。 这些属性在不同的操作系统上有不同的值。例如,对于用户的桌面目录, Mac 和 Windows 有各自不同的本机路径。然而, File.desktopDirectory 属性在每个平台上指向适当的目录路径。要编写可以跨平台正常工作的应用程序,在需要引用应用程序使 用的其他目录和文件时,请以这些属性为基础,然后使用 resolvePath() 方法来完善路径。例如,此代码会指向应用程序存储目 录中的 preferences.xml 文件: var prefsFile:File = air.File.applicationStorageDirectory; prefsFile = prefsFile.resolvePath("preferences.xml"); 尽管可以使用 File 类来指向特定文件路径,但这种做法会指向无法跨平台工作的应用程序。例如,路径 C:\Documents and Settings\joe\ 仅适用于 Windows。出于以上原因,最好使用 File 类的静态属性,如 File.documentsDirectory。 属性 说明 nativePath 指定文件在特定平台上的路径。例如,在 Windows 中,路径可能是 “c:\Sample directory\test.txt”,而在 Mac OS 中,路径可能是 “/Sample directory/test.txt”。 nativePath 属性在 Windows 中使用反斜杠 (\) 字 符作为目录分隔符,在 Mac OS 和 Linux 中使用正斜杠 (/) 字符。 url 此属性可以使用 file URL 方案指向文件。例如,在 Windows 中,路径可能是 “file:///c:/Sample%20directory/test.txt”,而在 Mac OS 中,路径可能是 “file:///Sample%20directory/test.txt”。除 file 之外,运行时还包括其他特殊 URL 方案,在第 134 页的 “ 支持的 AIR URL 方案 ” 中将予以介绍129ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 公用目录位置 根据具体的操作系统和计算机配置,这些目录的实际本机路径会有所不同。此表中显示的路径是典型示例。您应该始终使用适 当的静态 File 类属性引用这些目录,以便您的应用程序在任何平台上都能正常工作。在一个实际的 AIR 应用程序中,表中显示 的 applicationID 和 filename 的值取自应用程序描述符。如果您在应用程序描述符中指定发布者 ID,则发布者 ID 在这些路径中 会追加到应用程序 ID。 userName 的值是安装用户的帐户名称。 将 File 对象指向目录 Adobe AIR 1.0 和更高版本 可以采用多种不同方式设置 File 对象以使其指向某目录。 指向用户的主目录 Adobe AIR 1.0 和更高版本 您可以将 File 对象指向用户的主目录。以下代码将设置 File 对象以使其指向主目录中的 AIR Test 子目录: var file = air.File.userDirectory.resolvePath("AIR Test"); 指向用户的文档目录 Adobe AIR 1.0 和更高版本 您可以将 File 对象指向用户的文档目录。以下代码设置 File 对象以指向文档目录中的 AIR Test 子目录: 平台 目录类型 典型的文件系统位置 Linux 应用程序 /opt/filename/share 应用程序存储 /home/userName/.appdata/applicationID/Local Store 桌面 /home/userName/Desktop 文档 /home/userName/Documents 临时 /tmp/FlashTmp.randomString 用户 /home/userName Mac 应用程序 /Applications/filename.app/Contents/Resources 应用程序存储 /Users/userName/Library/Preferences/applicationID/Local Store 桌面 /Users/userName/Desktop 文档 /Users/userName/Documents 临时 /private/var/folders/JY/randomString/TemporaryItems/FlashTmp 用户 /Users/userName Windows 应用程序 C:\Program Files\filename 应用程序存储 C:\Documents and settings\userName\ApplicationData\applicationID\Local Store 桌面 C:\Documents and settings\userName\Desktop 文档 C:\Documents and settings\userName\My Documents 临时 C:\Documents and settings\userName\Local Settings\Temp\randomString.tmp 用户 C:\Documents and settings\userName130ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 var file = air.File.documentsDirectory.resolvePath("AIR Test"); 指向桌面目录 Adobe AIR 1.0 和更高版本 您可以使 File 对象指向桌面。以下代码设置 File 对象以使其指向桌面的 AIR Test 子目录: var file = air.File.desktopDirectory.resolvePath("AIR Test"); 指向应用程序存储目录 Adobe AIR 1.0 和更高版本 您可以使 File 对象指向应用程序存储目录。对于每个 AIR 应用程序,有一个唯一的关联路径用于定义应用程序存储目录。此 目录对每个应用程序和用户是唯一的。您可以使用此目录存储特定于用户、特定于应用程序的数据(如用户数据或首选参数文 件)。例如,以下代码将使 File 对象指向应用程序存储目录中包含的首选参数文件 prefs.xml: var file = air.File.applicationStorageDirectory; file = file.resolvePath("prefs.xml"); 应用程序存储目录位置通常基于用户名称和应用程序 ID。此处提供了下列文件系统位置以帮助您调试应用程序。您应该始终使 用 File.applicationStorage 属性或 app-storage: URI 方案解析此目录中的文件: • 在 Mac OS 中,位于: /Users/user name/Library/Preferences/applicationID/Local Store/ 例如: /Users/babbage/Library/Preferences/com.example.TestApp/Local Store • 在 Windows 中,位于 Documents and Settings 目录下的以下位置: C:\Documents and Settings\user name\Application Data\applicationID\Local Store\ 例如: C:\Documents and Settings\babbage\Application Data\com.example.TestApp\Local Store • 在 Linux 中位于: /home/user name/.appdata/applicationID/Local Store/ 例如: /home/babbage/.appdata/com.example.TestApp/Local Store 注: 如果应用程序具有发行商 ID,则还可将该 ID 用作应用程序存储目录路径的一部分。 通过 File.applicationStorageDirectory 创建的 File 对象的 URL (和 url 属性)将使用 app-storage URL 方案(请参阅第 134 页 的 “ 支持的 AIR URL 方案 ”),如下所示: var dir = air.File.applicationStorageDirectory; dir = dir.resolvePath("prefs.xml"); air.trace(dir.url); // app-storage:/preferences 指向应用程序目录 Adobe AIR 1.0 和更高版本 您可以使 File 对象指向应用程序的安装目录,即应用程序目录。您可以使用 File.applicationDirectory 属性引用此目录。您可以 使用此目录检查应用程序描述符文件或与应用程序一起安装的其他资源。例如,以下代码将使 File 对象指向应用程序目录中名 为 images 的目录:131ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 var dir = air.File.applicationDirectory; dir = dir.resolvePath("images"); 通过 File.applicationDirectory 创建的 File 对象的 URL (和 url 属性)将使用 app URL 方案(请参阅第 134 页的 “ 支持的 AIR URL 方案 ”),如下所示: var dir = air.File.applicationDirectory; dir = dir.resolvePath("images"); air.trace(dir.url); // app:/images 指向文件系统根目录 Adobe AIR 1.0 和更高版本 File.getRootDirectories() 方法列出所有根卷,如 Windows 计算机中的 C: 和已装好的卷。在 Mac OS 和 Linux 中,此方法始 终返回计算机的唯一根目录( “/” 目录)。 StorageVolumeInfo.getStorageVolumes() 方法提供有已关装的存储卷的更多详细信息 (请参阅第 142 页的 “ 使用存储卷 ”)。 指向明确的目录 Adobe AIR 1.0 和更高版本 通过设置 File 对象的 nativePath 属性,可以使 File 对象指向某个明确的目录,如以下示例中所示(在 Windows 中): var file = new air.File(); file.nativePath = "C:\\AIR Test"; 重要说明:通过这种方式指向明确的路径会导致代码无法跨平台使用。例如,上面的示例仅适用于 Windows。您可以使用 File 类的静态属性(如 File.applicationStorageDirectory)来定位跨平台工作的目录。然后使用 resolvePath() 方法(请参阅下一 节)导航到相对路径。 导航到相对路径 Adobe AIR 1.0 和更高版本 您可以使用 resolvePath() 方法获取相对于其他给定路径的路径。例如,以下代码将设置 File 对象以使其指向用户主目录中的 “AIR Test” 子目录: var file = air.File.userDirectory; file = file.resolvePath("AIR Test"); 您还可以使用 File 对象的 url 属性以使该对象指向基于 URL 字符串的目录,如下所示: var urlStr = "file:///C:/AIR Test/"; var file = new air.File() file.url = urlStr; 有关详细信息,请参阅第 133 页的 “ 修改文件路径 ”。 让用户浏览以选择目录 Adobe AIR 1.0 和更高版本 File 类包括 browseForDirectory() 方法,它表示系统对话框,在该对话框中用户可以选择要分配给对象的目录。 browseForDirectory() 方法为异步方法。如果用户选择一个目录并单击 “ 打开 ” 按钮,File 对象将调度一个 select 事件;如果用 户单击 “ 取消 ” 按钮,它将调度一个 cancel 事件。 例如,以下代码能使用户选择一个目录,并在选择后输出目录路径:132ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 var file = new air.File(); file.addEventListener(air.Event.SELECT, dirSelected); file.browseForDirectory("Select a directory"); function dirSelected(event) { alert(file.nativePath); } 指向从中调用应用程序的目录 Adobe AIR 1.0 和更高版本 通过检查调用应用程序时所调度的 InvokeEvent 对象的 currentDirectory 属性,可以获取从中调用应用程序的目录位置。有关 详细信息,请参阅第 255 页的 “ 捕获命令行参数 ”。 将 File 对象指向文件 Adobe AIR 1.0 和更高版本 可采用多种不同方式设置 File 对象所指向的文件。 指向明确的文件路径 Adobe AIR 1.0 和更高版本 重要说明:指向明确的路径会导致代码无法跨平台工作。例如,路径 C:/foo.txt 仅适用于 Windows。您可以使用 File 类的静 态属性(如 File.applicationStorageDirectory)来定位跨平台工作的目录。然后使用 resolvePath() 方法(请参阅第 133 页的 “ 修改文件路径 ”)导航到相对路径。 您可以使用 File 对象的 url 属性以使该对象指向基于 URL 字符串的文件或目录,如下所示: var urlStr = "file:///C:/AIR Test/test.txt"; var file = new air.File() file.url = urlStr; 您还可以将 URL 传递到 File() 构造函数,如下所示: var urlStr = "file:///C:/AIR Test/test.txt"; var file = new air.File(urlStr); url 属性始终返回 URL 的 URI 编码版本(例如,空格替换为 %20): file.url = "file:///c:/AIR Test"; alert(file.url); // file:///c:/AIR%20Test 您还可以使用 File 对象的 nativePath 属性设置明确的路径。例如,在 Windows 计算机中运行以下代码,可以设置 File 对象以 使其指向 C: 驱动器的 AIR Test 子目录中的 test.txt 文件: var file = new air.File(); file.nativePath = "C:/AIR Test/test.txt"; 您还可以将此路径传递到 File() 构造函数,如下所示: var file = new air.File("C:/AIR Test/test.txt"); 请使用正斜杠 (/) 字符作为 nativePath 属性的路径分隔符。在 Windows 上,还可以使用反斜杠 (\) 字符,但这会导致应用程序 无法跨平台工作。 有关详细信息,请参阅第 133 页的 “ 修改文件路径 ”。 133ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 枚举目录中的文件 Adobe AIR 1.0 和更高版本 您可以使用 File 对象的 getDirectoryListing() 方法获取指向位于某目录根级的文件和子目录的 File 对象数组。有关详细信息, 请参阅第 138 页的 “ 枚举目录 ”。 让用户浏览以选择文件 Adobe AIR 1.0 和更高版本 File 类包括以下方法,它们表示系统对话框,在该对话框中用户可以选择要分配给对象的文件: • browseForOpen() • browseForSave() • browseForOpenMultiple() 这些方法均为异步方法。当用户选择一个文件时(或者,对于 browseForSave() 选择一个目标路径时), browseForOpen() 和 browseForSave() 方法将调度 select 事件。对 browseForOpen() 和 browseForSave() 方法,在进行选择后目标 File 对象将指向所 选的文件。当用户选择多个文件时, browseForOpenMultiple() 方法调度一个 selectMultiple 事件。selectMultiple 事件的类型是 FileListEvent,它具有一个 files 属性,该属性是一个 File 对象数组(指向所选的文件)。 例如,以下代码向用户显示 “Open” 对话框,在该对话框中用户可以选择文件: var fileToOpen = air.File.documentsDirectory; selectTextFile(fileToOpen); function selectTextFile(root) { var txtFilter = new air.FileFilter("Text", "*.as;*.css;*.html;*.txt;*.xml"); root.browseForOpen("Open", new window.runtime.Array(txtFilter)); root.addEventListener(air.Event.SELECT, fileSelected); } function fileSelected(event) { trace(fileToOpen.nativePath); } 当您调用浏览方法时,如果应用程序已打开了其他浏览器对话框,则运行时会引发一个错误异常。 修改文件路径 Adobe AIR 1.0 和更高版本 通过调用 resolvePath() 方法或通过修改对象的 nativePath 或 url 属性,您还可以修改现有 File 对象的路径,如以下示例中所示 (在 Windows 中): file1 = air.File.documentsDirectory; file1 = file1.resolvePath("AIR Test"); alert(file1.nativePath); // C:\Documents and Settings\userName\My Documents\AIR Test var file2 = air.File.documentsDirectory; file2 = file2.resolvePath(".."); alert(file2.nativePath); // C:\Documents and Settings\userName var file3 = air.File.documentsDirectory; file3.nativePath += "/subdirectory"; alert(file3.nativePath); // C:\Documents and Settings\userName\My Documents\subdirectory var file4 = new air.File(); file4.url = "file:///c:/AIR Test/test.txt"; alert(file4.nativePath); // C:\AIR Test\test.txt134ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 使用 nativePath 属性时,请使用正斜杠 (/) 字符作为目录分隔符。在 Windows 上,还可以使用反斜杠 (\) 字符,但不应这样 做,因为这会导致代码无法跨平台工作。 支持的 AIR URL 方案 Adobe AIR 1.0 和更高版本 在 AIR 中定义 File 对象的 url 属性时,可以使用以下任一 URL 方案: 查找两个文件之间的相对路径 Adobe AIR 1.0 和更高版本 您可以使用 getRelativePath() 方法查找两个文件之间的相对路径: var file1 = air.File.documentsDirectory file1 = file1.resolvePath("AIR Test"); var file2 = air.File.documentsDirectory file2 = file2.resolvePath("AIR Test/bob/test.txt"); alert(file1.getRelativePath(file2)); // bob/test.txt getRelativePath() 方法的第二个参数 useDotDot 允许在结果中返回 .. 语法,以指示父目录: var file1 = air.File.documentsDirectory; file1 = file1.resolvePath("AIR Test"); var file2 = air.File.documentsDirectory; file2 = file2.resolvePath("AIR Test/bob/test.txt"); var file3 = air.File.documentsDirectory; file3 = file3.resolvePath("AIR Test/susan/test.txt"); alert(file2.getRelativePath(file1, true)); // ../.. alert(file3.getRelativePath(file2, true)); // ../../bob/test.txt 获取文件名的规范版本 Adobe AIR 1.0 和更高版本 文件名和路径名在 Windows 和 Mac OS 中不区分大小写。在以下示例中,两个 File 对象指向同一个文件: File.documentsDirectory.resolvePath("test.txt"); File.documentsDirectory.resolvePath("TeSt.TxT"); URL 方案 说明 file 用于指定相对于文件系统根目录的路径。例如: file:///c:/AIR Test/test.txt URL 标准规定 file URL 采用 file:/// 形式。作为一个特例, 可以是空字符串,它被解释为 “ 解释该 URL 的计算机 ”。因此, file URL 通常具有三个斜杠 (///)。 app 用于指定相对于所安装应用程序的根目录(该目录包含所安装应用程序的 application.xml 文件)的路径。例如, 以下路径指向所安装应用程序的目录的 images 子目录: app:/images app-storage 用于指定相对于应用程序存储目录的路径。对于每个安装的应用程序, AIR 定义了一个唯一的应用程序存储目录, 此目录对于存储特定于该应用程序的数据很有用。例如,以下路径指向应用程序存储目录的 settings 子目录中的 prefs.xml 文件: app-storage:/settings/prefs.xml135ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 不过,文档和目录名确实包括大小写。例如,以下代码假定在文档目录中有一个名为 AIR Test 的文件夹,如以下示例中所示: var file = air.File.documentsDirectory; file = file.resolvePath("AIR test"); trace(file.nativePath); // ... AIR test file.canonicalize(); alert(file.nativePath); // ... AIR Test canonicalize() 方法可以转换 nativePath 对象,以使用文件名或目录名的正确大写形式。在区分大小写的文件系统(如 Linux) 上,当多个文件的名称只有大小写不同时, canonicalize() 方法将调整路径以匹配最先找到的文件(以文件系统确定的顺序)。 在 Windows 中,您还可以使用 canonicalize() 方法将短文件名( “8.3” 名称)转换为长文件名,如以下示例中所示: var path = new air.File(); path.nativePath = "C:\\AIR~1"; path.canonicalize(); alert(path.nativePath); // C:\AIR Test 使用包和符号链接 Adobe AIR 1.0 和更高版本 多种操作系统支持包文件和符号链接文件: 包 — 在 Mac OS 中,可以指定目录作为包,并且目录可以作为单个文件而非目录出现在 Mac OS Finder 中。 符号链接 — Mac OS、 Linux 和 Windows Vista 支持符号链接。通过符号链接,文件可以指向磁盘上的另一个文件或目录。 尽管符号链接与别名类似,不过它们并不相同。别名始终报告为文件(而不是目录),读取或写入别名或快捷方式从不影响它 指向的原始文件或目录。另一方面,符号链接的行为则完全与它指向的文件或目录类似。可以将符号链接报告为文件或目录, 并且读写符号链接影响的是符号链接所指向的文件或目录,而不影响其本身。此外,在 Windows 中,引用交接点(用于 NTFS 文件系统中)的 File 对象的 isSymbolicLink 属性设置为 true。 File 类包括 isPackage 和 isSymbolicLink 属性,用于检查 File 对象是否引用包或符号链接。 以下代码将遍历用户的桌面目录,列出不是 包的子目录: var desktopNodes = air.File.desktopDirectory.getDirectoryListing(); for (i = 0; i < desktopNodes.length; i++) { if (desktopNodes[i].isDirectory && !!desktopNodes[i].isPackage) { air.trace(desktopNodes[i].name); } } 以下代码将遍历户的桌面目录,列出不是 符号链接的文件和目录: var desktopNodes = air.File.desktopDirectory.getDirectoryListing(); for (i = 0; i < desktopNodes.length; i++) { if (!desktopNodes[i].isSymbolicLink) { air.trace(desktopNodes[i].name); } } canonicalize() 方法可更改符号链接的路径,以指向该链接所引用的文件或目录。以下代码将遍历用户的桌面目录,报告由是符 号链接的文件引用的路径:136ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 var desktopNodes = air.File.desktopDirectory.getDirectoryListing(); for (i = 0; i < desktopNodes.length; i++) { if (desktopNodes[i].isSymbolicLink) { var linkNode = desktopNodes[i]; linkNode.canonicalize(); air.trace(desktopNodes[i].name); } } 确定卷上的可用空间 Adobe AIR 1.0 和更高版本 File 对象的 spaceAvailable 属性是 File 位置的可用空间(以字节为单位)。例如,以下代码检查应用程序存储目录中的可用空 间: air.trace(air.File.applicationStorageDirectory.spaceAvailable); 如果 File 对象引用一个目录,则 spaceAvailable 属性将指示可供文件使用的目录空间。如果 File 对象引用一个文件,则 spaceAvailable 属性将指示可供该文件使用的空间。如果 File 位置不存在,则 spaceAvailable 属性将设置为 0。如果 File 对象引 用一个符号链接,则 spaceAvailable 属性将设置为符号链接指向的位置的可用空间。 通常,目录或文件的可用空间与包含该目录或文件的卷上的可用空间相同。不过,可用空间与磁盘配额及每个目录的空间限制 有关。 将文件或目录添加到卷中通常需要比文件的实际大小或目录中内容的实际大小更多的空间。例如,操作系统可能需要更多空间 来存储索引信息。或者,所需的磁盘扇区可能会使用额外的空间。此外,可用空间是动态变化的。因此,您不能期望为文件存 储分配报告的全部空间。有关写入文件系统的信息,请参阅第 143 页的 “ 读取和写入文件 ”。 StorageVolumeInfo.getStorageVolumes() 方法提供有已关装的存储卷的更多详细信息(请参阅第 142 页的 “ 使用存储卷 ”)。 使用默认系统应用程序打开文件 Adobe AIR 2 和更高版本 在 AIR 2 中,您可以使用操作系统注册的用来打开某文件的应用程序打开该文件。例如, AIR 应用程序可以使用注册的用来打 开文档文件的应用程序打开一个文档文件。使用 File 对象的 openWithDefaultApplication() 方法打开该文件。例如,以下代码 打开用户桌面上名为 test.doc 的文件,并且打开该文件所用的是与文档文件相对应的默认应用程序: var file = air.File.deskopDirectory; file = file.resolvePath("test.doc"); file.openWithDefaultApplication(); 注: 在 Linux 中,文件的 MIME 类型(而不是文件扩展名)确定文件的默认应用程序。 以下代码使用户可以导航到一个 mp3 文件,并在用于播放 mp3 文件的默认应用程序中打开它: var file = air.File.documentsDirectory; var mp3Filter = new air.FileFilter("MP3 Files", "*.mp3"); file.browseForOpen("Open", [mp3Filter]); file.addEventListener(Event.SELECT, fileSelected); function fileSelected(event) { file.openWithDefaultApplication(); } 无法对位于应用程序目录中的文件使用 openWithDefaultApplication() 方法。137ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 AIR 会阻止您使用 openWithDefaultApplication() 方法打开某些文件。在 Windows 中, AIR 会阻止您打开某些文件类型的文 件,例如 EXE 或 BAT。在 Mac OS 和 Linux 中,AIR 阻止您打开将在某些应用程序中启动的文件。(其中包括 Mac OS 中的 Terminal 和 AppletLauncher 以及 Linux 中的 csh、bash 或 ruby。)尝试使用 openWithDefaultApplication() 方法打开其中 一个文件将导致异常。有关阻止打开的文件类型的完整列表,请参阅 File.openWithDefaultApplication() 方法的语言参考条目。 注: 对于使用本机安装程序(一种扩展桌面应用程序)安装的 AIR 应用程序不存在这种限制。 获取文件系统信息 Adobe AIR 1.0 和更高版本 File 类包括以下可提供有关文件系统的一些有用信息的静态属性: Capabilities 类还包括有用的系统信息,在使用文件时这些信息可能很有用: 注: 使用 Capabilities.os 确定系统特性时,应务必小心。如果有更加具体的属性可用来确定系统特性,请使用该属性。否则,您 可能面临所写代码无法在所有平台上正常工作的风险。例如,请看以下代码: var separator:String; if (Capablities.os.indexOf("Mac") > -1) { separator = "/"; } else { separator = "\\"; } 此代码会导致 Linux 上出现问题。最好只使用 File.separator 属性。 使用目录 Adobe AIR 1.0 和更高版本 通过运行时提供的功能,可以使用本地文件系统上的目录。 有关创建指向目录的 File 对象的详细信息,请参阅第 129 页的 “ 将 File 对象指向目录 ”。 属性 说明 File.lineEnding 主机操作系统使用的行结束字符序列。在 Mac OS 和 Linux 中,这是换行符。在 Windows 中,它是回车符 后跟换行符。 File.separator 主机操作系统的路径组件分隔符。在 Mac OS 和 Linux 中,这是正斜杠 (/) 字符。在 Windows 中,它是反 斜杠 (\) 字符。 File.systemCharset 主机操作系统为文件使用的默认编码。此属性与操作系统使用的字符集有关,与操作系统语言相对应。 属性 说明 Capabilities.hasIME 指定播放器是在安装有 (true) 输入法编辑器 (IME) 的系统上运行,还是在未安装 (false) IME 的系统上运 行。 Capabilities.language 指定运行播放器的系统的语言代码。 Capabilities.os 指定当前的操作系统。 138ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 创建目录 Adobe AIR 1.0 和更高版本 使用 File.createDirectory() 方法可以创建目录。例如,以下代码创建名为 AIR Test 的目录以作为用户主目录的子目录: var dir = air.File.userDirectory.resolvePath("AIR Test"); dir.createDirectory(); 如果该目录存在, createDirectory() 方法不执行任何操作。 另外,在某些模式中, FileStream 对象在打开文件时会创建目录。如果 FileStream() 构造函数的 fileMode 参数设置为 FileMode.APPEND 或 FileMode.WRITE,则在实例化 FileStream 实例时将创建缺少的目录。有关详细信息,请参阅第 143 页 的 “ 读取和写入文件的工作流程 ”。 创建临时目录 Adobe AIR 1.0 和更高版本 File 类包括一个 createTempDirectory() 方法,该方法可在系统的临时目录文件夹中创建一个目录,如以下示例中所示: var temp = air.File.createTempDirectory(); createTempDirectory() 方法会自动创建一个唯一的临时目录(您无需确定新的唯一位置)。 您可以使用临时目录暂时存储应用程序会话中使用的临时文件。请注意,有一个 createTempFile() 方法可以在系统临时目录中 创建新的、唯一的临时文件。 您可能需要在关闭应用程序前删除临时目录,因为不会 在所有设备上自动删除临时目录。 枚举目录 Adobe AIR 1.0 和更高版本 您可以使用 File 对象的 getDirectoryListing() 方法或 getDirectoryListingAsync() 方法获取指向目录中的文件和子文件夹的 File 对象数组。 例如,以下代码将列出用户的文档目录的内容(无需检查子目录): var directory = air.File.documentsDirectory; var contents = directory.getDirectoryListing(); for (i = 0; i < contents.length; i++) { alert(contents[i].name, contents[i].size); } 当使用该方法的异步版本时, directoryListing 事件对象具有一个 files 属性,该属性是与目录有关的 File 对象数组: var directory = air.File.documentsDirectory; directory.getDirectoryListingAsync(); directory.addEventListener(air.FileListEvent.DIRECTORY_LISTING, dirListHandler); function dirListHandler(event) { var contents = event.files; for (i = 0; i < contents.length; i++) { alert(contents[i].name, contents[i].size); } }139ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 复制和移动目录 Adobe AIR 1.0 和更高版本 您可以使用与复制或移动文件相同的方法复制或移动目录。例如,以下代码将以同步方式复制目录: var sourceDir = air.File.documentsDirectory.resolvePath("AIR Test"); var resultDir = air.File.documentsDirectory.resolvePath("AIR Test Copy"); sourceDir.copyTo(resultDir); 当您将 copyTo() 方法的 overwrite 参数指定为 true 时,现有目标目录中的所有文件和文件夹都将删除,并替换为源目录中的文 件和文件夹(即使在源目录中目标文件不存在)。 指定为 copyTo() 方法的 newLocation 参数的目录将指定所生成的目录的路径,它不 指定将包含所生成的目录的父 目录。 有关详细信息,请参阅第 140 页的 “ 复制和移动文件 ”。 删除目录内容 Adobe AIR 1.0 和更高版本 File 类包括一个 deleteDirectory() 方法和一个 deleteDirectoryAsync() 方法。这些方法删除目录,第一个方法以同步方式运行, 第二个方法以异步方式运行(请参阅 第 126 页的 “AIR 文件基础知识 ”)。两个方法都包括一个 deleteDirectoryContents 参数 (该参数取布尔值);当此参数设置为 true 时 (默认值为 false),调用该方法将删除非空目录;否则,只删除空目录。 例如,以下代码以同步方式删除用户的文档目录中的 AIR Test 子目录: var directory = air.File.documentsDirectory.resolvePath("AIR Test"); directory.deleteDirectory(true); 以下代码以异步方式删除用户的文档目录中的 AIR Test 子目录: var directory = air.File.documentsDirectory.resolvePath("AIR Test"); directory.addEventListener(air.Event.COMPLETE, completeHandler) directory.deleteDirectoryAsync(true); function completeHandler(event) { alert("Deleted.") } 此外,还包括 moveToTrash() 和 moveToTrashAsync() 方法,您可以使用这些方法将目录移到系统垃圾桶。有关详细信息,请 参阅第 141 页的 “ 将文件移到垃圾桶 ”。 使用文件 Adobe AIR 1.0 和更高版本 使用 AIR 文件 API,您可以向应用程序中添加基本的文件交互功能。例如,您可以读取和写入文件、复制和删除文件等。由 于您的应用程序可以访问本地文件系统,因此请参阅 第 60 页的 “AIR 安全性 ” (如果您还没有阅读该章节)。 注: 您可以将文件类型与 AIR 应用程序相关联(以便双击时可以打开应用程序)。有关详细信息,请参阅第 261 页的 “ 管理文 件关联 ”。 获取文件信息 Adobe AIR 1.0 和更高版本 File 类包括以下属性,这些属性提供有关 File 对象指向的文件或目录的信息:140ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 有关这些属性的详细信息,请参阅针对 HTML 开发人员的 Adobe AIR API 参考中的 File 类条目。 复制和移动文件 Adobe AIR 1.0 和更高版本 File 类包括两个用于复制文件或目录的方法:copyTo() 和 copyToAsync()。 File 类包括两个用于移动文件或目录的方法: moveTo() 和 moveToAsync()。copyTo() 和 moveTo() 方法以同步方式运行,copyToAsync() 和 moveToAsync() 方法以异步方式 运行(请参阅 第 126 页的 “AIR 文件基础知识 ”)。 若要复制或移动文件,请设置两个 File 对象。一个对象指向要复制或移动的文件,它是调用复制或移动方法的对象;另一个对 象指向目标(结果)路径。 以下代码将 test.txt 文件从用户的文档目录的 AIR Test 子目录复制到同一目录中名为 copy.txt 的文件: var original = air.File.documentsDirectory.resolvePath("AIR Test/test.txt"); var newFile = air.File.documentsDirectory.resolvePath("AIR Test/copy.txt"); original.copyTo(newFile, true); 在此例中,copyTo() 方法的 overwrite 参数(第二个参数)的值设置为 true。通过将 overwrite 设置为 true,可以覆盖现有目标 文件。此参数是可选的。如果您将它设置为 false (默认值),则当目标文件存在时该操作调度一个 IOErrorEvent 事件(文件 没有复制)。 File 属性 说明 creationDate 本地磁盘上文件的创建日期。 creator 已废弃。请使用 extension 属性。(此属性报告文件的 Macintosh 创建者类型,此属性仅用于 Mac OS X 之前 的 Mac OS 版本中。) downloaded (AIR 2 和更高版本)指示是否已(从 Internet)下载引用的文件或目录。属性仅在文件可以标记为已下载的 操作系统上有意义: • Windows XP Service Pack 2 和更高版本,在 Windows Vista 上 • Mac OS 10.5 和更高版本 exists 引用的文件或目录是否存在。 extension 文件扩展名,它是最后一个句点( “.”)后面的名称部分(不包括句点)。如果文件名中没有句点,则 extension 为 null。 icon 包含为文件定义的图标的 Icon 对象。 isDirectory File 对象引用是否为对目录的引用。 modificationDate 本地磁盘上文件或目录的上一次修改日期。 name 本地磁盘上文件或目录的名称(如果存在文件扩展名,则包括文件扩展名) 。 nativePath 采用主机操作系统表示形式的完整路径。请参阅 第 128 页的 “File 对象的路径 ”。 parent 包含由 File 对象表示的文件夹或文件的文件夹。如果 File 对象引用的是文件系统根目录中的文件或目录,此属 性为 null。 size 本地磁盘上文件的大小(以字节为单位) 。 type 已废弃。请使用 extension 属性。(在 Macintosh 中,此属性是四个字符的文件类型,它仅用于 Mac OS X 之 前的 Mac OS 版本中。) url 文件或目录的 URL。请参阅 第 128 页的 “File 对象的路径 ”。141ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 复制和移动方法的 “ 异步 ” 版本以异步方式运行。使用 addEventListener() 方法可以监视任务是否完成或错误条件,如以下代码 中所示: var original = air.File.documentsDirectory; original = original.resolvePath("AIR Test/test.txt"); var destination = air.File.documentsDirectory; destination = destination.resolvePath("AIR Test 2/copy.txt"); original.addEventListener(air.Event.COMPLETE, fileMoveCompleteHandler); original.addEventListener(air.IOErrorEvent.IO_ERROR, fileMoveIOErrorEventHandler); original.moveToAsync(destination); function fileMoveCompleteHandler(event){ alert(event.target); // [object File] } function fileMoveIOErrorEventHandler(event) { alert("I/O Error."); } File 类还包括 File.moveToTrash() 和 File.moveToTrashAsync() 方法,它们将文件或目录移到系统垃圾桶。 删除文件 Adobe AIR 1.0 和更高版本 File 类包括一个 deleteFile() 方法和一个 deleteFileAsync() 方法。这些方法删除文件,第一个方法以同步方式运行,第二个方法 以异步方式运行(请参阅 第 126 页的 “AIR 文件基础知识 ”)。 例如,以下代码以同步方式删除用户的文档目录中的 test.txt 文件: var file = air.File.documentsDirectory.resolvePath("test.txt"); file.deleteFile(); 以下代码以异步方式删除用户的文档目录中的 test.txt 文件: var file = air.File.documentsDirectory.resolvePath("test.txt"); file.addEventListener(air.Event.COMPLETE, completeHandler) file.deleteFileAsync(); function completeHandler(event) { alert("Deleted.") } 此外,还包括 moveToTrash() 和 moveToTrashAsync 方法,您可以使用这些方法将文件或目录移到系统垃圾桶。有关详细信 息,请参阅第 141 页的 “ 将文件移到垃圾桶 ”。 将文件移到垃圾桶 Adobe AIR 1.0 和更高版本 File 类包括一个 moveToTrash() 方法和一个 moveToTrashAsync() 方法。这些方法将文件或目录发送到系统垃圾桶,第一个方 法以同步方式运行,第二个方法以异步方式运行(请参阅 第 126 页的 “AIR 文件基础知识 ”)。 例如,以下代码以同步方式将用户的文档目录中的 test.txt 文件移到系统垃圾桶: var file = air.File.documentsDirectory.resolvePath("test.txt"); file.moveToTrash(); 注: 在不支持可恢复垃圾桶文件夹概念的操作系统上,会立即删除文件。142ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 创建临时文件 Adobe AIR 1.0 和更高版本 File 类包括一个 createTempFile() 方法,该方法在系统的临时目录文件夹中创建一个文件,如以下示例中所示: var temp = air.File.createTempFile(); createTempFile() 方法会自动创建一个唯一的临时文件(您无需确定新的唯一位置)。 您可以使用临时文件暂时存储应用程序会话中使用的信息。请注意,还有一个 createTempDirectory() 方法可以在系统临时目录 中创建唯一的临时目录。 您可能需要在关闭应用程序前删除临时文件,因为不会 在所有设备上自动删除临时文件。 使用存储卷 Adobe AIR 2 和更高版本 在 AIR 2 中,安装或卸载大容量存储卷时,您可以进行检测。 StorageVolumeInfo 类定义单个 storageVolumeInfo 对象。 StorageVolumeInfo.storageVolumeInfo 对象在存储卷安装之后调度 storageVolumeMount 事件。它在某个卷被卸载时调度 storageVolumeUnmount 事件。 StorageVolumeChangeEvent 类定义这些事件。 注: 在现今的 Linux 发行版中, StorageVolumeInfo 对象仅对在特定位置装载的物理设备和网络驱动器调度 storageVolumeMount 和 storageVolumeUnmount 事件。 StorageVolumeChangeEvent 类的 storageVolume 属性是一个 StorageVolume 对象。 StorageVolume 类定义存储卷的基 本属性: • drive — Windows 上的卷驱动器号(在其他操作系统上为 null) • fileSystemType — 存储卷上的文件系统的类型(如 “FAT”、 “NTFS”、 “HFS” 或 “UFS”) • isRemoveable — 卷是可删除(为 true)还是不可删除(为 false) • isWritable — 卷可写入 (true) 还是不可写入 (false) • name — 卷的名称 • rootDirectory — 与卷的根目录对应的 File 对象 StorageVolumeChangeEvent 类还包括一个 rootDirectory 属性。rootDirectory 属性是一个引用已装载或已卸载的存储卷的根 目录的 File 对象。 对于卸载的卷,未定义 StorageVolumeChangeEvent 对象的 storageVolume 属性 (null)。然而,您可以访问此事件的 rootDirectory 的属性。 以下代码在安装完存储卷之后输出该存储卷的名称和文件路径: air.StorageVolumeInfo.storageVolumeInfo.addEventListener(air.StorageVolumeChangeEvent.STORAGE_VOLUME_MOUN T, onVolumeMount); function onVolumeMount(event) { air.trace(event.storageVolume.name, event.rootDirectory.nativePath); } 以下代码在卸载完存储卷之后输出该存储卷的文件路径: air.StorageVolumeInfo.storageVolumeInfo.addEventListener(air.StorageVolumeChangeEvent.STORAGE_VOLUME_UNMO UNT, onVolumeUnmount); function onVolumeUnmount(event) { air.trace(event.rootDirectory.nativePath); }143ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 StorageVolumeInfo.storageVolumeInfo 对象包含 getStorageVolumes() 方法。此方法返回与当前安装的存储卷对应的 StorageVolume 对象的矢量。以下代码显示如何列出所有安装的存储卷的名称和根目录: var volumes = air.StorageVolumeInfo.storageVolumeInfo.getStorageVolumes(); for (i = 0; i < volumes.length; i++) { air.trace(volumes[i].name, volumes[i].rootDirectory.nativePath); } 注: 在现今的 Linux 发行版中, getStorageVolumes() 方法返回与在特定位置安装的物理设备和网络驱动器相对应的对象。 File.getRootDirectories() 方法列出根目录(请参阅第 131 页的 “ 指向文件系统根目录 ”)。然而, StorageVolume 对象(由 StorageVolumeInfo.getStorageVolumes() 方法枚举)提供有关存储卷的详细信息。 可使用 StorageVolume 对象的 rootDirectory 属性的 spaceAvailable 属性查看存储卷上的可用空间。(请参阅第 136 页的 “ 确 定卷上的可用空间 ”。) 更多帮助主题 StorageVolume StorageVolumeInfo 读取和写入文件 Adobe AIR 1.0 和更高版本 FileStream 类允许 AIR 应用程序读取和写入文件系统。 读取和写入文件的工作流程 Adobe AIR 1.0 和更高版本 读取和写入文件的工作流程如下所示。 初始化指向路径的 File 对象。 File 对象表示您要使用的文件(或您以后将创建的文件)的路径。 var file = air.File.documentsDirectory; file = file.resolvePath("AIR Test/testFile.txt"); 此例使用 File 对象的 File.documentsDirectory 属性和 resolvePath() 方法来初始化 File 对象。不过,有许多其他方式可以将 File 对象指向文件。有关详细信息,请参阅第 132 页的 “ 将 File 对象指向文件 ”。 初始化 FileStream 对象。 调用 FileStream 对象的 open() 方法或 openAsync() 方法。 具体调用哪个方法取决于您希望是以同步还是异步方式打开文件。使用 File 对象作为打开方法的 file 参数。对于 fileMode 参 数,请指定 FileMode 类中的一个常量,以指定使用文件的方式。 例如,以下代码将初始化一个 FileStream 对象,该对象用于创建一个文件并覆盖所有现有数据: var fileStream = new air.FileStream(); fileStream.open(file, air.FileMode.WRITE); 有关详细信息,请参阅第 145 页的 “ 初始化 FileStream 对象以及打开和关闭文件 ” 和 第 144 页的 “FileStream 打开模式 ”。144ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 如果您以异步方式打开了文件(使用 openAsync() 方法),请为 FileStream 对象添加并设置事件侦听器。 这些事件侦听器方法响应在各种情形下由 FileStream 对象调度的事件。这些情形包括:从文件读取数据时、遇到 I/O 错误时、 要写入的全部数据量已写入时。 有关详细信息,请参阅第 148 页的 “ 异步编程和以异步方式打开的 FileStream 对象所生成的事件 ”。 根据需要包含用于读取和写入数据的代码。 FileStream 类中有许多与读取和写入相关的方法。(它们都以 “read” 或 “write” 开头。)具体选择使用哪个方法读取或写入数 据取决于目标文件中数据的格式。 例如,如果目标文件中的数据为 UTF 编码的文本,您可以使用 readUTFBytes() 和 writeUTFBytes() 方法。如果您希望将数据作 为字节数组处理,您可以使用 readByte()、 readBytes()、 writeByte() 和 writeBytes() 方法。有关详细信息,请参阅第 149 页的 “ 数据格式以及选择要使用的读取和写入方法 ”。 如果以异步方式打开了文件,请确保在调用读取方法前有足够的可用数据。有关详细信息,请参阅第 147 页的 “ 读取缓冲区和 FileStream 对象的 bytesAvailable 属性 ”。 写入文件之前,如果要检查可用磁盘空间量,您可以检查 File 对象的 spaceAvailable 属性。有关详细信息,请参阅第 136 页 的 “ 确定卷上的可用空间 ”。 当您处理完文件后,请调用 FileStream 对象的 close() 方法。 调用 close() 方法可使文件对其他应用程序可用。 有关详细信息,请参阅第 145 页的 “ 初始化 FileStream 对象以及打开和关闭文件 ”。 若要查看使用 FileStream 类读取和写入文件的范例应用程序,请参阅 Adobe AIR 开发人员中心上的以下文章: • 构建文本文件编辑器 • 构建文本文件编辑器 • 构建文本文件编辑器 • 从 XML 首选参数文件中读取和写入 • 从 XML 首选参数文件中读取和写入 使用 FileStream 对象 Adobe AIR 1.0 和更高版本 FileStream 类定义打开、读取和写入文件的方法。 FileStream 打开模式 Adobe AIR 1.0 和更高版本 FileStream 对象的 open() 和 openAsync() 方法都包括一个 fileMode 参数,该参数定义文件流的一些属性,其中包括以下属性: • 从文件读取的能力 • 写入文件的能力 • 数据是否始终追加到文件的结尾(当写入时) • 当文件不存在时(以及当文件的父目录不存在时)执行哪些操作 以下是各种文件模式(您可以将这些模式指定为 open() 和 openAsync() 方法的 fileMode 参数):145ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 初始化 FileStream 对象以及打开和关闭文件 Adobe AIR 1.0 和更高版本 当您打开 FileStream 对象后,即可使用该对象从文件读取数据和向文件写入数据。通过将 File 对象传递到 FileStream 对象的 open() 或 openAsync() 方法,可以打开 FileStream 对象: var myFile = air.File.documentsDirectory; myFile = myFile.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.open(myFile, air.FileMode.READ); fileMode 参数( open() 和 openAsync() 方法的第二个参数)指定打开文件的模式: read、 write、 append 或 update。有关详 细信息,请参阅上一部分 第 144 页的 “FileStream 打开模式 ”。 如果您使用 openAsync() 方法打开文件进行异步文件操作,请设置事件侦听器以处理异步事件: var myFile = air.File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.addEventListener(air.Event.COMPLETE, completeHandler); myFileStream.addEventListener(air.ProgressEvent.PROGRESS, progressHandler); myFileStream.addEventListener(air.IOErrorEvent.IOError, errorHandler); myFileStream.open(myFile, air.FileMode.READ); function completeHandler(event) { // ... } function progressHandler(event) { // ... } function errorHandler(event) { // ... } 打开文件进行同步操作还是异步操作取决于您使用 open() 方法还是 openAsync() 方法。有关详细信息,请参阅 第 126 页的 “AIR 文件基础知识 ”。 如果您在 FileStream 对象的打开方法中将 fileMode 参数设置为 FileMode.READ 或 FileMode.UPDATE,则当打开 FileStream 对象后数据将立即读入读取缓冲区中。有关详细信息,请参阅第 147 页的 “ 读取缓冲区和 FileStream 对象的 bytesAvailable 属性 ”。 您可以调用 FileStream 对象的 close() 方法关闭关联文件,使其他应用程序可以使用该文件。 文件模式 说明 FileMode.READ 指定只能打开文件进行读取。 FileMode.WRITE 指定打开文件进行写入。如果文件不存在,则在打开 FileStream 对象时创建它。如果文件存在,则删除所有现 有数据。 FileMode.APPEND 指定打开文件进行追加。如果文件不存在,则创建它。如果文件存在,不覆盖现有数据,所有写入操作都从文件 结尾开始。 FileMode.UPDATE 指定打开文件进行读取和写入。如果文件不存在,则创建它。如果想对文件进行随机读取 / 写入访问,可以指定 此模式。您可以从文件中的任何位置读取。当写入文件时,只有写入的字节会覆盖现有字节(所有其他字节保持 不变)。146ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 FileStream 对象的 position 属性 Adobe AIR 1.0 和更高版本 FileStream 对象的 position 属性确定下一个读取或写入方法读取或写入数据的位置。 执行读取或写入操作之前,请将 position 属性设置为文件中的任何有效位置。 例如,以下代码在文件的位置 8 处写入字符串 "hello" (采用 UTF 编码): var myFile = air.File.documentsDirectory; myFile = myFile.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.open(myFile, air.FileMode.UPDATE); myFileStream.position = 8; myFileStream.writeUTFBytes("hello"); 当您首次打开 FileStream 对象时, position 属性设置为 0。 执行读取操作之前, position 的值必须至少为 0 并且小于文件中的字节数(即文件中的现有位置)。 只有在以下情况下才修改 position 属性的值: • 当您明确设置 position 属性时。 • 当您调用读取方法时。 • 当您调用写入方法时。 当您调用 FileStream 对象的读取或写入方法时, position 属性值立即增加您读取或写入的字节数。根据您使用的读取方法, position 属性可以增加您指定读取的字节数,也可以增加可用的字节数。当您随后调用读取或写入方法时,它从新的位置开始 读取或写入。 var myFile = air.File.documentsDirectory; myFile = myFile.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.open(myFile, air.FileMode.UPDATE); myFileStream.position = 4000; alert(myFileStream.position); // 4000 myFileStream.writeBytes(myByteArray, 0, 200); alert(myFileStream.position); // 4200 不过,有一个例外:对于以 append 模式打开的 FileStream,调用写入方法后 position 属性不变。(在 append 模式中,数据 始终写入文件的结尾,而与 position 属性的值无关。) 对于打开进行异步操作的文件,在下一行代码执行之前不会完成写入操作。不过,您可以连续调用多个异步方法,运行时会按 顺序执行它们: var myFile = air.File.documentsDirectory; myFile = myFile.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.openAsync(myFile, air.FileMode.WRITE); myFileStream.writeUTFBytes("hello"); myFileStream.writeUTFBytes("world"); myFileStream.addEventListener(air.Event.CLOSE, closeHandler); myFileStream.close(); air.trace("started."); closeHandler(event) { air.trace("finished."); } 此代码的跟踪输出如下所示: 147ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 started. finished. 您可以 在调用读取或写入方法后立即(或在任何时间)指定 position 值,下一个读取或写入操作将从该位置开始执行。例如, 请注意以下代码在调用 writeBytes() 操作后立即设置 position 属性,即使写入操作完成后 position 仍设置为该值 (300): var myFile = air.File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.openAsync(myFile, air.FileMode.UPDATE); myFileStream.position = 4000; air.trace(myFileStream.position); // 4000 myFileStream.writeBytes(myByteArray, 0, 200); myFileStream.position = 300; air.trace(myFileStream.position); // 300 读取缓冲区和 FileStream 对象的 bytesAvailable 属性 Adobe AIR 1.0 和更高版本 当打开具有读取功能的 FileStream 对象时(在该对象中, open() 或 openAsync() 方法的 fileMode 参数设置为 READ 或 UPDATE),运行时将数据存储在内部缓冲区中。当您打开文件后, FileStream 对象立即开始将数据读取到缓冲区中(通过调 用 FileStream 对象的 open() 或 openAsync() 方法)。 对于打开执行同步操作的文件(使用 open() 方法),您始终可以设置 position 指针指向任何有效位置(在文件的范围内),并 开始读取任何数量的数据(在文件的范围内),如以下代码中所示(假定该文件包含至少 100 个字节): var myFile = air.File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.open(myFile, air.FileMode.READ); myFileStream.position = 10; myFileStream.readBytes(myByteArray, 0, 20); myFileStream.position = 89; myFileStream.readBytes(myByteArray, 0, 10); 无论打开文件进行同步操作还是异步操作,读取方法始终从由 bytesAvalable 属性表示的 “ 可用 ” 字节读取。当以同步方式读取 时,任何时间文件的所有字节都是可用的。当以异步方式读取时,在由 progress 事件指示的一系列异步缓冲区填充数据中,从 position 属性指定的位置开始的字节是可用的。 对于打开进行同步 操作的文件, bytesAvailable 属性始终设置为表示从 position 属性到文件结尾的字节数(文件中所有字节始 终是可以读取的)。 对于打开进行异步 操作的文件,您需要确保在调用读取方法之前读取缓冲区已包含了足够的数据。对于以异步方式打开的文 件,随着读取操作的进行,文件中从读取操作开始时指定的 position 开始的数据将添加到缓冲区,每读取一个字节 bytesAvailable 属性增加一。 bytesAvailable 属性指示从 position 属性指定的位置的字节开始到缓冲区结尾的可用字节数。 FileStream 对象定期发送一个 progress 事件。 对于以异步方式打开的文件,随着数据在读取缓冲区中可用, FileStream 对象定期调度 progress 事件。例如,当数据读取到缓 冲区时,以下代码将把该数据读取到 ByteArray 对象 bytes 中: var bytes = new air.ByteArray(); var myFile = new air.File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.addEventListener(air.ProgressEvent.PROGRESS, progressHandler); myFileStream.openAsync(myFile, air.FileMode.READ); function progressHandler(event) { myFileStream.readBytes(bytes, myFileStream.position, myFileStream.bytesAvailable); } 对于以异步方式打开的文件,只能读取读取缓冲区中的数据。而且,当您读取数据后,它即从读取缓冲区中删除。对于读取操 作,您需要确保在调用读取操作之前数据在读取缓冲区中存在。例如,以下代码读取文件中从位置 4000 开始的 8000 个字节: 148ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 var myFile = air.File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.addEventListener(air.ProgressEvent.PROGRESS, progressHandler); myFileStream.addEventListener(air.Event.COMPLETE, completed); myFileStream.openAsync(myFile, air.FileMode.READ); myFileStream.position = 4000; var str = ""; function progressHandler(event) { if (myFileStream.bytesAvailable > 8000 ) { str += myFileStream.readMultiByte(8000, "iso-8859-1"); } } 在写入操作过程中, FileStream 对象不会将数据读入读取缓冲区中。当写入操作完成后(写入缓冲区中所有数据都已写入文 件), FileStream 对象启动一个新的读取缓冲区(假定关联的 FileStream 对象已打开并具有读取功能),并开始将从 position 属性指定的位置开始的数据读入读取缓冲区中。 position 属性可以是写入的最后一个字节的位置,也可以是其他位置(如果在 写入操作后用户为 position 对象指定了其他值)。 异步编程和以异步方式打开的 FileStream 对象所生成的事件 Adobe AIR 1.0 和更高版本 当以异步方式打开文件时(使用 openAsync() 方法),读取和写入文件是以异步方式执行的。在将数据读入读取缓冲区以及写 入输出数据时,可以执行其他 ActionScript 代码。 这表示您需要注册由以异步方式打开的 FileStream 对象所生成的事件。 通过注册 progress 事件 , 当有新数据可供使用时您可以收到通知,如以下代码中所示: var myFile = air.File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.addEventListener(air.ProgressEvent.PROGRESS, progressHandler); myFileStream.openAsync(myFile, air.FileMode.READ); var str = ""; function progressHandler(event) { str += myFileStream.readMultiByte(myFileStream.bytesAvailable, "iso-8859-1"); } 通过注册 complete 事件,您可以读取全部数据,如以下代码中所示: var myFile = air.File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.addEventListener(air.Event.COMPLETE, completed); myFileStream.openAsync(myFile, air.FileMode.READ); var str = ""; function completeHandler(event) { str = myFileStream.readMultiByte(myFileStream.bytesAvailable, "iso-8859-1"); } 就像输入数据将存储到缓冲区中以便可以执行异步操作一样,您在异步流上写入的数据也将存储到缓冲区中,然后以异步方式 写入文件。随着数据写入文件, FileStream 对象将定期调度一个 OutputProgressEvent 对象。OutputProgressEvent 对象包括一 个 bytesPending 属性,该属性设置为剩余的要写入的字节数。您可以注册 outputProgress 事件,以便当此缓冲区实际写入文件 时收到通知,或者为了显示进度对话框。不过,通常情况下不需要这样做。具体而言,您可以调用 close() 方法,而不考虑未写 入的字节。 FileStream 对象将继续写入数据,当最后一个字节写入文件并且基础文件关闭后将传递 close 事件。149ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 数据格式以及选择要使用的读取和写入方法 Adobe AIR 1.0 和更高版本 每个文件是磁盘上的一组字节。在 ActionScript 中,文件中的数据始终可以表示为 ByteArray。例如,以下代码将文件中的 数据读入到名为 bytes 的 ByteArray 对象中: var myFile = air.File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.addEventListener(air.Event.COMPLETE, completeHandler); myFileStream.openAsync(myFile, air.FileMode.READ); var bytes = new air.ByteArray(); function completeHandler(event) { myFileStream.readBytes(bytes, 0, myFileStream.bytesAvailable); } 同样,以下代码将名为 bytes 的 ByteArray 中的数据写入文件: var myFile = air.File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.open(myFile, air.FileMode.WRITE); myFileStream.writeBytes(bytes, 0, bytes.length); 不过,通常您不希望在 ActionScript ByteArray 对象中存储数据,并且数据文件通常是指定的文件格式。 例如,文件中的数据可能是文本文件格式,您可能希望在 String 对象中表示这种数据。 因此, FileStream 类包括读取和写入方法,用于读取和写入除 ByteArray 对象以外的类型的数据。例如,使用 readMultiByte() 方法可以从文件中读取数据,然后将它存储到字符串,如以下代码中所示: var myFile = air.File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream = new air.FileStream(); myFileStream.addEventListener(air.Event.COMPLETE, completed); myFileStream.openAsync(myFile, air.FileMode.READ); var str = ""; function completeHandler(event) { str = myFileStream.readMultiByte(myFileStream.bytesAvailable, "iso-8859-1"); } readMultiByte() 方法的第二个参数指定 ActionScript 用来解释数据的文本格式(在示例中是 “iso-8859-1”)。 Adobe AIR 支 持常见的字符集编码(请参阅支持的字符集)。 FileStream 类还包括 readUTFBytes() 方法,该方法使用 UTF-8 字符集将读取缓冲区中的数据读入一个字符串中。由于 UTF- 8 字符集中字符的长度是可变的,请不要在响应 progress 事件的方法中使用 readUTFBytes(),这是因为读取缓冲区结尾的数据 可能表示不完整的字符。(将 readMultiByte() 方法用于可变长度字符编码时,需同样遵循上述要求。)因此,当 FileStream 对 象调度 complete 事件时,应读取整个数据集。 还有类似的写入方法 writeMultiByte() 和 writeUTFBytes() 可用于 String 对象和文本文件。 readUTF() 和 writeUTF() 方法(请不要与 readUTFBytes() 和 writeUTFBytes() 相混淆)也可以从文件读取文本数据和将文本数 据写入文件,不过它们假定文本数据前面有指定文本数据长度的数据(此方式在标准文本文件中不常见)。 有些 UTF 编码的文本文件以 “UTF-BOM” (字节顺序标记)字符开头,该字符定义字节顺序以及编码格式(如 UTF-16 或 UTF-32)。 有关读取和写入文本文件的示例,请参阅第 151 页的 “ 示例:将 XML 文件读取到 XML 对象中 ”。 使用 readObject() 和 writeObject() 可以很方便地存储和检索复杂 ActionScript 对象的数据。数据采用 AMF (ActionScript Message Format) 编码。 Adobe AIR、 Flash Player、 Flash Media Server 和 Flex Data Services 包括用于此格式数据的 API。 150ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 还有一些其他读取和写入方法(如 readDouble() 和 writeDouble())。不过,如果您使用这些方法,请确保文件格式与这些方法 定义的数据的格式相匹配。 文件格式通常比简单文本格式复杂。例如, MP3 文件包括压缩的数据,这些数据只能使用特定于 MP3 文件的解压缩和解码算 法解释。 MP3 文件还可能包括 ID3 标签,这些标签包含有关文件的元标签信息(如歌曲的标题和艺术家)。 ID3 格式有多种 版本,不过最简单的版本( ID3 第 1 版)在第 151 页的 “ 示例:使用随机访问读取和写入数据 ” 部分中进行了介绍。 其他文件格式(用于图像、数据库、应用程序文档等)具有不同的结构,若要在 ActionScript 中使用这些格式的数据,必须 了解数据的构造方式。 使用 load() 和 save() 方法 Flash Player 10 和更高版本, Adobe AIR 1.5 和更高版本 Flash Player 10 向 FileReference 类添加了 load() 和 save() 方法。AIR 1.5 中也有这些方法,并且 File 类从 FileReference 类 继承这些方法。这些方法旨在为用户提供一种在 Flash Player 中加载和保存文件数据的安全方法。但是, AIR 应用程序还可以 使用这些方法作为一种异步加载和保存文件的简便方式。 例如,以下代码将字符串保存到文本文件: var file = air.File.applicationStorageDirectory.resolvePath("test.txt"); var str = "Hello."; file.addEventListener(air.Event.COMPLETE, fileSaved); file.save(str); function fileSaved(event) { air.trace("Done."); } save() 方法的 data 参数可以采用 String 或 ByteArray 值。当参数为 String 值时,该方法将文件保存为 UTF-8 编码的文本文 件。 执行此代码示例时,应用程序将显示一个对话框,用户在该对话框中选择所保存文件的目标。 以下代码从 UTF-8 编码的文本文件加载字符串: var file = air.File.applicationStorageDirectory.resolvePath("test.txt"); file.addEventListener(air.Event.COMPLETE, loaded); file.load(); var str; function loaded(event) { var bytes = file.data; str = bytes.readUTFBytes(bytes.length); air.trace(str); } FileStream 类所提供的功能要多于 load() 和 save() 方法: • 借助 FileStream 类,既可以同步读写数据,也可以异步读写数据。 • 使用 FileStream 类可以用增量方式写入文件。 • 使用 FileStream 类可以打开文件进行随机访问(读写文件的任意部分)。 • 使用 FileStream 类可以指定对文件具有的访问权限的类型,具体途径是设置 open() 或 openAsync() 方法的 fileMode 参数。 • 通过 FileStream,不用向用户显示 “ 打开 ” 或 “ 保存 ” 对话框即可将数据保存到文件。 • 用 FileStream 类读取数据时可以直接使用字节数组之外的类型。151ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 示例:将 XML 文件读取到 XML 对象中 Adobe AIR 1.0 和更高版本 以下示例演示如何读取和写入包含 XML 数据的文本文件。 若要从文件读取,请初始化 File 和 FileStream 对象,调用 FileStream 的 readUTFBytes() 方法,然后将字符串转换为 XML 对象: var file = air.File.documentsDirectory.resolvePath("AIR Test/preferences.xml"); var fileStream = new air.FileStream(); fileStream.open(file, air.FileMode.READ); var prefsXML = fileStream.readUTFBytes(fileStream.bytesAvailable); fileStream.close(); 同样,将数据写入文件也很容易,比如设置适当的 File 和 FileStream 对象,然后调用 FileStream 对象的写入方法。将 XML 数据的字符串版本传递到写入方法,如以下代码中所示: var file = air.File.documentsDirectory.resolvePath("AIR Test/preferences.xml"); fileStream = new air.FileStream(); fileStream.open(file, air.FileMode.WRITE); var outputString = '\n'; outputString += 'true' fileStream.writeUTFBytes(outputString); fileStream.close(); 这些示例使用 readUTFBytes() 和 writeUTFBytes() 方法,这是因为它们假定文件采用 UTF-8 格式。如果不是此格式,您可能需 要使用其他方法(请参阅第 149 页的 “ 数据格式以及选择要使用的读取和写入方法 ”)。 前面的示例使用为进行同步操作而打开的 FileStream 对象。您还可以打开文件进行异步操作(这依赖于事件侦听器函数以响 应事件)。例如,以下代码演示如何以异步方式读取 XML 文件: var file = air.File.documentsDirectory.resolvePath("AIR Test/preferences.xml"); var fileStream= new air.FileStream(); fileStream.addEventListener(air.Event.COMPLETE, processXMLData); fileStream.openAsync(file, air.FileMode.READ); var prefsXML; function processXMLData(event) { var xmlString = fileStream.readUTFBytes(fileStream.bytesAvailable); prefsXML = domParser.parseFromString(xmlString, "text/xml"); fileStream.close(); } 在将整个文件读入到读取缓冲区时(当 FileStream 对象调度 complete 事件时),将调用 processXMLData() 方法。它调用 readUTFBytes() 方法以获取所读数据的字符串版本,然后它基于该字符串创建一个 XML 对象 prefsXML。 要查看演示这些功能的示例应用程序,请参阅从 XML 首选参数文件中读取和写入。 要查看演示这些功能的示例应用程序,请参阅从 XML 首选参数文件中读取和写入。 示例:使用随机访问读取和写入数据 Adobe AIR 1.0 和更高版本 MP3 文件可以包括 ID3 标签,这种标签是位于文件开头或结尾、包含用于标识录制情况的元数据的部分。 ID3 标签格式本身 具有不同的修订版本。此例描述如何使用 “ 随机访问文件数据 ” 从包含最简单的 ID3 格式( ID3 1.0 版)的 MP3 文件读取和 写入, “ 随机访问文件数据 ” 表示它在文件中任意位置进行读取和写入。 152ADOBE AIR HTML 开发人员指南 使用文件系统 上次更新 2011/10/13 包含 ID3 第 1 版标签的 MP3 文件在文件结尾最后 128 个字节中包括 ID3 数据。 当访问文件以进行随机读取 / 写入访问时,将 FileMode.UPDATE 指定为 open() 或 openAsync() 方法的 fileMode 参数很重要。 var file = air.File.documentsDirectory.resolvePath("My Music/Sample ID3 v1.mp3"); var fileStr = new air.FileStream(); fileStr.open(file, air.FileMode.UPDATE); 这样可以读取和写入文件。 打开文件时,您可以设置 position 指针以指向文件结尾向前 128 个字节的位置: fileStr.position = file.size - 128; 此代码将 position 属性设置为指向文件中的此位置,这是因为 ID3 1.0 版格式指定 ID3 标签数据存储在文件的最后 128 个字节 中。该规范还包含以下内容: • 标签的前 3 个字节包含字符串 "TAG"。 • 接下来的 30 个字符包含 MP3 曲目的标题,为字符串。 • 接下来的 30 个字符包含艺术家的姓名,为字符串。 • 接下来的 30 个字符包含唱片的名称,为字符串。 • 接下来的 4 个字符包含年份,为字符串。 • 接下来的 30 个字符包含注释,为字符串。 • 接下来的 1 个字节包含代码,指示曲目的流派。 • 所有文本数据都采用 ISO 8859-1 格式。 当读取数据后(在调度 complete 事件时), id3TagRead() 方法将检查数据: function id3TagRead() { if (fileStr.readMultiByte(3, "iso-8859-1").match(/tag/i)) { var id3Title = fileStr.readMultiByte(30, "iso-8859-1"); var id3Artist = fileStr.readMultiByte(30, "iso-8859-1"); var id3Album = fileStr.readMultiByte(30, "iso-8859-1"); var id3Year = fileStr.readMultiByte(4, "iso-8859-1"); var id3Comment = fileStr.readMultiByte(30, "iso-8859-1"); var id3GenreCode = fileStr.readByte().toString(10); } } 您还可以对文件执行随机访问写入。例如,您可以解析 id3Title 变量以确保它的大小写正确(使用 String 类的方法),然后将 修改后的名为 newTitle 的字符串写入文件,如下所示: fileStr.position = file.length - 125; // 128 - 3 fileStr.writeMultiByte(newTitle, "iso-8859-1"); 为了遵守 ID3 第 1 版标准, newTitle 字符串的长度应为 30 个字符,结尾以字符代码 0 (String.fromCharCode(0)) 填充。153 上次更新 2011/10/13 第 12 章 : AIR 中的拖放 Adobe AIR 1.0 和更高版本 使用 Adobe® AIR™ 拖放 API 中的类可以支持在用户界面上执行拖放手势。此处所说的手势 是指由用户通过操作系统和应用程 序执行的一种操作,表示要复制、移动或链接信息。当用户将对象拖出组件或应用程序时,执行的就是拖出 手势。当用户从组 件或应用程序外部拖入对象时,执行的就是拖入 手势。 利用拖放 API,可以允许用户在应用程序之间以及在应用程序内的组件之间拖动数据。支持的传输格式包括: • 位图 • 文件 • HTML 格式的文本 • 文本 • URL HTML 中的拖放 Adobe AIR 1.0 和更高版本 若要将数据拖入和拖出基于 HTML 的应用程序(或者拖入和拖出 HTMLLoader 中显示的 HTML),则可以使用 HTML 拖 放事件。使用 HTML 拖放 API,可以拖到和拖出 HTML 内容中的 DOM 元素。 注: 还可以通过侦听包含 HTML 内容的 HTMLLoader 对象上发生的事件,来使用 AIR NativeDragEvent 和 NativeDragManager API。但是, HTML API 更好地与 HTML DOM 集成到了一起,因而您可以控制默认行为。 NativeDragEvent 和 NativeDragManager API 在基于 HTML 的应用程序中不经常使用,因此在针对 HTML 开发人员的 Adobe AIR API 参考中未提供。有关使用这些类的更多信息,请参阅 Adobe ActionScript 3.0 开发人员指南和用于 Adobe Flash Platform 的 ActionScript 3.0 参考。 默认的拖放行为 Adobe AIR 1.0 和更高版本 HTML 环境为涉及文本、图像和 URL 的拖放手势提供了默认行为。利用默认行为,始终都可以将这些类型的数据拖出元素。 但是,只能将文本拖入元素,并且只能拖到页面的可编辑区域内的元素。在页面的可编辑区域之间或可编辑区域内部拖动文本 时,默认行为会执行移动动作。从不可编辑的区域或应用程序外部向可编辑区域拖动文本时,默认行为则会执行复制动作。 可以通过自行处理拖放事件来覆盖默认行为。若要取消默认行为,必须调用为拖放事件调度的对象的 preventDefault() 方法。这 样,您就可以根据需要将数据插入放置目标以及从拖动源中删除数据,以便执行所选的动作。 默认情况下,用户可以选择和拖动任何文本,并可以拖动图像和链接。可以使用 WebKit CSS 属性 -webkit-user-select 来控制 任何 HTML 元素的选择方式。例如,如果将 -webkit-user-select 设置为 none,则元素内容是不可选择的,因而也无法拖动。还 可以使用 -webkit-user-drag CSS 属性控制元素作为一个整体是否可以拖动。不过,元素的内容则单独处理。用户仍可以拖动文 本的选定部分。有关详细信息,请参阅 第 13 页的 “AIR 中的 CSS”。 154ADOBE AIR HTML 开发人员指南 AIR 中的拖放 上次更新 2011/10/13 HTML 中的拖放事件 Adobe AIR 1.0 和更高版本 从中发起拖动操作的启动器元素调度的事件有: 由拖动目标调度的事件有: 为响应这些事件而调度的事件对象与鼠标事件类似。可以使用诸如 (clientX, clientY) 和 (screenX, screenY) 等鼠标事件属性来确 定鼠标位置。 拖动事件对象最重要的属性是 dataTransfer,此属性包含被拖动的数据。 dataTransfer 对象本身具有以下属性和方法: 事件 说明 dragstart 在用户启动拖动手势时调度。如有必要,此事件的处理函数可以通过调用事件对象的 preventDefault() 方法来阻止拖 动。若要控制是否可以复制、链接或移动所拖动的数据,请设置 effectAllowed 属性。所选的文本、图像和链接由默 认行为放置到剪贴板上,但您可以使用事件对象的 dataTransfer 属性为拖动手势设置其他数据。 drag 在执行拖动手势期间持续调度 dragend 在用户释放鼠标按键终止拖动手势时调度。 事件 说明 dragover 当拖动手势仍然在元素边界内时持续调度。此事件的处理函数应设置 dataTransfer.dropEffect 属性,以指示在用户 释放鼠标时放置操作是否会导致复制、移动或链接动作。 dragenter 在拖动手势进入元素的边界内时调度。 如果在 dragenter 事件处理函数中更改 dataTransfer 对象的任何属性,则这些更改将很快被下一个 dragover 事件覆 盖。另一方面,在 dragenter 与第一个 dragover 事件之间有一个短暂的延迟,如果设置了不同的属性,此延迟可导致 光标闪烁。在很多情况下,都可以对这两个事件使用相同的事件处理函数。 dragleave 在拖动手势离开元素边界时调度。 drop 在用户将数据放到元素上时调度。只能在此事件的处理函数内访问所拖动的数据。 属性或方法 说明 effectAllowed 拖动源允许的效果。通常情况下, dragstart 事件的处理函数设置此值。请参阅 第 155 页的 “HTML 中的拖动效果 ”。 dropEffect 由目标或用户选择的效果。如果在 dragover 或 dragenter 事件处理函数中设置 dropEffect,则 AIR 会更新鼠标光标, 以指示在用户释放鼠标时出现的效果。如果允许的效果中没有一种效果与 dropEffect 设置匹配,则不允许放置,并显 示不可用 光标。如果尚未设置 dropEffect 来响应最新的 dragover 或 dragenter 事件,则用户可以使用标准的操作系统 功能键从允许的效果中进行选择。 最终的效果由为 dragend 调度的对象的 dropEffect 属性报告。如果用户通过在符合条件的目标外部释放鼠标放弃放置 操作,则 dropEffect 将设置为 none。 类型 一个数组,其中包含了 dataTransfer 对象中存在的每种数据格式的 MIME 类型字符串。 getData(mimeType) 以 mimeType 参数指定的格式获取数据。 只能为响应 drop 事件调用 getData() 方法。155ADOBE AIR HTML 开发人员指南 AIR 中的拖放 上次更新 2011/10/13 用于 HTML 拖放的 MIME 类型 Adobe AIR 1.0 和更高版本 与 HTML 拖放事件的 dataTransfer 对象一起使用的 MIME 类型包括: 还可以使用其他 MIME 字符串,包括应用程序定义的字符串。但是,其他应用程序可能无法识别或使用所传输的数据。以所 需格式向 dataTransfer 对象添加数据的工作由您负责完成。 重要说明: 只有在应用程序沙箱中运行的代码才能访问放置的文件。如果试图在非应用程序沙箱内读取或设置 File 对象的任何 属性,则会产生安全错误。有关详细信息,请参阅第 159 页的 “ 在非应用程序 HTML 沙箱中处理文件放置 ”。 HTML 中的拖动效果 Adobe AIR 1.0 和更高版本 拖动手势的启动器可以通过在 dragstart 事件的处理函数中设置 dataTransfer.effectAllowed 属性,来限制允许的拖动效果。可以 使用以下字符串值: setData(mimeType) 以 mimeType 参数指定的格式向 dataTransfer 添加数据。可以通过对每种 MIME 类型调用 setData(),以多种格式添 加数据。将清除由默认拖动行为放入 dataTransfer 对象的所有数据。 只能为响应 dragstart 事件调用 setData() 方法。 clearData(mimeType) 清除采用 mimeType 参数指定的格式的所有数据。 setDragImage(image, offsetX, offsetY) 设置自定义拖动图像。只能为响应 dragstart 事件,且只有当拖动整个 HTML 元素(通过将 -webkit-user-drag CSS 样式设置为 element)时,才可以调用 setDragImage() 方法。 image 参数可以是 JavaScript 元素或 Image 对象。 数据格式 MIME 类型 文本 "text/plain" HTML "text/html" URL "text/uri-list" 位图 "image/x-vnd.adobe.air.bitmap" 文件列表 "application/x-vnd.adobe.air.file-list" 字符串值 说明 "none" 不允许任何拖动操作。 "copy" 将数据复制到目标位置,并保留原始数据的位置不变。 "link" 使用指回原始数据的链接与放置目标共享数据。 "move" 将数据复制到目标,并将其从原始位置删除。 "copyLink" 可以复制数据,也可链接数据。 "copyMove" 可以复制数据,也可移动数据。 "linkMove" 可以链接数据,也可移动数据。 "all" 可以复制数据、移动数据,也可链接数据。当您阻止默认行为时, All 是默认效果。 属性或方法 说明156ADOBE AIR HTML 开发人员指南 AIR 中的拖放 上次更新 2011/10/13 拖动手势的目标可以设置 dataTransfer.dropEffect 属性,以指示在用户完成放置后采取的动作。如果放置效果是允许的动作之 一,则系统将显示相应的复制、移动或链接光标。如果不是,则系统将显示不可用 光标。如果目标未设置放置效果,则用户可 以使用功能键从允许的动作中进行选择。 同时在 dragover 和 dragenter 事件的处理函数中设置 dropEffect 值: function doDragStart(event) { event.dataTransfer.setData("text/plain","Text to drag"); event.dataTransfer.effectAllowed = "copyMove"; } function doDragOver(event) { event.dataTransfer.dropEffect = "copy"; } function doDragEnter(event) { event.dataTransfer.dropEffect = "copy"; } 注: 尽管您始终都应在 dragenter 的处理函数中设置 dropEffect 属性,但要注意,下一个 dragover 事件会将此属性重置为其默认 值。设置 dropEffect 以响应这两个事件。 将数据拖出 HTML 元素 Adobe AIR 1.0 和更高版本 默认行为允许以拖动方式复制 HTML 页面中的大部分内容。可以使用 CSS 属性 -webkit-user-select 和 -webkit-user-drag 来控 制允许拖动的内容。 在 dragstart 事件的处理函数中覆盖默认的拖出行为。调用事件对象的 dataTransfer 属性的 setData() 方法,以便将您自己的数据 放入拖动手势。 若要指示在不依赖默认行为时源对象支持的拖动效果,请设置为 dragstart 事件调度的事件对象的 dataTransfer.effectAllowed 属 性。您可以选择任意效果组合。例如,如果源元素既支持复制 效果,也支持链接 效果,则请将此属性设置为 "copyLink"。 设置拖动的数据 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 使用 dataTransfer 属性在 dragstart 事件的处理函数中为拖动手势添加数据。使用 dataTransfer.setData() 方法将数据放到剪贴板 上,同时传入 MIME 类型和要传输的数据。 例如,如果应用程序中有一个 ID 为 imageOfGeorge 的图像元素,则可以使用下面的 dragstart 事件处理函数。此示例以多种 数据格式添加 George 照片的表示形式,从而增加了其他应用程序能够使用拖动的数据的可能性。 function dragStartHandler(event){ event.dataTransfer.effectAllowed = "copy"; var dragImage = document.getElementById("imageOfGeorge"); var dragFile = new air.File(dragImage.src); event.dataTransfer.setData("text/plain","A picture of George"); event.dataTransfer.setData("image/x-vnd.adobe.air.bitmap", dragImage); event.dataTransfer.setData("application/x-vnd.adobe.air.file-list", new Array(dragFile)); } 注: 调用 dataTransfer 对象的 setData() 方法时,默认拖放行为不会添加任何数据。 157ADOBE AIR HTML 开发人员指南 AIR 中的拖放 上次更新 2011/10/13 将数据拖入 HTML 元素 Adobe AIR 1.0 和更高版本 默认行为只允许将文本拖入页面的可编辑区域中。可以通过在元素的开始标签中包含 contenteditable 属性,指定可以使元素及 其子级可编辑。还可以通过将文档对象的 designMode 属性设置为 "on",使整个文档可编辑。 可以通过处理可接受所拖动数据的任何元素的 dragenter、 dragover 和 drop 事件,支持页面上的替代拖入行为。 允许拖入 Adobe AIR 1.0 和更高版本 若要处理拖入手势,必须先取消默认行为。侦听您要用作放置目标的任何 HTML 元素上发生的 dragenter 和 dragover 事件。在 这些事件的处理函数中,调用调度的事件对象的 preventDefault() 方法。如果取消默认行为,则会允许不可编辑的区域接收放 置。 获取放置的数据 Adobe AIR 1.0 和更高版本 可以在 ondrop 事件的处理函数中访问放置的数据: function doDrop(event){ droppedText = event.dataTransfer.getData("text/plain"); } 使用 dataTransfer.getData() 方法将数据读到剪贴板上,同时传入要读取的数据格式的 MIME 类型。可以使用 dataTransfer 对象 的 types 属性查明哪些数据格式可用。 types 数组包含每种可用格式的 MIME 类型字符串。 取消 dragenter 或 dragover 事件中的默认行为后,须由您将放置的任何数据插入到其在文档中的正确位置。不存在可将鼠标 位置转换成元素内的插入点的 API。由于存在这一限制,因而可能很难实现插入类型的拖动手势。 示例:覆盖默认的 HTML 拖入行为 Adobe AIR 1.0 和更高版本 此示例实现一个放置目标,此目标显示了一个表,表中显示放置的项目中可用的每种数据格式。 默认行为用于允许在应用程序内拖动文本、链接和图像。此示例覆盖用作放置目标的 div 元素的默认拖入行为。使不可编辑的 内容能接受拖入手势的关键步骤,就是调用为 dragenter 和 dragover 事件调度的事件对象的 preventDefault() 方法。为响应 drop 事件,处理函数将传输的数据转换成 HTML 行元素,然后将该行插入表中以进行显示。158ADOBE AIR HTML 开发人员指南 AIR 中的拖放 上次更新 2011/10/13 Drag-and-drop

    Source

    Items to drag:

    • Plain text.
    • HTML formatted text.
    • A URL.
    • An image
    • 159ADOBE AIR HTML 开发人员指南 AIR 中的拖放 上次更新 2011/10/13 Uses "-webkit-user-drag:none" style.
    • Uses "-webkit-user-select:none" style.

    Target

    Drag items from the source list (or elsewhere).

    Plain textHtml textURLFile listBitmap Data
         
在非应用程序 HTML 沙箱中处理文件放置 Adobe AIR 1.0 和更高版本 非应用程序内容无法访问在将文件拖入 AIR 应用程序时产生的 File 对象。也无法将这些 File 对象中的一个对象通过沙箱桥传 递给应用程序内容。(必须在序列化期间访问对象属性。)但是,您仍可以通过侦听 HTMLLoader 对象上发生的 AIR nativeDragDrop 事件,在应用程序中放置文件。 通常,如果用户将文件放入承载非应用程序内容的框架中,则放置事件不会从子级传播到父级。但是,由于 HTMLLoader (AIR 应用程序中所有 HTML 内容的容器)调度的事件不是 HTML 事件流的一部分,因此您仍可以在应用程序内容中接收放 置事件。 为了接收文件放置事件,父级文档会使用 window.htmlLoader 提供的引用向 HTMLLoader 对象添加一个事件侦听器: window.htmlLoader.addEventListener("nativeDragDrop",function(event){ var filelist = event.clipboard.getData(air.ClipboardFormats.FILE_LIST_FORMAT); air.trace(filelist[0].url); }); NativeDragEvent 对象在行为上与其 HTML 事件的对应对象相似,但部分属性和方法的名称和数据类型不同。例如, HTML 事件 dataTransfer 属性的用途与 ActionScript 事件 clipboard 属性相同。 有关使用这些类的更多信息,请参阅 Adobe ActionScript 3.0 开发人员指南和用于 Adobe Flash Platform 的 ActionScript 3.0 参考。 下面的示例使用将子级页面加载到远程沙箱 (http://localhost/) 中的父级文档:父级侦听 HTMLLoader 对象上发生的 nativeDragDrop 事件,并输出文件 URL。160ADOBE AIR HTML 开发人员指南 AIR 中的拖放 上次更新 2011/10/13 Drag-and-drop in a remote sandbox 子级文档必须通过在 HTML dragenter 和 dragover 事件处理函数中调用 Event 对象的 preventDefault() 方法来提供有效的放置 目标。否则,放置事件绝对不会发生。 Drag and drop target

Drop Files Here

放置文件释放 Adobe AIR 2 和更高版本 文件释放是一种拖放剪贴板格式,这种格式允许用户将尚不存在的文件拖出 AIR 应用程序外。例如,使用文件释放,您的应用 程序使用户可将代理图标拖动到桌面文件夹中。代理图标表示 URL 上已知并可用的文件或一些数据。在用户放置图标后,运 行时将下载数据并将文件写入放置位置。 可使用 AIR 应用程序中的 URLFilePromise 类来到拖放 URL 上可访问的文件。在 aircore 库中, URLFilePromise 实现作 为 AIR 2 SDK 的一部分提供。使用包含在 SDK frameworks/libs/air 目录中的 aircore.swc 或 aircore.swf 文件。 或者,您可以使用 IFilePromise 接口(在运行时 flash.desktop 包中定义)实现自己的文件承诺逻辑。 文件释放在概念上类似于在剪贴板上使用数据处理函数的延迟呈现。在拖放文件时使用文件释放而不使用延迟呈现。当生成或 下载数据时,使用延迟呈现技术可能会导致拖动手势出现不需要的暂停。使用延迟呈现执行复制粘贴操作(文件释放不支持此 操作)。161ADOBE AIR HTML 开发人员指南 AIR 中的拖放 上次更新 2011/10/13 使用文件释放时的限制 与您可以放在拖放剪贴板中的其他数据格式相比,文件释放有以下限制: • 文件释放只能拖出 AIR 应用程序;而不能拖入 AIR 应用程序中。 • 并非所有操作系统都不支持文件释放。使用 Clipboard.supportsFilePromise 属性测试主机系统是否支持文件释放。在不支持 文件释放的系统中,您应提供替代机制,以便下载或生成文件数据。 • 文件释放不能与复制粘贴剪贴板 (Clipboard.generalClipboard) 一起使用。 更多帮助主题 flash.desktop.IFilePromise air.desktop.URLFilePromise 放置远程文件 Adobe AIR 2 和更高版本 使用 URLFilePromise 类创建表示 URL 上可用文件或数据的文件释放对象。使用 FILE_PROMISE_LIST 剪贴板格式将一个或 多个文件释放对象添加到剪贴板。在以下示例中,从 http://www.example.com/foo.txt 下载一个单独的文件,并作为 bar.txt 保存到放置位置。(远程和本地文件名不必匹配。)

Drag to file system

通过将多个文件释放对象添加到分配给剪贴板的数组,您可以允许用户一次拖动多个文件。您还可以在 relativePath 属性中指定 子目录,以便将操作中包括的部分文件或所有文件放置到子文件夹(相对于放置位置)中。162ADOBE AIR HTML 开发人员指南 AIR 中的拖放 上次更新 2011/10/13 以下示例演示如何启动包括多个文件释放的拖动操作。在此示例中, HTML 页面 article.html 作为文件释放与两个链接的图 像文件一起放置在剪贴板上。这些图像被复制到 images 子文件夹中,以便保持相对链接。

Drag to file system

实现 IFilePromise 接口 Adobe AIR 2 和更高版本 若要为不能使用 URLFilePromise 对象访问的资源提供文件释放,可以在自定义类中实现 IFilePromise 接口。一旦放置文件 释放后, IFilePromise 接口就会定义由 AIR 运行时访问要写入到文件中的数据所用的方法和属性。 注: 由于 JavaScript 语言不支持接口的实现,您只能使用 ActionScript 实现自己的文件承诺逻辑。当然,您可以将包含 ActionScript 类的 SWF 文件导入到使用

Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.

171ADOBE AIR HTML 开发人员指南 复制和粘贴 上次更新 2011/10/13 剪贴板数据格式 Flash Player 10 和更高版本, Adobe AIR 1.0 和更高版本 剪贴板格式描述了 Clipboard 对象中放置的数据。Flash Player 或 AIR 可在 ActionScript 数据类型和系统剪贴板格式之间自 动进行标准数据格式的转换。此外,使用应用程序定义的格式可以在基于 ActionScript 的应用程序内或这些应用程序之间传输 应用程序对象。 Clipboard 对象可以包含采用不同格式的同一信息的多种表示形式。例如,表示 Sprite 的 Clipboard 对象可以包括在同一应 用程序中使用的引用格式、由在 Flash Player 或 AIR 中运行的另一应用程序使用的序列化格式、由图像编辑器使用的位图格式 以及文件列表格式,还可能具有延迟呈示功能以对 PNG 文件进行编码,以便将 Sprite 的表示形式复制或拖动到文件系统。 标准数据格式 Flash Player 10 和更高版本, Adobe AIR 1.0 和更高版本 ClipboardFormats 类中提供了用于定义标准格式名称的常量: 因响应 HTML 内容(在 AIR 应用程序中承载的)中的 copy、 cut 或 paste 事件而复制和粘贴数据时,必须使用 MIME 类型 而不是 ClipboardFormat 字符串。有效的数据 MIME 类型为: 注: 如果事件对象是因为 HTML 内容中的 paste 事件而被调度,则无法从该事件对象的 clipboardData 属性中获得 RTF 格式数 据。 自定义数据格式 Flash Player 10 和更高版本, Adobe AIR 1.0 和更高版本 您可以使用应用程序定义的自定义格式将对象作为引用或序列化副本传输。参考只在同一应用程序中有效。序列化对象可以在 应用程序之间传输,但只能用于序列化和取消序列化后仍然有效的对象。如果对象的属性为简单类型或可序列化对象,则通常 可以将该对象序列化。 常量 说明 TEXT_FORMAT 文本格式数据与 ActionScript String 类之间的转换。 HTML_FORMAT 带有 HTML 标记的文本。 RICH_TEXT_FORMAT RTF 格式数据与 ActionScript ByteArray 类之间的转换。不会以任何方式对 RTF 标记进行解释或转换。 BITMAP_FORMAT (仅限 AIR)位图格式数据与 ActionScript BitmapData 类之间的转换。 FILE_LIST_FORMAT (仅限 AIR)文件列表格式数据与 ActionScript File 对象数组之间的转换。 URL_FORMAT (仅限 AIR) URL 格式数据与 ActionScript String 类之间的转换。 MIME 类型 说明 文本 "text/plain" URL "text/uri-list" 位图 "image/x-vnd.adobe.air.bitmap" 文件列表 "application/x-vnd.adobe.air.file-list"172ADOBE AIR HTML 开发人员指南 复制和粘贴 上次更新 2011/10/13 若要将序列化对象添加到 Clipboard 对象,请在调用 Clipboard.setData() 方法时将可序列化 参数设置为 true。格式名称可以是 标准格式中的某一种或由应用程序定义的任意字符串。 传输模式 Flash Player 10 和更高版本, Adobe AIR 1.0 和更高版本 使用自定义数据格式将对象写入剪贴板后,可以从剪贴板中将对象数据作为引用读取,也可以将其作为原始对象的序列化副本 读取。共有四种传输模式,这些模式确定了对象是以引用还是以序列化副本的形式传输: 读取和写入自定义数据格式 Flash Player 10 和更高版本, Adobe AIR 1.0 和更高版本 将对象写入剪贴板时,可将任何不以保留前缀 air: 或 flash: 开头的字符串用于格式 参数。请使用相同字符串作为读取对象的格 式。下面的示例说明了如何从剪贴板读取对象和向其中写入对象: public function createClipboardObject(object:Object):Clipboard{ var transfer:Clipboard = Clipboard.generalClipboard; transfer.setData("object", object, true); } function createClipboardObject(object){ var transfer = new air.Clipboard(); transfer.setData("object", object, true); } 若要从 Clipboard 对象中提取序列化对象(放置或粘贴操作之后),请使用相同格式名称和 CLONE_ONLY 或 CLONE_PREFFERED 传输模式。 var transfer:Object = clipboard.getData("object", ClipboardTransferMode.CLONE_ONLY); var transfer = clipboard.getData("object", air.ClipboardTransferMode.CLONE_ONLY); 此时将始终向 Clipboard 对象添加一个引用。若要从 Clipboard 对象中提取引用(放置或粘贴操作之后)而不是提取序列化 副本,请使用 ORIGINAL_ONLY 或 ORIGINAL_PREFFERED 传输模式: var transferredObject:Object = clipboard.getData("object", ClipboardTransferMode.ORIGINAL_ONLY); var transferredObject = clipboard.getData("object", air.ClipboardTransferMode.ORIGINAL_ONLY); 仅当 Clipboard 对象是源自当前应用程序中时,引用才有效。当引用可用时,可使用 ORIGINAL_PREFFERED 传输模式访问 该引用;当引用不可用时,则可使用该模式访问序列化副本。 传输模式 说明 ClipboardTransferModes.ORIGINAL_ONLY 仅返回引用。如果没有引用,则返回 null 值。 ClipboardTransferModes.ORIGINAL_PREFFERE D 如果存在引用,将返回引用。否则返回序列化副本。 ClipboardTransferModes.CLONE_ONLY 仅返回序列化副本。如果没有可用的序列化副本,则返回 null 值。 ClipboardTransferModes.CLONE_PREFFERED 如果存在序列化副本,将返回序列化副本。否则返回引用。173ADOBE AIR HTML 开发人员指南 复制和粘贴 上次更新 2011/10/13 延迟呈现 Flash Player 10 和更高版本, Adobe AIR 1.0 和更高版本 如果创建数据格式的计算成本高昂,则可以通过提供按需提供数据的函数来使用延迟呈现。仅当放置或粘贴操作的接收方请求 延迟格式的数据时才会调用此函数。 呈现函数是通过使用 setDataHandler() 方法添加到 Clipboard 对象中的。该函数必须返回相应格式的数据。例如,如果您调用 setDataHandler(ClipboardFormat.TEXT_FORMAT, writeText),则 writeText() 函数必须返回字符串。 如果使用 setData() 方法将同一类型的数据格式添加到 Clipboard 对象,则该数据的优先级高于其延迟版本(不会调用呈示函 数)。如果再次访问该同一剪贴板数据,则可能会再次调用或不调用该呈示函数。 注: 在 Mac OS X 上,延迟呈示仅适用于自定义数据格式。使用标准数据格式时,会直接调用呈示函数。 使用延迟呈现函数粘贴文本 Flash Player 10 和更高版本, Adobe AIR 1.0 和更高版本 下面的示例说明了如何实现延迟呈现函数。 当用户按下 “Copy” 按钮时,应用程序将清除系统剪贴板以确保不会留下上次剪贴板操作的数据。然后, setDataHandler() 方 法将 renderData() 函数设置为剪贴板渲染器。 当用户从目标文本字段的上下文菜单中选择 “ 粘贴 ” 命令时,应用程序将访问剪贴板并设置目标文本。由于已使用函数而不是 字符串设置了剪贴板上的文本数据格式,剪贴板将调用 renderData() 函数。 renderData() 函数将返回源文本中的文本,然后将 其分配给目标文本。 请注意,如果按下 “Paste” 按钮前编辑源文本,则此编辑操作将反映到粘贴的文本中,即使按下 “Paste” 按钮后再进行编辑也 是如此。这是因为呈现函数直到按下 “Paste” 按钮后才会复制源文本。(当在实际的应用程序中使用延迟呈现时,最好以某种 方式存储或保护源数据以防止出现此问题。) Flash 示例 package { import flash.desktop.Clipboard; import flash.desktop.ClipboardFormats; import flash.desktop.ClipboardTransferMode; import flash.display.Sprite; import flash.text.TextField; import flash.text.TextFormat; import flash.text.TextFieldType; import flash.events.MouseEvent; import flash.events.Event; public class DeferredRenderingExample extends Sprite { private var sourceTextField:TextField; private var destination:TextField; private var copyText:TextField; public function DeferredRenderingExample():void { sourceTextField = createTextField(10, 10, 380, 90); sourceTextField.text = "Neque porro quisquam est qui dolorem " + "ipsum quia dolor sit amet, consectetur, adipisci velit."; copyText = createTextField(10, 110, 35, 20); copyText.htmlText = "Copy"; copyText.addEventListener(MouseEvent.CLICK, onCopy); destination = createTextField(10, 145, 380, 90); 174ADOBE AIR HTML 开发人员指南 复制和粘贴 上次更新 2011/10/13 destination.addEventListener(Event.PASTE, onPaste); } private function createTextField(x:Number, y:Number, width:Number, height:Number):TextField { var newTxt:TextField = new TextField(); newTxt.x = x; newTxt.y = y; newTxt.height = height; newTxt.width = width; newTxt.border = true; newTxt.multiline = true; newTxt.wordWrap = true; newTxt.type = TextFieldType.INPUT; addChild(newTxt); return newTxt; } public function onCopy(event:MouseEvent):void { Clipboard.generalClipboard.clear(); Clipboard.generalClipboard.setDataHandler(ClipboardFormats.TEXT_FORMAT, renderData); } public function onPaste(event:Event):void { sourceTextField.text = Clipboard.generalClipboard.getData(ClipboardFormats.TEXT_FORMAT).toString; } public function renderData():String { trace("Rendering data"); var sourceStr:String = sourceTextField.text; if (sourceTextField.selectionEndIndex > sourceTextField.selectionBeginIndex) { return sourceStr.substring(sourceTextField.selectionBeginIndex, sourceTextField.selectionEndIndex); } else { return sourceStr; } } } }175ADOBE AIR HTML 开发人员指南 复制和粘贴 上次更新 2011/10/13 Flex 示例 Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit. 176 上次更新 2011/10/13 第 14 章 : 在 AIR 中使用本地 SQL 数据库 Adobe AIR 1.0 和更高版本 Adobe® AIR® 包括创建和使用本地 SQL 数据库的功能。运行时包括一个 SQL 数据库引擎,该引擎使用开放源代码 SQLite 数 据库系统,支持许多标准 SQL 功能。本地 SQL 数据库可用于存储本地永久性数据。例如,它可用于应用程序数据、应用程序 用户设置、文档或希望应用程序在本地保存的任何其他类型的数据。 关于本地 SQL 数据库 Adobe AIR 1.0 和更高版本 有关使用 SQL 数据库的快速介绍和代码示例,请参阅 Adobe Developer Connection 中的以下快速入门文章: • 异步处理本地 SQL 数据库 • 同步处理本地 SQL 数据库 • 使用加密数据库 Adobe AIR 包括一个基于 SQL 的关系数据库引擎,该引擎在运行时中运行,数据以本地方式存储在运行 AIR 应用程序的计算 机上的数据库文件中(例如,在计算机的硬盘驱动器上)。由于数据库的运行和数据文件的存储都在本地进行,因此,不管网 络连接是否可用, AIR 应用程序都可以使用数据库。这样,运行时的本地 SQL 数据库引擎为存储永久的本地应用程序数据提 供了一种便利机制,特别是您具有 SQL 和关系数据库经验时。 本地 SQL 数据库的用途 Adobe AIR 1.0 和更高版本 AIR 本地 SQL 数据库功能可以用于将应用程序数据存储在用户的本地计算机上的任何目的。Adobe AIR 包括在本地存储数据 的几种机制,各机制具有不同的优点。以下是本地 SQL 数据库在 AIR 应用程序中的一些可能用途: • 对于面向数据的应用程序(例如通讯簿),数据库可以用于存储主应用程序数据。 • 对于面向文档的应用程序(用户创建要保存并可能共享的文档),可以在用户指定的位置将每个文档另存为数据库文件。 (不过请注意,除非加密了数据库,否则任何 AIR 应用程序都可以打开该数据库文件。对于可能存在敏感信息的文档,建 议使用加密。) • 对于支持网络的应用程序,数据库可以用于存储应用程序数据的本地缓存,或者在网络连接不可用时暂时存储数据。可以创 建一种将本地数据库与网络数据存储同步的机制。 • 对于任何应用程序,数据库都可以用于存储单个用户的应用程序设置,例如用户选项或应用程序信息(如窗口大小和位 置)。 更多帮助主题 Christophe Coenraets:AIR for Android 上的 Employee 目录 Raymond Camden:jQuery 和 AIR – 从网页到应用程序177ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 关于 AIR 数据库和数据库文件 Adobe AIR 1.0 和更高版本 单个 Adobe AIR 本地 SQL 数据库作为单个文件存储在计算机的文件系统中。运行时包括 SQL 数据库引擎,该引擎管理数据 库文件的创建和结构化以及操作和检索数据库文件中的数据。运行时不指定在文件系统上存储数据库数据的方式或位置;相 反,每个数据库完全存储在单个文件中。您指定在文件系统中存储数据库文件的位置。单个 AIR 应用程序可以访问一个或多个 单独的数据库(即单独的数据库文件)。由于运行时将每个数据库作为单个文件存储在文件系统上,因此可以在需要时按照应 用程序的设计和操作系统的文件访问约束查找您的数据库。每个用户都可以具有其特定数据的单独数据库文件,或者数据库文 件可以由在单个计算机上共享数据的所有应用程序用户访问。由于数据对单个计算机是本地的,因此在不同计算机上的用户之 间并不自动共享数据。本地 SQL 数据库引擎未提供对远程数据库或基于服务器的数据库执行 SQL 语句的任何功能。 关于关系数据库 Adobe AIR 1.0 和更高版本 关系数据库是一种在计算机上存储(和检索)数据的机制。数据被组织到表中:行表示记录或项目,而列(有时称为 “ 字段 ”)将每个记录分到各个值中。例如,通讯簿应用程序可能包含 “ 朋友 ” 表。表中的每个行都表示存储在数据库中的单个朋友。 表的列表示名字、姓氏、出生日期等数据。对于表中的每个朋友行,数据库为每个列存储一个单独的值。 关系数据库设计用于存储复杂数据,其中一个项目与其他类型的项目关联或相关。在关系数据库中,应该将具有一对多关系 (其中单个记录可以与不同类型的多个记录相关)的任何数据分到不同的表中。例如,假定您希望通讯簿应用程序为每个朋友 存储多个电话号码;这就是一对多关系。 “ 朋友 ” 表包含每个朋友的所有个人信息。单独的 “ 电话号码 ” 表包含所有朋友的所 有电话号码。 除了存储有关朋友和电话号码的数据外,每个表都需要一段数据来跟踪这两个表之间的关系,以便使单个朋友记录与其电话号 码匹配。该数据称为主键 — 将一个表中的每个行与该表中的其他行区分开的唯一标识符。主键可以是 “ 自然键 ”,这意味着它 是自然区分表中每个记录的数据项目之一。在 “ 朋友 ” 表中,如果您知道朋友的出生日期都是不同的,则可以将出生日期列用 作 “ 朋友 ” 表的主键(自然键)。如果没有自然键,则应单独创建一个主键列,如 “ 朋友 id” (应用程序用于区分各行的人工 值)。 使用主键,可以设置多个表之间的关系。例如,假定 “ 朋友 ” 表有一个 “ 朋友 id” 列,其中包含每行(每个朋友)的唯一编 号。 可以用以下两列来构建相关的 “ 电话号码 ” 表:一个列包含电话号码所属的朋友的 “ 朋友 id”,另一列包含实际的电话号 码。这样,不管单个朋友具有多少个电话号码,都可以将它们全部存储在 “ 电话号码 ” 表中,并可以使用 “ 朋友 id” 主键将其 链接到相关的朋友。在相关表中使用一个表的主键指定记录之间的联系时,相关表中的值称为外键。与许多数据库不同, AIR 本地数据库引擎不允许您创建外键约束(即自动检查插入的或更新的外键值在主键表中是否具有对应行的约束)。然而,外键 关系是关系数据库结构的重要部分,而且在数据库的表之间创建关系时应该使用外键。 关于 SQL Adobe AIR 1.0 和更高版本 结构化查询语言 (SQL) 用于关系数据库以操作和检索数据。 SQL 是一种描述性语言,而不是一种过程语言。 SQL 语句描述您 所需的一组数据,而不是提供有关它应该如何检索数据的计算机指令。数据库引擎确定如何检索该数据。 SQL 语言已由美国国家标准协会 (ANSI) 进行了标准化。 Adobe AIR 本地 SQL 数据库支持 SQL-92 标准的大部分内容。 有关 Adobe AIR 中支持的 SQL 语言的特定说明,请参阅第 293 页的 “ 本地数据库中的 SQL 支持 ”。178ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 关于 SQL 数据库类 Adobe AIR 1.0 和更高版本 要在 JavaScript 中使用本地 SQL 数据库,请使用以下类的实例。 (请注意,需要在 HTML 文档中加载文件 AIRAliases.js 才 能使用这些类的 air.* 别名): 若要获取描述数据库结构的架构信息,请使用以下类: 以下类提供用于 SQLConnection 类的常数: 此外,以下类表示所用的事件(和支持常数): 最后,以下类提供有关数据库操作错误的信息: 类说明 air.SQLConnection 提供创建和打开数据库(数据库文件)的方式,以及执行数据库级操作和控制数据库事务的方法。 air.SQLStatement 表示对数据库执行的单个 SQL 语句(单个查询或命令),包括定义语句文本和设置参数值。 air.SQLResult 提供一种通过执行语句获取信息或结果的方法,如执行 SELECT 语句后的结果行、受 UPDATE 或 DELETE 语句影 响的行数等。 类说明 air.SQLSchemaResult 充当通过调用 SQLConnection.loadSchema() 方法生成的数据库架构结果的容器。 air.SQLTableSchema 提供描述数据库中单个表的信息。 air.SQLViewSchema 提供描述数据库中单个视图的信息。 air.SQLIndexSchema 提供描述数据库中表或视图的单个列的信息。 air.SQLTriggerSchema 提供描述数据库中单个触发器的信息。 类说明 air.SQLMode 定义一组常量,它们表示 SQLConnection.open() 和 SQLConnection.openAsync() 方法的 openMode 参数的可能 值。 air.SQLColumnNameStyle 定义一组常量,它们表示 SQLConnection.columnNameStyle 属性的可能值。 air.SQLTransactionLockTyp e 定义一组常量,它们表示 SQLConnection.begin() 方法的 option 参数的可能值。 air.SQLCollationType 定义一组常数,它们表示 SQLColumnSchema() 构造函数的 SQLColumnSchema.defaultCollationType 属性和 defaultCollationType 参数的可能值。 类说明 air.SQLEvent 定义其任何操作成功执行时 SQLConnection 或 SQLStatement 实例调度的事件。每个操作都具有一个在 SQLEvent 类中定义的关联事件类型常数。 air.SQLErrorEvent 定义 SQLConnection 或 SQLStatement 实例在其任何操作导致错误时调度的事件。 air.SQLUpdateEvent 定义因执行 INSERT、 UPDATE 或 DELETE SQL 语句而导致其连接数据库之一中的表数据更改时 SQLConnection 实例调度的事件。179ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 关于同步和异步执行模式 Adobe AIR 1.0 和更高版本 编写代码以处理本地 SQL 数据库时,会指定以两种执行模式之一执行数据库操作:异步或同步执行模式。通常,代码示例说 明如何以这两种方式执行每个操作,以便您可以使用最适合您需求的示例。 在异步执行模式中,为运行时提供一个指令,运行时将在请求的操作完成或失败时调度事件。首先,通知数据库引擎执行操 作。在应用程序继续运行的同时,数据库引擎在后台工作。最后,完成操作时(或者它失败时),数据库引擎调度事件。由事 件触发的代码执行后续操作。此方法具有一个重要的优点:运行时在后台执行数据库操作,同时主应用程序代码继续执行。如 果数据库操作花费大量的时间,则应用程序继续运行。最重要的是,用户可以继续与其交互,而屏幕不会冻结。但是,与其他 代码相比,编写异步操作代码可能更加复杂。在必须将多个相关的操作分配给各个事件侦听器方法的情况下,通常会出现此复 杂性。 从概念上说,将操作作为单个步骤序列(一组同步操作,而不是分到几个事件侦听器方法中的一组操作)进行编码更为简单。 除了异步数据库操作外, Adobe AIR 还允许您同步执行数据库操作。在同步执行模式中,操作不在后台运行。相反,它们以 与所有其他应用程序代码相同的执行序列运行。通知数据库引擎执行操作。然后,代码在数据库引擎工作时暂停。完成操作 后,继续执行下一行代码。 异步还是同步执行操作是在 SQLConnection 级别上设置的。使用单个数据库连接,无法同步执行某些操作或语句,同时异步 执行其他操作或语句。通过调用 SQLConnection 方法打开数据库,可以指定 SQLConnection 是在同步还是异步执行模式下 操作。如果调用 SQLConnection.open(),则连接在同步执行模式下操作;如果调用 SQLConnection.openAsync(),则连接在异 步执行模式下操作。使用 open() 或 openAsync() 将 SQLConnection 实例连接到数据库后,除非先关闭再重新打开到数据库的 连接,否则该实例将固定为同步或异步执行模式。 每种执行模式各有其优点。虽然每种模式的大多数方面是类似的,但是在每种模式下工作时要牢记一些差异。有关这些主题的 详细信息以及在每种模式下工作的建议,请参阅第 198 页的 “ 使用同步和异步数据库操作 ”。 创建和修改数据库 Adobe AIR 1.0 和更高版本 数据库中必须定义了应用程序可以访问的表,应用程序才可以添加或检索数据。下面说明了创建数据库和在数据库中创建数据 结构的任务。虽然这些任务的使用频率低于数据插入和数据检索,但大多数应用程序都必须使用这些任务。 更多帮助主题 使用 Flex:更新现有 AIR 数据库 类说明 air.SQLError 提供有关数据库操作错误的信息,包括尝试的操作和出错原因。 air.SQLErrorOperation 定义一组常数,它们表示 SQLError 类的 operation 属性(它指示导致错误的数据库操作)的可能值。180ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 创建数据库 Adobe AIR 1.0 和更高版本 要创建数据库文件,需要首先创建 SQLConnection 实例。调用其 open() 方法在同步执行模式下打开它,或者调用其 openAsync() 方法在异步执行模式下打开它。open() 和 openAsync() 方法用于打开到数据库的连接。如果传递的 File 实例引用 reference 参数(第一个参数)的不存在的文件位置,则 open() 或 openAsync() 方法将在该文件位置创建一个数据库文件,并打 开到新创建的数据库的连接。 无论创建数据库时调用的是 open() 方法还是 openAsync() 方法,数据库文件的名称都可以是采用任何文件扩展名的任何有效文 件名。如果调用 reference 参数为 null 的 open() 或 openAsync() 方法,则将创建新的内存中数据库,而不是在磁盘上创建数据库 文件。 以下代码清单说明使用异步执行模式创建数据库文件(新数据库)的过程。在本例中,数据库文件保存在第 130 页的 “ 指向应 用程序存储目录 ” 中,文件名为 “DBSample.db”: // Include AIRAliases.js to use air.* shortcuts var conn = new air.SQLConnection(); conn.addEventListener(air.SQLEvent.OPEN, openHandler); conn.addEventListener(air.SQLErrorEvent.ERROR, errorHandler); // The database file is in the application storage directory var folder = air.File.applicationStorageDirectory; var dbFile = folder.resolvePath("DBSample.db"); conn.openAsync(dbFile); function openHandler(event) { air.trace("the database was created successfully"); } function errorHandler(event) { air.trace("Error message:", event.error.message); air.trace("Details:", event.error.details); } 注: 尽管 File 类用于指向特定本机文件路径,但这会导致应用程序无法跨平台工作。例如,路径 C:\Documents and Settings\joe\test.db 仅适用于 Windows。出于以上原因,最好使用 File 类的静态属性(如 File.applicationStorageDirectory) 和 resolvePath() 方法(如上一示例所示)。有关详细信息,请参阅第 128 页的 “File 对象的路径 ”。 要同步执行操作,请在使用 SQLConnection 实例打开数据库连接时,调用 open() 方法。以下示例说明如何创建和打开同步执 行其操作的 SQLConnection 实例:181ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 // Include AIRAliases.js to use air.* shortcuts var conn = new air.SQLConnection(); // The database file is in the application storage directory var folder = air.File.applicationStorageDirectory; var dbFile = folder.resolvePath("DBSample.db"); try { conn.open(dbFile); air.trace("the database was created successfully"); } catch (error) { air.trace("Error message:", error.message); air.trace("Details:", error.details); } 创建数据库表 Adobe AIR 1.0 和更高版本 在数据库中创建表包括使用与执行 SELECT、 INSERT 等 SQL 语句相同的过程对该数据库执行 SQL 语句。要创建表,请使用 CREATE TABLE 语句,该语句包括新表的列和约束的定义。有关执行 SQL 语句的详细信息,请参阅第 184 页的 “ 使用 SQL 语句 ”。 以下示例演示如何使用异步执行模式在现有数据库文件中创建一个名为 “employees” 的表。请注意,此代码假定存在一个名 为 conn 的 SQLConnection 实例,并且该实例已经实例化并连接到数据库。 // Include AIRAliases.js to use air.* shortcuts // ... create and open the SQLConnection instance named conn ... var createStmt = new air.SQLStatement(); createStmt.sqlConnection = conn; var sql = "CREATE TABLE IF NOT EXISTS employees (" + " empId INTEGER PRIMARY KEY AUTOINCREMENT, " + " firstName TEXT, " + " lastName TEXT, " + " salary NUMERIC CHECK (salary > 0)" + ")"; createStmt.text = sql; createStmt.addEventListener(air.SQLEvent.RESULT, createResult); createStmt.addEventListener(air.SQLErrorEvent.ERROR, createError); createStmt.execute(); function createResult(event) { air.trace("Table created"); } function createError(event) { air.trace("Error message:", event.error.message); air.trace("Details:", event.error.details); }182ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 以下示例演示如何使用同步执行模式在现有数据库文件中创建一个名为 “employees” 的表。请注意,此代码假定存在一个名 为 conn 的 SQLConnection 实例,并且该实例已经实例化并连接到数据库。 // Include AIRAliases.js to use air.* shortcuts // ... create and open the SQLConnection instance named conn ... var createStmt = new air.SQLStatement(); createStmt.sqlConnection = conn; var sql = "CREATE TABLE IF NOT EXISTS employees (" + " empId INTEGER PRIMARY KEY AUTOINCREMENT, " + " firstName TEXT, " + " lastName TEXT, " + " salary NUMERIC CHECK (salary > 0)" + ")"; createStmt.text = sql; try { createStmt.execute(); air.trace("Table created"); } catch (error) { air.trace("Error message:", error.message); air.trace("Details:", error.details); } 操作 SQL 数据库数据 Adobe AIR 1.0 和更高版本 使用本地 SQL 数据库时,会执行一些常见任务。这些任务包括连接到数据库、向数据库的表中添加数据以及从数据库的表中 检索数据。 执行这些任务时,还要牢记几个问题,例如使用数据类型和处理错误。 请注意,还有几个数据库任务的执行频率较低,但经常需要在执行这些更常见的任务之前执行。例如,需要创建数据库和在数 据库中创建表结构,才可以连接到数据库和从表中检索数据。第 179 页的 “ 创建和修改数据库 ” 中讨论了这些执行频率较低的 初始设置任务。 可以选择异步执行数据库操作,这意味着数据库引擎在后台运行并在操作成功或失败时通过调度事件来通知您。还可以同步执 行这些操作。在这种情况下,数据库操作依次执行,整个应用程序(包括对屏幕的更新)等待操作完成后再执行其他代码。有 关使用异步执行模式或同步执行模式的详细信息,请参阅第 198 页的 “ 使用同步和异步数据库操作 ”。 连接到数据库 Adobe AIR 1.0 和更高版本 在执行任何数据库操作之前,请首先打开到数据库文件的连接。 SQLConnection 实例用于表示到一个或多个数据库的连接。 使用 SQLConnection 实例连接的第一个数据库称为 “ 主 ” 数据库。此数据库是使用 open() 方法(对于同步执行模式)或 openAsync() 方法(对于异步执行模式)连接的。 如果使用异步 openAsync() 操作打开数据库,则注册 SQLConnection 实例的 open 事件,以便知道 openAsync() 操作何时完 成。注册 SQLConnection 实例的 error 事件,以确定操作是否失败。183ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 以下示例说明如何为异步执行打开现有的数据库文件。数据库文件名为 “DBSample.db”,位于用户的第 130 页的 “ 指向应用 程序存储目录 ” 下。 // Include AIRAliases.js to use air.* shortcuts var conn = new air.SQLConnection(); conn.addEventListener(air.SQLEvent.OPEN, openHandler); conn.addEventListener(air.SQLErrorEvent.ERROR, errorHandler); // The database file is in the application storage directory var folder = air.File.applicationStorageDirectory; var dbFile = folder.resolvePath("DBSample.db"); conn.openAsync(dbFile, air.SQLMode.UPDATE); function openHandler(event) { air.trace("the database opened successfully"); } function errorHandler(event) { air.trace("Error message:", event.error.message); air.trace("Details:", event.error.details); } 以下示例说明如何为同步执行打开现有的数据库文件。数据库文件名为 “DBSample.db”,位于用户的第 130 页的 “ 指向应用 程序存储目录 ” 下。 // Include AIRAliases.js to use air.* shortcuts var conn = new air.SQLConnection(); // The database file is in the application storage directory var folder = air.File.applicationStorageDirectory; var dbFile = folder.resolvePath("DBSample.db"); try { conn.open(dbFile, air.SQLMode.UPDATE); air.trace("the database opened successfully"); } catch (error) { air.trace("Error message:", error.message); air.trace("Details:", error.details); } 请注意,在异步示例的 openAsync() 方法调用中以及同步示例的 open() 方法调用中,第二个参数是常数 SQLMode.UPDATE。 如果指定的文件不存在,则为第二个参数 (openMode) 指定 SQLMode.UPDATE 会导致运行时调度一个错误。如果为 openMode 参数传递 SQLMode.CREATE(或者如果使 openMode 参数处于关闭状态),则在指定的文件不存在时,运行时将尝 试创建数据库文件。但是如果文件存在,则会打开该文件,这与使用 SQLMode.Update 相同。也可以为 openMode 参数指定 SQLMode.READ,以便在只读模式下打开现有的数据库。在这种情况下,可以从数据库检索数据,但是不能添加、删除或更改 数据。184ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 使用 SQL 语句 Adobe AIR 1.0 和更高版本 单个 SQL 语句(查询或命令)在运行时中表示为 SQLStatement 对象。按照以下步骤创建和执行 SQL 语句: 创建 SQLStatement 实例。 在您的应用程序中, SQLStatement 对象表示 SQL 语句。 var selectData = new air.SQLStatement(); 指定对其运行查询的数据库。 为此,请将 SQLStatement 对象的 sqlConnection 属性设置为与所需数据库连接的 SQLConnection 实例。 // A SQLConnection named "conn" has been created previously selectData.sqlConnection = conn; 指定实际的 SQL 语句。 将语句文本创建为字符串,并将其分配给 SQLStatement 实例的 text 属性。 selectData.text = "SELECT col1, col2 FROM my_table WHERE col1 = :param1"; 定义函数以处理执行操作的结果(仅限异步执行模式)。 使用 addEventListener() 方法将函数注册为 SQLStatement 实例的 result 和 error 事件的侦听器。 // using listener methods and addEventListener() selectData.addEventListener(air.SQLEvent.RESULT, resultHandler); selectData.addEventListener(air.SQLErrorEvent.ERROR, errorHandler); function resultHandler(event) { // do something after the statement execution succeeds } function errorHandler(event) { // do something after the statement execution fails } 或者,可以使用 Responder 对象指定侦听器方法。在这种情况下,创建 Responder 实例并将侦听器方法链接到该实例。 // using a Responder var selectResponder = new air.Responder(onResult, onError); function onResult(result) { // do something after the statement execution succeeds } function onError(error) { // do something after the statement execution fails } 如果语句文本包括参数定义,则分配这些参数的值。 若要分配参数值,请使用 SQLStatement 实例的 parameters 关联数组属性。 selectData.parameters[":param1"] = 25;185ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 执行 SQL 语句。 调用 SQLStatement 实例的 execute() 方法。 // using synchronous execution mode // or listener methods in asynchronous execution mode selectData.execute(); 此外,如果在异步执行模式下使用 Responder 而不是事件侦听器,则将 Responder 实例传递到 execute() 方法。 // using a Responder in asynchronous execution mode selectData.execute(-1, selectResponder); 有关演示这些步骤的特定示例,请参阅以下主题: 第 187 页的 “ 从数据库检索数据 ” 第 192 页的 “ 插入数据 ” 第 195 页的 “ 更改或删除数据 ” 在语句中使用参数 Adobe AIR 1.0 和更高版本 使用 SQL 语句参数,您可以创建可重用的 SQL 语句。使用语句参数时,语句中的值可以更改(如在 INSERT 语句中添加的 值),但是基本的语句文本保持不变。所以,使用参数可提供性能优势,并且可以更轻松地进行应用程序编码。 了解语句参数 Adobe AIR 1.0 和更高版本 应用程序经常在自身中多次使用单个 SQL 语句,只是稍有不同。以一个库存跟踪应用程序为例,用户可以在其中向数据库添 加新的库存项目。向数据库添加库存项目的应用程序代码执行 SQL INSERT 语句,该语句实际上向数据库添加数据。但是,每 次执行该语句时都稍有不同。具体来说,在表中插入的实际值是不同的,因为它们特定于所添加的库存项目。 在多次使用一个 SQL 语句但该语句中的值不同的情况下,最佳方法是使用包括参数的 SQL 语句而不是在 SQL 文本中包括字 面值。参数是语句文本中的一个占位符,每次执行语句时都将它替换为实际的值。要在 SQL 语句中使用参数,请像通常一样创 建 SQLStatement 实例。对于分配给 text 属性的实际 SQL 语句,使用参数占位符而不是字面值。然后通过在 SQLStatement 实例的 parameters 属性中设置元素值来定义每个参数的值。 parameters 属性是一个关联数组,所以需要使用以下语法设置特殊 值: statement.parameters[parameter_identifier] = value; 如果使用命名参数,则 parameter_identifier 是字符串;如果使用未命名参数,则它是整数索引。 使用命名参数 Adobe AIR 1.0 和更高版本 参数可以是命名参数。命名参数具有一个特定的名称,数据库使用该名称将参数值与语句文本中其占位符位置相匹配。参数名 称由 “:” 或 “@” 字符后跟一个名称组成,如以下示例所示: :itemName @firstName 以下代码清单演示命名参数的用法:186ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 var sql = "INSERT INTO inventoryItems (name, productCode)" + "VALUES (:name, :productCode)"; var addItemStmt = new air.SQLStatement(); addItemStmt.sqlConnection = conn; addItemStmt.text = sql; // set parameter values addItemStmt.parameters[":name"] = "Item name"; addItemStmt.parameters[":productCode"] = "12345"; addItemStmt.execute(); 使用未命名参数 Adobe AIR 1.0 和更高版本 作为使用命名参数的一种替代方式,也可以使用未命名参数。若要使用未命名参数,请使用 “?” 字符表示 SQL 语句中的参数。 按照参数在语句中的顺序,每个参数都分配有一个数字索引,数字索引从索引 0 (表示第一个参数)开始。以下示例使用未命 名参数演示上述示例的一个版本: var sql = "INSERT INTO inventoryItems (name, productCode)" + "VALUES (?, ?)"; var addItemStmt = new air.SQLStatement(); addItemStmt.sqlConnection = conn; addItemStmt.text = sql; // set parameter values addItemStmt.parameters[0] = "Item name"; addItemStmt.parameters[1] = "12345"; addItemStmt.execute(); 使用参数的优点 Adobe AIR 1.0 和更高版本 在 SQL 语句中使用参数有以下几个优点: 性能更佳 与每次执行时动态创建 SQL 文本的 SQLStatement 实例相比,使用参数的 SQLStatement 实例可以更高效地执行。 性能之所以得到提高,是因为只准备一次语句,然后可以使用不同的参数值多次执行它,而无需重新编译 SQL 语句。 显式数据类型指定 参数用于允许对构造 SQL 语句时未知的值进行类型替代。使用参数是保证将值的存储类传递到数据库的唯一 方式。不使用参数时,运行时会尝试根据相关联列的类型关联将所有值从其文本表示形式转换为存储类。 有关存储类和列关联的详细信息,请参阅第 310 页的 “ 数据类型支持 ”。 安全性更高 使用参数有助于防止恶意技术攻击(称为 SQL 注入攻击)。在 SQL 注入攻击中,用户在用户可访问的位置(例如 数据输入字段)输入 SQL 代码。如果应用程序代码通过将用户输入直接连接到 SQL 文本来构造 SQL 语句,则将对数据库执行 用户输入的 SQL 代码。下面的列表显示将用户输入连接到 SQL 文本的示例。不要使用此技术:187ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 // assume the variables "username" and "password" // contain user-entered data var sql = "SELECT userId " + "FROM users " + "WHERE username = '" + username + "' " + " AND password = '" + password + "'"; var statement = new air.SQLStatement(); statement.text = sql; 使用语句参数而不是将用户输入的值连接到语句的文本中,可防止 SQL 注入攻击。 SQL 注入无法发生的原因是,系统将参数 值明确视为替代值,而不是作为字面语句文本的一部分。下面是对前面列表的建议替代方法: // assume the variables "username" and "password" // contain user-entered data var sql = "SELECT userId " + "FROM users " + "WHERE username = :username " + " AND password = :password"; var statement = new air.SQLStatement(); statement.text = sql; // set parameter values statement.parameters[":username"] = username; statement.parameters[":password"] = password; 从数据库检索数据 Adobe AIR 1.0 和更高版本 从数据库检索数据分为以下两步。首先,执行 SQL SELECT 语句(描述要从数据库检索的一组数据)。然后,访问已检索的数 据,并根据需要由应用程序显示或操作它。 执行 SELECT 语句 Adobe AIR 1.0 和更高版本 要从数据库检索现有数据,请使用 SQLStatement 实例。将相应的 SQL SELECT 语句分配给实例的 text 属性,然后调用其 execute() 方法。 有关 SELECT 语句的语法的详细信息,请参阅第 293 页的 “ 本地数据库中的 SQL 支持 ”。 以下示例演示如何使用异步执行模式执行 SELECT 语句从名为 “products” 的表中检索数据:188ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 // Include AIRAliases.js to use air.* shortcuts var selectStmt = new air.SQLStatement(); // A SQLConnection named "conn" has been created previously selectStmt.sqlConnection = conn; selectStmt.text = "SELECT itemId, itemName, price FROM products"; selectStmt.addEventListener(air.SQLEvent.RESULT, resultHandler); selectStmt.addEventListener(air.SQLErrorEvent.ERROR, errorHandler); selectStmt.execute(); function resultHandler(event) { var result = selectStmt.getResult(); var numResults = result.data.length; for (i = 0; i < numResults; i++) { var row = result.data[i]; var output = "itemId: " + row.itemId; output += "; itemName: " + row.itemName; output += "; price: " + row.price; air.trace(output); } } function errorHandler(event) { // Information about the error is available in the // event.error property, which is an instance of // the SQLError class. } 以下示例演示如何使用同步执行模式执行 SELECT 语句从名为 “ 产品 ” 的表检索数据:189ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 // Include AIRAliases.js to use air.* shortcuts var selectStmt = new air.SQLStatement(); // A SQLConnection named "conn" has been created previously selectStmt.sqlConnection = conn; selectStmt.text = "SELECT itemId, itemName, price FROM products"; try { selectStmt.execute(); var result = selectStmt.getResult(); var numResults = result.data.length; for (i = 0; i < numResults; i++) { var row = result.data[i]; var output = "itemId: " + row.itemId; output += "; itemName: " + row.itemName; output += "; price: " + row.price; air.trace(output); } } catch (error) { // Information about the error is available in the // error variable, which is an instance of // the SQLError class. } 在异步执行模式下,语句完成执行时, SQLStatement 实例调度 result 事件 (SQLEvent.RESULT),指示该语句已成功运行。或 者,如果 Responder 对象作为参数传递给 execute() 方法,则调用 Responder 对象的结果处理函数。在同步执行模式下,执行 暂停,直到 execute() 操作完成,然后继续执行下一行代码。 访问 SELECT 语句结果数据 Adobe AIR 1.0 和更高版本 SELECT 语句完成执行后,下一步是访问已检索的数据。通过调用 SQLStatement 对象的 getResult() 方法,从执行 SELECT 语 句中检索结果数据: var result = selectStatement.getResult(); getResult() 方法返回 SQLResult 对象。 SQLResult 对象的 data 属性是一个包含 SELECT 语句的结果的数组: var numResults = result.data.length; for (var i = 0; i < numResults; i++) { // row is an Object representing one row of result data var row = result.data[i]; } SELECT 结果集中的每行数据成为包含在 data 数组中的 Object 实例。该对象具有其名称与结果集的列名称匹配的属性。该属 性包含结果集的列值。例如,假定 SELECT 语句指定一个结果集,该结果集具有名为 “itemId”、 “itemName” 和 “price” 的 三个列。对于结果集中的每一行,使用名为 itemId、 itemName 和 price 的属性创建 Object 实例。这些属性包含来自其相应列 的值。190ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 以下代码清单定义其文本为 SELECT 语句的 SQLStatement 实例。该语句从名为 employees 的表的所有行中检索包含 firstName 和 lastName 列值的行。此示例使用异步执行模式。执行完成时,调用 selectResult() 方法,使用 SQLStatement.getResult() 访问生成的数据行,使用 trace() 方法显示它们。请注意,此列表假定存在一个名为 conn、已进行实 例化并连接到数据库的 SQLConnection 实例。它还假定已创建 “employees” 表并为其填充了数据。 // Include AIRAliases.js to use air.* shortcuts // ... create and open the SQLConnection instance named conn ... // create the SQL statement var selectStmt = new air.SQLStatement(); selectStmt.sqlConnection = conn; // define the SQL text var sql = "SELECT firstName, lastName " + "FROM employees"; selectStmt.text = sql; // register listeners for the result and error events selectStmt.addEventListener(air.SQLEvent.RESULT, selectResult); selectStmt.addEventListener(air.SQLErrorEvent.ERROR, selectError); // execute the statement selectStmt.execute(); function selectResult(event) { // access the result data var result = selectStmt.getResult(); var numRows = result.data.length; for (i = 0; i < numRows; i++) { var output = ""; for (columnName in result.data[i]) { output += columnName + ": " + result.data[i][columnName] + "; "; } air.trace("row[" + i.toString() + "]\t", output); } } function selectError(event) { air.trace("Error message:", event.error.message); air.trace("Details:", event.error.details); } 以下代码清单演示与前面的代码清单相同的技术,但使用的是同步执行模式。该示例定义其文本为 SELECT 语句的 SQLStatement 实例。该语句从名为 employees 的表的所有行中检索包含 firstName 和 lastName 列值的行。使用 SQLStatement.getResult() 访问生成的数据行,并使用 trace() 方法显示它们。请注意,此列表假定存在一个名为 conn、已进行 实例化并连接到数据库的 SQLConnection 实例。它还假定已创建 “employees” 表并为其填充了数据。191ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 // Include AIRAliases.js to use air.* shortcuts // ... create and open the SQLConnection instance named conn ... // create the SQL statement var selectStmt = new air.SQLStatement(); selectStmt.sqlConnection = conn; // define the SQL text var sql = "SELECT firstName, lastName " + "FROM employees"; selectStmt.text = sql; try { // execute the statement selectStmt.execute(); // access the result data var result = selectStmt.getResult(); var numRows = result.data.length; for (i = 0; i < numRows; i++) { var output = ""; for (columnName in result.data[i]) { output += columnName + ": " + result.data[i][columnName] + "; "; } air.trace("row[" + i.toString() + "]\t", output); } } catch (error) { air.trace("Error message:", error.message); air.trace("Details:", error.details); } 定义 SELECT 结果数据的数据类型 Adobe AIR 1.0 和更高版本 默认情况下,由 SELECT 语句返回的每行都创建为 Object 实例,以结果集的列名作为属性名,每列的值作为其关联属性的值。 但是,在执行 SQL SELECT 语句之前,可以将 SQLStatement 实例的 itemClass 属性设置为类。通过设置 itemClass 属性,由 SELECT 语句返回的每个行将创建为指定类的实例。通过将 SELECT 结果集中的列名与 itemClass 类中的属性名相匹配,运行时 将结果列值分配给属性值。 作为 itemClass 属性值分配的任何类都必须具有不需要任何参数的构造函数。另外,对于由 SELECT 语句返回的每个列,该类 必须具有一个单一的属性。如果 SELECT 列表中的列在 itemClass 类中没有相匹配的属性名称,系统会将其视为错误。 检索部分 SELECT 结果 Adobe AIR 1.0 和更高版本 默认情况下,执行 SELECT 语句会一次检索结果集的所有行。语句完成后,通常以某种方式处理检索的数据,如创建对象或在 屏幕上显示数据。如果语句返回了大量的行,则同时处理所有数据可能对计算机要求过高,这又会导致用户界面无法自行重 绘。192ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 通过指示运行时一次返回特定数量的结果行,可以提高应用程序的感知性能。这样做会使初始结果数据更快地返回。它还允许 您将结果行分到各组中,以便在处理每组行后更新用户界面。请注意,只有在异步执行模式下使用此技术才是可行的。 要检索部分 SELECT 结果,请为 SQLStatement.execute() 方法的第一个参数( prefetch 参数)指定一个值。 prefetch 参数指示首 次执行语句时检索的行数。调用 SQLStatement 实例的 execute() 方法时,请指定 prefetch 参数值,并只检索由此值指定的行 数: // Include AIRAliases.js to use air.* shortcuts var stmt = new air.SQLStatement(); stmt.sqlConnection = conn; stmt.text = "SELECT ..."; stmt.addEventListener(air.SQLEvent.RESULT, selectResult); stmt.execute(20); // only the first 20 rows (or fewer) are returned 该语句调度 result 事件,指示第一组结果行是可用的。得到的 SQLResult 实例的 data 属性包含数据行,并且其 complete 属性 指示是否存在要检索的其他结果行。要检索其他结果行,请调用 SQLStatement 实例的 next() 方法。与 execute() 方法一样, 使用 next() 方法的第一个参数指示下次调度 result 事件时要检索的行数。 function selectResult(event) { var result = stmt.getResult(); if (result.data != null) { // ... loop through the rows or perform other processing ... if (!result.complete) { stmt.next(20); // retrieve the next 20 rows } else { stmt.removeEventListener(air.SQLEvent.RESULT, selectResult); } } } 每次 next() 方法返回后续的一组结果行时, SQLStatement 都会调度 result 事件。因此,可以使用同一侦听器函数继续处理结 果 (通过 next() 调用),直到检索了所有行。 有关详细信息,请参阅 SQLStatement.execute() 方法( prefetch 参数描述)和 SQLStatement.next() 方法的描述。 插入数据 Adobe AIR 1.0 和更高版本 向数据库添加数据包括执行 SQL INSERT 语句。语句完成执行后,如果数据库生成了键,则可以访问新插入的行的主键。 执行 INSERT 语句 Adobe AIR 1.0 和更高版本 要向数据库中的表添加数据,请创建并执行其文本为 SQL INSERT 语句的 SQLStatement 实例。 以下示例使用 SQLStatement 实例向已存在的 employees 表添加数据行。此示例演示如何使用异步执行模式插入数据。请注 意,此列表假定存在一个名为 conn 的 SQLConnection 实例,并且该实例已经实例化并连接到数据库。它还假定已创建 “employees” 表。193ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 // Include AIRAliases.js to use air.* shortcuts // ... create and open the SQLConnection instance named conn ... // create the SQL statement var insertStmt = new air.SQLStatement(); insertStmt.sqlConnection = conn; // define the SQL text var sql = "INSERT INTO employees (firstName, lastName, salary) " + "VALUES ('Bob', 'Smith', 8000)"; insertStmt.text = sql; // register listeners for the result and failure (status) events insertStmt.addEventListener(air.SQLEvent.RESULT, insertResult); insertStmt.addEventListener(air.SQLErrorEvent.ERROR, insertError); // execute the statement insertStmt.execute(); function insertResult(event) { air.trace("INSERT statement succeeded"); } function insertError(event) { air.trace("Error message:", event.error.message); air.trace("Details:", event.error.details); } 以下示例使用同步执行模式向已存在的 employees 表添加数据行。请注意,此列表假定存在一个名为 conn 的 SQLConnection 实例,并且该实例已经实例化并连接到数据库。它还假定已创建 “employees” 表。 // Include AIRAliases.js to use air.* shortcuts // ... create and open the SQLConnection instance named conn ... // create the SQL statement var insertStmt = new air.SQLStatement(); insertStmt.sqlConnection = conn; // define the SQL text var sql = "INSERT INTO employees (firstName, lastName, salary) " + "VALUES ('Bob', 'Smith', 8000)"; insertStmt.text = sql; try { // execute the statement insertStmt.execute(); air.trace("INSERT statement succeeded"); } catch (error) { air.trace("Error message:", error.message); air.trace("Details:", error.details); }194ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 检索已插入行的数据库生成的主键 Adobe AIR 1.0 和更高版本 通常,向表中插入数据行后,代码需要知道新插入行的数据库生成的主键或行标识符值。例如,在一个表中插入行后,您可能 希望在相关表中添加行。在这种情况下,希望将主键值作为外键插入到相关表中。新插入的行的主键可使用与语句执行相关联 的 SQLResult 对象进行检索。这是在执行 SELECT 语句后用来访问结果数据的同一对象。与任何 SQL 语句一样, INSERT 语 句执行完成时,运行时将创建 SQLResult 实例。如果您使用的是事件侦听器或同步执行模式,则可通过调用 SQLStatement 对象的 getResult() 方法来访问 SQLResult 实例。或者,如果您使用的是异步执行模式并将 Responder 实例传递给 execute() 调 用,则 SQLResult 实例将作为参数传递给结果处理函数。在任一情况下, SQLResult 实例都具有属性 lastInsertRowID ;如果 执行的 SQL 语句是 INSERT 语句,则该属性包含最近插入的行的行标识符。 以下示例演示如何在异步执行模式下访问已插入行的主键: insertStmt.text = "INSERT INTO ..."; insertStmt.addEventListener(air.SQLEvent.RESULT, resultHandler); insertStmt.execute(); function resultHandler(event) { // get the primary key var result = insertStmt.getResult(); var primaryKey = result.lastInsertRowID; // do something with the primary key } 以下示例演示如何在同步执行模式下访问已插入行的主键: insertStmt.text = "INSERT INTO ..."; try { insertStmt.execute(); // get the primary key var result = insertStmt.getResult(); var primaryKey = result.lastInsertRowID; // do something with the primary key } catch (error) { // respond to the error } 请注意,根据以下规则,行标识符可能是也可能不是在表定义中指定为主键列的列值: • 如果表是用其关联(列数据类型)为 INTEGER 的主键列定义的,则 lastInsertRowID 属性包含插入到该行中的值(如果它 是 AUTOINCREMENT 列,则为由运行时生成的值)。 • 如果表是用多个主键列(组合键)或其关联不是 INTEGER 的单个主键列定义的,则数据库将在后台为行生成整数行标识 符值。该生成的值是 lastInsertRowID 属性的值。 • 该值始终是最近插入的行的行标识符。如果 INSERT 语句导致一个触发器激发(这将插入一行),则 lastInsertRowID 属性 包含由触发器插入的最后一行的行标识符,而不是由 INSERT 语句创建的行的行标识符。 由于存在这些规则,因此,如果您希望获得明确定义的主键列,并且其值通过 SQLResult.lastInsertRowID 属性调用 INSERT 命 令后获得,则该列必须定义为 INTEGER PRIMARY KEY 列。即使表不包括显式 INTEGER PRIMARY KEY 列,但就定义与相关 表的关系而言,将数据库生成的行标识符用作表的主键也是同样可接受的。通过使用特殊的列名 ROWID、 _ROWID_ 或 OID 195ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 之一,行标识符列值在任何 SQL 语句中都是可用的。可以在相关表中创建外键列,并将行标识符值用作外键列值,就像明确声 明的 INTEGER PRIMARY KEY 列一样。在该意义上,如果使用的是任意主键而不是自然键,并且只要您不在乎生成主键值的 运行时,则将 INTEGER PRIMARY KEY 列还是系统生成的行标识符用作表的主键以定义两个表之间的外键关系几乎没有差别。 有关主键和生成的行标识符的详细信息,请参阅第 293 页的 “ 本地数据库中的 SQL 支持 ”。 更改或删除数据 Adobe AIR 1.0 和更高版本 执行其他数据处理操作的过程和用于执行 SQL SELECT 或 INSERT 语句的过程相同,具体内容在第 184 页的 “ 使用 SQL 语句 ” 中进行了介绍。仅需使用 SQLStatement 实例的 text 属性中的不同 SQL 语句进行替换即可: • 若要更改表中的现有数据,请使用 UPDATE 语句。 • 要从表中删除一行或多行数据,请使用 DELETE 语句。 有关这些语句的说明,请参阅第 293 页的 “ 本地数据库中的 SQL 支持 ”。 使用多个数据库 Adobe AIR 1.0 和更高版本 使用 SQLConnection.attach() 方法,在已具有打开的数据库的 SQLConnection 实例上打开到其他数据库的连接。在 attach() 方法调用中,使用 name 参数为附加的数据库提供一个名称。在编写语句操作该数据库时,可以在前缀中使用该名称(使用格 式 database-name.table-name)在 SQL 语句中限定任何表名,指示运行时可以在指定的数据库中找到该表。 可以执行包括多个数据库中的表的单个 SQL 语句,这些数据库连接到同一 SQLConnection 实例。如果事务是在 SQLConnection 实例上创建的,则该事务适用于使用 SQLConnection 实例执行的所有 SQL 语句。不管语句运行在哪个附 加的数据库上,这一点都适用。 或者,也可以在一个应用程序中创建多个 SQLConnection 实例,其中每个实例都连接到一个或多个数据库。但是,如果确实 使用到同一数据库的多个连接,请牢记数据库事务不是跨 SQLConnection 实例共享的。因此,如果使用多个 SQLConnection 实例连接到同一数据库文件,则不能指望以预期方式应用这两个连接的数据更改。例如,如果通过不同的 SQLConnection 实例对同一数据库运行两个 UPDATE 或 DELETE 语句,并且在一个操作发生后出现应用程序错误,则数据 库数据可能处于不可逆的中间状态,而且可能影响数据库的完整性(进而影响应用程序)。 处理数据库错误 Adobe AIR 1.0 和更高版本 通常,数据库错误处理与其他运行时错误处理类似。应该编写代码以备可能出现的错误,并对错误作出响应,而不是直到运行 时才这样做。通常认为,可以将可能的数据库错误分为以下三类:连接错误、 SQL 语法错误和约束错误。 连接错误 Adobe AIR 1.0 和更高版本 大多数的数据库错误是连接错误,它们可能出现在任何操作过程中。尽管存在防止连接错误的策略,但是,如果数据库是应用 程序的关键部分,则几乎没有从连接错误中正常恢复的简单方法。196ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 大多数连接错误与运行时和操作系统、文件系统及数据库文件交互的方式有关。例如,如果用户没有在文件系统上的特定位置 创建数据库文件的权限,则会出现连接错误。以下策略有助于防止连接错误: 使用特定于用户的数据库文件 为每个用户提供其自己的数据库文件,而不是将单个数据库文件用于在单个计算机上使用应用程 序的所有用户。该文件应该位于与用户帐户关联的目录中。例如,它可能在以下位置:应用程序的存储目录、用户的文档文件 夹、用户的桌面等。 考虑不同的用户类型 在不同的操作系统上,用不同类型的用户帐户测试应用程序。请勿假定用户具有计算机上的管理员权限。 此外,请勿假定安装了某应用程序的个人是运行该应用程序的用户。 考虑各个文件位置 如果允许用户指定保存数据库文件的位置或者选择要打开的文件,请考虑用户可能使用的文件位置。此外, 请考虑定义对用户可以存储(或他们可以从中打开)数据库文件的位置的限制。例如,可以仅允许用户打开位于其用户帐户存 储位置中的文件。 如果出现连接错误,则很可能出现在创建或打开数据库的首次尝试中。这意味着用户无法在应用程序中执行与数据库相关的任 何操作。对于某些类型的错误,如只读或权限错误,一种可能的恢复技术是将数据库文件复制到其他位置。应用程序可以将数 据库文件复制到用户有权创建和写入文件的其他位置,然后改用该位置。 语法错误 Adobe AIR 1.0 和更高版本 在 SQL 语句格式不正确,而应用程序尝试执行该语句时,会出现语法错误。由于本地数据库 SQL 语句是作为字符串创建的, 因此无法进行编译时 SQL 语法检查。必须执行所有 SQL 语句才能检查其语法。使用以下策略可防止 SQL 语法错误: 全面地测试所有 SQL 语句 如有可能,在开发应用程序的过程中,将 SQL 语句编码为应用程序代码中的语句文本之前,单独对 其进行测试。此外,使用代码测试方法(如单元测试)创建一组测试,在代码中运用每个可能的选项和变体。 使用语句参数和避免连接的(动态生成的) SQL 使用参数和避免动态生成的 SQL 语句,意味着每次执行语句时都使用相同的 SQL 语句文本。因此,测试语句和限制可能的变体更为容易。如果必须动态生成 SQL 语句,请将语句的动态部分保持在最小 限度内。此外,仔细验证任何用户输入,以确保它不会导致语法错误。 若要从语法错误中恢复,应用程序将需要复杂的逻辑才能检查 SQL 语句和更正其语法。通过遵循用于防止语法错误的上述准 则,您的代码可以识别 SQL 语法错误的任何潜在运行时根源(如语句中使用的用户输入)。若要从语法错误中恢复,请为用户 提供指导。指出要更正哪些内容才能使语句正确执行。 约束错误 Adobe AIR 1.0 和更高版本 在 INSERT 或 UPDATE 语句尝试向列添加数据时,会出现约束错误。如果新数据违反表或列的已定义约束之一,则会发生该错 误。一组可能的约束包括: 唯一约束 指示对于表中的所有行,在一个列中不能有重复值。或者,将多个列组合在唯一约束中时,这些列中值的组合不得重 复。换句话说,对于指定的具有唯一性的一列或多列,每个行必须是不同的。 主键约束 对于约束允许和不允许的数据,主键约束与唯一约束完全相同。 非 null 约束 指定单个列不能存储 NULL 值,因此在每个行中,该列必须具有一个值。 检查约束 允许您在一个或多个表上指定任意约束。常见的检查约束是一个规则,它定义列的值必须在某些界限内(例如,数字 列的值必须大于 0)。另一种常见的检查约束类型指定列值之间的关系(例如,一个列的值必须与同一行中其他列的值不同)。 数据类型(列关联)约束 运行时强制实施列值的数据类型,尝试将类型不正确的值存储在列中时会出现错误。但是,在许多情 况下,会转换值以匹配列的已声明数据类型。有关详细信息,请参阅第 197 页的 “ 使用数据库数据类型 ”。 运行时不对外键值强制实施约束。换句话说,匹配现有的主键值不需要外键值。197ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 除了预定义的约束类型外,运行时 SQL 引擎还支持使用触发器。触发器类似于事件处理函数。 它是发生某个操作时执行的一组 预定义指令。例如,可以定义一个触发器,它在向特定表插入数据或从中删除数据时运行。触发器的一个可能用途是检查数据 更改,并在不满足指定的条件时导致出现错误。因此,触发器可以具有与约束相同的用途,防止约束错误和从中恢复的策略也 适用于触发器生成的错误。但是,触发器生成的错误的错误 id 与约束错误的错误 id 不同。 在设计应用程序时,就确定了适用于特定表的一组约束。通过有意识地设计约束,可以更轻松地设计应用程序,以防止约束错 误和从中恢复。但是,约束错误很难系统地预测和预防。很难预测的原因是,约束错误在添加应用程序数据后才出现。数据在 创建后被添加到数据库时会出现约束错误。这些错误通常是由新数据和已经存在于数据库中的数据之间的关系导致的。以下策 略可以帮助您避免许多约束错误: 仔细计划数据库结构和约束 约束的用途是强制实施应用程序规则和帮助保护数据库数据的完整性。在计划应用程序时,请考虑 如何构建数据库来支持您的应用程序。作为该过程的一部分,确定数据的规则,如某些值是否必需、某值是否具有默认值、是 否允许重复值等。这些规则可以指导您定义数据库约束。 明确指定列名 可以编写 INSERT 语句而不明确指定要在其中插入值的列,但是这样做会产生不必要的风险。通过明确命名要在 其中插入值的列,可以允许自动生成的值、具有默认值的列和允许 NULL 值的列。此外,这样做可确保所有的 NOT NULL 列 都插入了显式值。 使用默认值 每当为列指定 NOT NULL 约束时,尽可能在列定义中指定默认值。应用程序代码也可以提供默认值。例如,代码 可以检查 String 变量是否为 null,并在使用它设置语句参数值之前为它分配一个值。 验证用户输入的数据 提前检查用户输入的数据,以确保它符合约束指定的限制,尤其是对于 NOT NULL 和 CHECK 约束。当 然, UNIQUE 约束更难检查,因为这样做会要求执行 SELECT 查询来确定数据是否唯一。 使用触发器 可以编写一个触发器,用于验证(并可能替换)插入的数据或执行其他操作以更正无效的数据。此验证和更正可防 止出现约束错误。 在许多方面,约束错误比其他类型的错误更难防范。幸运的是,有几个从约束错误恢复的策略,这样就不会使应用程序变得不 稳定或不可用: 使用冲突算法 在列上定义约束时,以及创建 INSERT 或 UPDATE 语句时,您可以选择指定冲突算法。冲突算法定义在出现约 束违规时数据库执行的操作。数据库引擎可以执行几种可能的操作。数据库引擎可以结束单个语句或整个事务。它可以忽略错 误。它甚至可以删除旧数据,并将它替换为代码尝试存储的数据。 有关详细信息,请参阅第 293 页的 “ 本地数据库中的 SQL 支持 ” 中的 “ON CONFLICT (冲突算法) ” 部分。 提供纠正反馈 可以提前识别可能影响特定 SQL 命令的一组约束。因此,可以预期语句可能导致的约束错误。知道这一点,就 可以生成应用程序逻辑来响应约束错误。例如,假定应用程序包括用于输入新产品的数据条目表单。如果数据库中的产品名称 列是用 UNIQUE 约束定义的,则在数据库中插入新产品行的操作可能会导致约束错误。因此,应用程序设计用于预期约束错 误。在错误发生时,应用程序将提醒用户,指出指定的产品名称已在使用中,并要求用户选择其他名称。另一种可能的响应 是,允许用户查看有关同名的其他产品的信息。 使用数据库数据类型 Adobe AIR 1.0 和更高版本 在数据库中创建表时,用于创建表的 SQL 语句将为表中的每个列定义关联或数据类型。尽管可以省略关联声明,但是最好在 CREATE TABLE SQL 语句中明确声明列关联。 通常,在执行 SELECT 语句时,使用 INSERT 语句存储在数据库中的任何对象都将作为相同数据类型的实例返回。但是,已检 索值的数据类型可能随存储该值的数据库列的关联的不同而不同。当值存储在列中时,如果其数据类型与列的关联不匹配,则 数据库会尝试转换该值以便与列的关联匹配。例如,如果数据库列是用 NUMERIC 关联声明的,则在存储数据之前,数据库会 尝试将插入的数据转换为数字存储类( INTEGER 或 REAL)。如果无法转换数据,则数据库将引发错误。按照此规则,如果将 字符串 “12345” 插入到 NUMERIC 列中,则在将它存储在数据库中之前,数据库会自动将它转换为整数值 12345。使用 SELECT 语句检索该值时,它将作为数字数据类型(如 Number)的实例而不是 String 实例返回。198ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 避免不需要的数据类型转换的最佳方式是遵循以下两个规则。首先,使用与其要存储的数据类型匹配的关联定义每个列。其 次,仅插入其数据类型与定义的关联匹配的值。遵循这些规则有两个优点。插入数据时,不会意外转换它(结果是可能丢失其 预期含义)。此外,检索数据时,它会按其原始数据类型返回。 有关可用列关联类型以及如何在 SQL 语句中使用数据类型的详细信息,请参阅第 310 页的 “ 数据类型支持 ”。 使用同步和异步数据库操作 Adobe AIR 1.0 和更高版本 前面几节已描述常见的数据库操作,如检索、插入、更新和删除数据,以及在数据库中创建数据库文件和表以及其他对象。示 例已演示如何以异步和同步方式执行这些操作。 需要提醒的是,在异步执行模式下,您指示数据库引擎执行操作。然后,在应用程序保持运行的同时,数据库引擎在后台工 作。当操作完成时,数据库引擎调度事件以提醒您该情况。异步执行的主要优点是,在主应用程序代码继续执行的同时,运行 时在后台执行数据库操作。当操作运行所用时间非常长时,这尤其有价值。 另一方面,在同步执行模式下,操作不在后台运行。通知数据库引擎执行操作。代码在数据库引擎工作时暂停。完成操作后, 继续执行下一行代码。 使用单个数据库连接,无法同步执行某些操作或语句,同时异步执行其他操作或语句。指定当您打开到数据库的连接时,是异 步还是同步操作 SQLConnection。如果调用 SQLConnection.open(),则连接在同步执行模式下操作;如果调用 SQLConnection.openAsync(),则连接在异步执行模式下操作。使用 open() 或 openAsync() 将 SQLConnection 实例连接到数 据库后,该实例将固定为同步或异步执行。 使用同步数据库操作 Adobe AIR 1.0 和更高版本 与异步执行模式的代码相比,使用同步执行时用于执行和响应操作的实际代码几乎没有差异。两种方法之间的主要差异体现在 以下两个方面。首先,执行一个依赖于另一个操作(如 SELECT 结果行或由 INSERT 语句添加的行的主键)的操作。第二方面 的差异体现在处理错误上。 为同步操作编写代码 Adobe AIR 1.0 和更高版本 同步执行和异步执行的主要差异在于:在同步模式下,以单个步骤系列的形式编写代码。相反,在异步代码中,注册事件侦听 器,并经常在侦听器方法之间分配操作。当在同步执行模式下连接数据库时,可以在单个代码块中连续执行一系列数据库操 作。以下示例对此技术进行了演示:199ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 // Include AIRAliases.js to use air.* shortcuts var conn = new air.SQLConnection(); // The database file is in the application storage directory var folder = File.applicationStorageDirectory; var dbFile = folder.resolvePath("DBSample.db"); // open the database conn.open(dbFile, air.OpenMode.UPDATE); // start a transaction conn.begin(); // add the customer record to the database var insertCustomer = new air.SQLStatement(); insertCustomer.sqlConnection = conn; insertCustomer.text = "INSERT INTO customers (firstName, lastName) " + "VALUES ('Bob', 'Jones')"; insertCustomer.execute(); var customerId = insertCustomer.getResult().lastInsertRowID; // add a related phone number record for the customer var insertPhoneNumber = new air.SQLStatement(); insertPhoneNumber.sqlConnection = conn; insertPhoneNumber.text = "INSERT INTO customerPhoneNumbers (customerId, number) " + "VALUES (:customerId, '800-555-1234')"; insertPhoneNumber.parameters[":customerId"] = customerId; insertPhoneNumber.execute(); // commit the transaction conn.commit(); 如您所看到的,不管使用的是同步执行还是异步执行,都调用相同的方法来执行数据库操作。两种方法的主要差异在于:执行 一个依赖于另一个操作的操作和处理错误。 执行一个依赖于另一个操作的操作 Adobe AIR 1.0 和更高版本 使用同步执行模式时,无需编写侦听事件的代码来确定操作完成的时间。相反,可以假定如果一个代码行中的操作成功完成, 则继续执行下一代码行。因此,要执行一个依赖于另一个操作成功的操作,只需在紧随它所依赖的操作之后编写相关代码即 可。例如,要为应用程序编码以开始事务,可执行 INSERT 语句,检索已插入行的主键,将该主键插入到不同表的其他行中, 最后提交事务,可以将代码全部编写为一系列语句。以下示例对这些操作进行了演示:200ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 // Include AIRAliases.js to use air.* shortcuts var conn = new air.SQLConnection(); // The database file is in the application storage directory var folder = File.applicationStorageDirectory; var dbFile = folder.resolvePath("DBSample.db"); // open the database conn.open(dbFile, air.OpenMode.UPDATE); // start a transaction conn.begin(); // add the customer record to the database var insertCustomer = new air.SQLStatement(); insertCustomer.sqlConnection = conn; insertCustomer.text = "INSERT INTO customers (firstName, lastName) " + "VALUES ('Bob', 'Jones')"; insertCustomer.execute(); var customerId = insertCustomer.getResult().lastInsertRowID; // add a related phone number record for the customer var insertPhoneNumber = new air.SQLStatement(); insertPhoneNumber.sqlConnection = conn; insertPhoneNumber.text = "INSERT INTO customerPhoneNumbers (customerId, number) " + "VALUES (:customerId, '800-555-1234')"; insertPhoneNumber.parameters[":customerId"] = customerId; insertPhoneNumber.execute(); // commit the transaction conn.commit(); 在同步执行时处理错误 Adobe AIR 1.0 和更高版本 在同步执行模式下,不侦听错误事件来确定操作是否已失败。相反,将可能触发错误的任何代码括在一组 try..catch..finally 代码 块中。将引发错误的代码包装在 try 块中。在单独的 catch 块中,编写响应每种类型的错误时要执行的操作。在 finally 块中放置 不管成功还是失败(例如,关闭不再需要的数据库连接)都希望始终执行的任何代码。以下示例演示如何使用 try..catch..finally 块进行错误处理。它建立在前面示例的基础之上,添加了错误处理代码:201ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 // Include AIRAliases.js to use air.* shortcuts var conn = new air.SQLConnection(); // The database file is in the application storage directory var folder = File.applicationStorageDirectory; var dbFile = folder.resolvePath("DBSample.db"); // open the database conn.open(dbFile, air.SQLMode.UPDATE); // start a transaction conn.begin(); try { // add the customer record to the database var insertCustomer = new air.SQLStatement(); insertCustomer.sqlConnection = conn; insertCustomer.text = "INSERT INTO customers (firstName, lastName)" + "VALUES ('Bob', 'Jones')"; insertCustomer.execute(); var customerId = insertCustomer.getResult().lastInsertRowID; // add a related phone number record for the customer var insertPhoneNumber = new air.SQLStatement(); insertPhoneNumber.sqlConnection = conn; insertPhoneNumber.text = "INSERT INTO customerPhoneNumbers (customerId, number)" + "VALUES (:customerId, '800-555-1234')"; insertPhoneNumber.parameters[":customerId"] = customerId; insertPhoneNumber.execute(); // if we've gotten to this point without errors, commit the transaction conn.commit(); } catch (error) { // rollback the transaction conn.rollback(); } 了解异步执行模式 Adobe AIR 1.0 和更高版本 使用异步执行模式的一个常见问题就是,假设您当前正在对同一个数据库连接执行某个 SQLStatement 实例,则无法开始执行 另一个 SQLStatement 实例。事实上,此假定是不正确的。在 SQLStatement 实例执行的同时,无法更改语句的 text 属性。 但是,如果对要执行的每个不同 SQL 语句使用单独的 SQLStatement 实例,则可以在其他 SQLStatement 实例仍执行的同时 调用 SQLStatement 的 execute() 方法,且不会导致错误。 在内部,当您使用异步执行模式执行数据库操作时,每个数据库连接(每个 SQLConnection 实例)都具有自己的队列或指示 它执行的操作列表。运行时依次执行每个操作(按照将它们添加到队列的顺序)。创建 SQLStatement 实例并调用其 execute() 方法时,会将该语句执行操作添加到连接队列。如果在该 SQLConnection 实例上当前未执行操作,则语句将在后台开始执202ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 行。假定在同一代码块中,创建另一个 SQLStatement 实例,并且也调用该方法的 execute() 方法。该第二个语句执行操作将 添加到队列中的第一个语句之后。在第一个语句完成执行后,运行时立即移动到队列中的下一个操作。队列中后续操作的处理 发生在后台,即使在主应用程序代码中调度第一个操作的 result 事件也如此。以下代码对此技术进行了演示: // Using asynchronous execution mode var stmt1 = new air.SQLStatement(); stmt1.sqlConnection = conn; // ... Set statement text and parameters, and register event listeners ... stmt1.execute(); // At this point stmt1's execute() operation is added to conn's execution queue. var stmt2 = new air.SQLStatement(); stmt2.sqlConnection = conn; // ... Set statement text and parameters, and register event listeners ... stmt2.execute(); // At this point stmt2's execute() operation is added to conn's execution queue. // When stmt1 finishes executing, stmt2 will immediately begin executing // in the background. 数据库自动执行排队的后续语句会产生另一个重要效果。如果一个语句依赖于另一个操作的结果,则在第一个操作完成之前, 无法将该语句添加到队列中(换句话说,无法调用其 execute() 方法)。这是因为调用第二个语句的 execute() 方法后,无法更 改该语句的 text 或 parameters 属性。在此情况下,在开始下一个操作之前,必须等待指示第一个操作已完成的事件。例如,如 果要在事务的上下文中执行语句,则该语句的执行将取决于打开事务的操作。 调用 SQLConnection.begin() 方法打开事务后,需 要等待 SQLConnection 实例调度其 begin 事件。只有这时才能调用 SQLStatement 实例的 execute() 方法。在此示例中,组 织应用程序以确保正确执行操作的最简单方法是,创建一个方法,并将其注册为 begin 事件的侦听器。将调用 SQLStatement.execute() 方法的代码放置在该侦听器方法中。 对 SQL 数据库使用加密 Adobe AIR 1.5 和更高版本 所有 Adobe AIR 应用程序都共享同一个本地数据库引擎。因此,任何 AIR 应用程序都可以连接到、读取和写入未加密的数据 库文件。从 Adobe AIR 1.5 起,AIR 中加入了创建和连接到加密数据库文件的功能。使用加密数据库时,应用程序必须提供正 确的加密密钥才能连接到数据库。如果提供的加密密钥有误(或不提供密钥),则应用程序无法连接到数据库。因此,应用程 序无法从数据库中读取数据,也无法写入数据库或更改数据库中的数据。 若要使用加密数据库,创建数据库时必须将其创建为加密数据库。有了加密数据库,即可打开到数据库的连接。还可以更改加 密数据库的加密密钥。除了创建和连接到加密数据库之外,处理加密数据库的方法与处理未加密数据库的方法相同。尤其是无 论数据库是否加密,执行 SQL 语句的方式都相同。 加密数据库的用途 Adobe AIR 1.5 和更高版本 希望限制对数据库中所存储信息的访问时,加密很有帮助。 Adobe AIR 的数据库加密功能可以用于多种用途。下面是需要使 用加密数据库的一些示例情况: • 从服务器下载的专用应用程序数据的只读缓存203ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 • 与服务器进行同步(向服务器发送数据以及从服务器加载数据)的专用数据的本地应用程序存储区 • 用作由应用程序创建和编辑的文档的文件格式的加密文件。可以专用于一个用户、或可以在应用程序的所有用户中共享的文 件。 • 本地数据存储区的任何其他用途(如第 176 页的 “ 本地 SQL 数据库的用途 ” 中所述),在这些用途中不能向有权访问计算机 或数据库文件的人员公开数据。 了解需要使用加密数据库的原因有助于您确定构建应用程序的方式。特别是,它可影响您的应用程序为数据库创建、获取及存 储加密密钥的方式。有关这些注意事项的详细信息,请参阅第 206 页的 “ 对数据库使用加密的注意事项 ”。 除了加密数据库,加密本地存储区是用于保存私有敏感数据的另一种机制。使用加密本地存储区,可使用字符串密钥存储单一 ByteArray 值。只有存储该值的 AIR 应用程序可访问它,而且只能在存储该值的计算机上进行访问。在采用加密本地存储区的 情况下,不需要创建自己的加密密钥。 出于这些原因,加密本地存储区最适合于方便地存储易于在 ByteArray 中编码的一个值 或一组值。加密数据库最适合于需要结构化数据存储和查询的大型数据集。有关使用加密本地存储的详细信息,请参阅第 218 页的 “ 加密的本地存储区 ”。 创建加密数据库 Adobe AIR 1.5 和更高版本 若要使用加密数据库,则创建数据库文件时必须将其加密。 一旦在不加密的情况下创建数据库,以后就无法再对其进行加密。 同样,以后也无法对加密数据库进行解密。如有必要,可以更改加密数据库的加密密钥。有关详细信息,请参阅第 205 页的 “ 更改数据库的加密密钥 ”。如果现有的数据库未加密,而您又希望使用数据库加密,则可以新建一个加密数据库,然后将现有 的表结构和数据复制到新数据库中。 创建加密数据库与创建未加密数据库几乎完全相同,如第 180 页的 “ 创建数据库 ” 中所述。首先创建一个表示数据库连接的 SQLConnection 实例。通过调用 SQLConnection 对象的 open() 方法或 openAsync() 方法创建数据库,并为数据库位置指定 一个尚未存在的文件。创建加密数据库时的唯一区别在于要为 encryptionKey 参数( open() 方法的第五个参数和 openAsync() 方法的第六个参数)提供值。 有效的 encryptionKey 参数值为正好包含 16 个字节的 ByteArray 对象。 下列示例演示创建加密数据库。为简洁起见,在这些示例中,加密密钥在应用程序代码中采用硬编码形式。但是,由于此方法 不安全,强烈建议不要使用此方法。 var conn = new air.SQLConnection(); var encryptionKey = new air.ByteArray(); encryptionKey.writeUTFBytes("Some16ByteString"); // This technique is not secure! // Create an encrypted database in asynchronous mode conn.openAsync(dbFile, air.SQLMode.CREATE, null, false, 1024, encryptionKey); // Create an encrypted database in synchronous mode conn.open(dbFile, air.SQLMode.CREATE, false, 1024, encryptionKey); 有关介绍生成加密密钥的建议方式的示例,请参阅第 206 页的 “ 示例:生成和使用加密密钥 ”。 连接到加密数据库 Adobe AIR 1.5 和更高版本 与创建加密数据库类似的是,打开到加密数据库的连接所采用的步骤类似于连接到未加密数据库。该步骤在第 182 页的 “ 连接 到数据库 ” 中有更详细的说明。使用 open() 方法在同步执行模式下打开连接,或者使用 openAsync() 方法在异步执行模式下打 开连接。唯一的区别在于,若要打开加密数据库,要为 encryptionKey 参数( open() 方法的第五个参数和 openAsync() 方法的 第六个参数)指定正确的值。204ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 如果所提供的加密密钥有误,则会出错。对于 open() 方法,将引发 SQLError 异常。对于 openAsync() 方法, SQLConnection 对象将调度 SQLErrorEvent,其 error 属性包含 SQLError 对象。在任一情况下,由异常生成的 SQLError 对象的 errorID 属性值都为 3138。该错误 ID 对应于错误消息 “ 所打开的文件不是数据库文件 ”。 以下示例介绍以异步执行模式打开加密数据库。为了简单起见,此示例中的加密密钥在应用程序代码中采用硬编码形式。但 是,由于此方法不安全,强烈建议不要使用此方法。 // Include AIRAliases.js to use air.* shortcuts var conn = new air.SQLConnection(); conn.addEventListener(air.SQLEvent.OPEN, openHandler); conn.addEventListener(air.SQLErrorEvent.ERROR, errorHandler); var dbFile = air.File.applicationStorageDirectory.resolvePath("DBSample.db"); var encryptionKey = new air.ByteArray(); encryptionKey.writeUTFBytes("Some16ByteString"); // This technique is not secure! conn.openAsync(dbFile, air.SQLMode.UPDATE, null, false, 1024, encryptionKey); function openHandler(event) { air.trace("the database opened successfully"); } function errorHandler(event) { if (event.error.errorID == 3138) { air.trace("Incorrect encryption key"); } else { air.trace("Error message:", event.error.message); air.trace("Details:", event.error.details); } } 以下示例介绍以同步执行模式打开加密数据库。为了简单起见,此示例中的加密密钥在应用程序代码中采用硬编码形式。但 是,由于此方法不安全,强烈建议不要使用此方法。205ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 // Include AIRAliases.js to use air.* shortcuts var conn = new air.SQLConnection(); var dbFile = air.File.applicationStorageDirectory.resolvePath("DBSample.db"); var encryptionKey = new air.ByteArray(); encryptionKey.writeUTFBytes("Some16ByteString"); // This technique is not secure! try { conn.open(dbFile, air.SQLMode.UPDATE, false, 1024, encryptionKey); air.trace("the database was created successfully"); } catch (error) { if (error.errorID == 3138) { air.trace("Incorrect encryption key"); } else { air.trace("Error message:", error.message); air.trace("Details:", error.details); } } 有关介绍生成加密密钥的建议方式的示例,请参阅第 206 页的 “ 示例:生成和使用加密密钥 ”。 更改数据库的加密密钥 Adobe AIR 1.5 和更高版本 数据库加密后,可以在以后更改数据库的加密密钥。要更改数据库的加密密钥,请首先创建一个 SQLConnection 实例并调用 其 open() 或 openAsync() 方法,从而打开到数据库的连接。连接数据库后,调用 reencrypt() 方法,并传递新的加密密钥作为参 数。 与大多数数据库操作类似的是, reencrypt() 方法的行为根据数据库连接使用同步还是异步执行模式而有所不同。如果使用 open() 方法连接到数据库,则 reencrypt() 操作会同步运行。操作完成后,继续执行下一行代码: var newKey = new air.ByteArray(); // ... generate the new key and store it in newKey conn.reencrypt(newKey); 另一方面,如果使用 openAsync() 方法打开数据库连接,则 reencrypt() 操作为异步方式。调用 reencrypt() 将开始重新加密的过 程。操作完成后, SQLConnection 对象调度一个 reencrypt 事件。使用事件侦听器确定重新加密完成的时间: var newKey = new air.ByteArray(); // ... generate the new key and store it in newKey conn.addEventListener(air.SQLEvent.REENCRYPT, reencryptHandler); conn.reencrypt(newKey); function reencryptHandler(event) { // save the fact that the key changed } reencrypt() 操作在其自身的事务中运行。如果操作中断或失败(例如,如果在操作完成之前关闭应用程序),则事务将回滚。 在这种情况下,原始的加密密钥仍为数据库的加密密钥。206ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 reencrypt() 方法不能用于解除对数据库的加密。向 reencrypt() 方法传递 null 值或非 16 字节 ByteArray 的加密密钥会导致错 误。 对数据库使用加密的注意事项 Adobe AIR 1.5 和更高版本 第 202 页的 “ 加密数据库的用途 ” 部分介绍了需要使用加密数据库的几种情况。显然,不同应用程序的使用情况(包括以上这 些情况和其他情况)具有不同的隐私要求。如何安排加密在应用程序中的用途,对于控制数据库的数据私密程度起着重要作 用。例如,如果使用加密数据库来保持个人数据的私密性(甚至针对同一计算机的其他用户),则每个用户的数据库都需要有 自己的加密密钥。为尽可能的安全起见,应用程序可以根据用户输入的密码生成密钥。加密密钥以密码为基础可以确保,即使 其他人可以在计算机上模拟用户的帐户,也无法访问数据。换个角度来看隐私问题,假设您希望数据库文件可以由您的应用程 序的任何用户读取,但不能由其他应用程序读取。在这种情况下,每个已安装的应用程序副本都需要具有访问共享加密密钥的 权限。 可以根据希望应用程序数据所达到的隐私等级来设计应用程序,尤其是用于生成加密密钥的方法。以下列表为各种级别的数据 隐私提供了设计建议: • 若要使任何计算机上有权访问应用程序的任何用户都可以访问数据库,请使用一个密钥,该密钥对于应用程序的所有实例都 可用。例如,应用程序首次运行时,可以使用一个安全协议(如 SSL)从服务器下载共享的加密密钥。然后可以将密钥保 存在加密本地存储区中,以供将来使用。作为替代方法,可以按计算机上的每个用户对数据进行加密,然后将数据与远程数 据存储区(如服务器)同步,以使数据可移植。 • 若要使任何计算机上的单个用户都可以访问数据库,请根据用户的保密事项(如密码)生成加密密钥。尤其是不要使用任 何与特定计算机关联的值(如存储在加密本地存储区中的值)生成密钥。作为替代方法,可以按计算机上的每个用户对数 据进行加密,然后将数据与远程数据存储区(如服务器)同步,以使数据可移植。 • 若要使单个计算机上的单个人可以访问数据库,请根据密码和所生成的 salt 来生成密钥。有关此方法的示例,请参阅 第 206 页的 “ 示例:生成和使用加密密钥 ”。 设计应用程序使用加密数据库时,还有一些安全注意事项务必要牢记,具体如下所示: • 系统的安全性取决于其最薄弱环节的安全性。如果使用用户输入的密码生成加密密钥,则请考虑对密码施加最小长度和复杂 性的限制。只使用基本字符的短密码很快就会被猜中。 • AIR 应用程序的源代码以纯文本形式(对于 HTML 内容)或易于反编译的二进制格式(对于 SWF 内容)存储在用户的 计算机上。由于源代码可访问,因此有两点要牢记: • 切勿在源代码中对加密密钥进行硬编码 • 始终假设用于生成加密密钥的方法(如随机字符生成器或特定的哈希算法)很容易就会被攻击者破解 • AIR 数据库加密使用高级加密标准 (AES) 及 Counter with CBC-MAC (CCM) 模式。这种加密密码需要将用户输入的密 钥与 salt 值组合在一起才安全。有关此方法的示例,请参阅第 206 页的 “ 示例:生成和使用加密密钥 ”。 • 如要加密数据库,则数据库引擎所使用的所有磁盘文件与该数据库一起都要进行加密。 但是,在事务过程中,数据库引擎会 在内存中的缓存中临时保留一些数据,以提高读写性能。驻留在内存中的任何数据都不加密。如果攻击者可以访问 AIR 应 用程序所使用的内存(例如通过使用调试器),则数据库中当前公开且未加密的数据即可供其使用。 示例:生成和使用加密密钥 Adobe AIR 1.5 和更高版本 此示例应用程序介绍生成加密密钥的一种方法。此应用程序旨在为用户的数据提供最高级别的隐私和安全。保障私有数据安全 的一个重要原则是:在应用程序每次连接到数据库时都要求用户输入密码。 因此,正如此例所示,需要此种保密级别的应用程 序在任何时候都不应直接存储数据库加密密钥。207ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 应用程序由两部分组成:生成加密密钥的 ActionScript 类(EncryptionKeyGenerator 类),以及介绍如何使用该类的基础 用户界面。 有关完整的源代码,请参阅第 208 页的 “ 用于生成和使用加密密钥的完整示例代码 ”。 使用 EncryptionKeyGenerator 类获得安全加密密钥 Adobe AIR 1.5 和更高版本 不需要了解 EncryptionKeyGenerator 类的工作方式的详情即可在您的应用程序中使用它。如果您有兴趣详细了解此类是如 何为数据库生成加密密钥的,请参阅第 214 页的 “ 了解 EncryptionKeyGenerator 类 ”。 请按照以下步骤在应用程序中使用 EncryptionKeyGenerator 类: 1 下载 EncryptionKeyGenerator 库。EncryptionKeyGenerator 类包括在开源 ActionScript 3.0 核心库 (as3corelib) 项 目中。可以下载包括源代码和文档的 as3corelib 包。还可以从项目页面下载 SWC 或源代码文件。 2 从 SWC 中提取 SWF 文件。若要提取 SWF 文件,请将 SWC 文件的扩展名改为 “.zip”,然后打开该 ZIP 文件。从 ZIP 文 件中提取 SWF 文件,将其放在应用程序源代码可以找到的地方。例如,可以将其放在包含应用程序主 HTML 文件的文件 夹中。如果愿意,可以重命名 SWF 文件。在本例中,将 SWF 文件命名为 “EncryptionKeyGenerator.swf”。 3 在应用程序源代码中,添加与 SWF 文件相链接的

Enter a password to create an encrypted database. The next time you open the application, you will need to re-enter the password to open the database again.

了解 EncryptionKeyGenerator 类 Adobe AIR 1.5 和更高版本 不必了解 EncryptionKeyGenerator 类的内部工作机制,也可以使用它为应用程序数据库创建安全加密密钥。第 207 页的 “ 使用 EncryptionKeyGenerator 类获得安全加密密钥 ” 中介绍了使用该类的过程。但是,您会发现非常值得了解该类使用的 技术。例如,对于需要不同数据保密级别的场合,可能要改编该类或加入它的某些技术。 EncryptionKeyGenerator 类包括在开源 ActionScript 3.0 核心库 (as3corelib) 项目中。可以下载 包括源代码和文档的 as3corelib 包。还可以在项目站点查看源代码,或进行下载以按照介绍进行操作。215ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 代码创建 EncryptionKeyGenerator 实例并调用其 getEncryptionKey() 方法时,将采取若干步骤来确保只有正当的用户才能访 问数据。此过程与创建数据库之前,根据用户输入的密码生成加密密钥的过程相同,亦与重新创建加密密钥,以打开数据库的 过程相同。 获取并验证强密码 Adobe AIR 1.5 和更高版本 代码调用 getEncryptionKey() 方法时,将传入密码作为参数。密码用作加密密钥的基础。此设计使用只有用户知道的一条信 息,从而确保只有知道密码的用户才能访问数据库中的数据。即使攻击者可以访问用户在计算机上的帐户,在不知道密码的情 况下也无法进入数据库。为尽可能安全起见,应用程序从不存储密码。 应用程序的代码创建 EncryptionKeyGenerator 实例并调用其 getEncryptionKey() 方法,将用户输入的密码作为参数(此示 例中为 password 变量)传递: var keyGenerator = new ekg.EncryptionKeyGenerator(); var encryptionKey = keyGenerator.getEncryptionKey(password); 调用 getEncryptionKey() 方法后,EncryptionKeyGenerator 类所采取的第一步是检查用户输入的密码,以确保其符合密码强 度的要求。EncryptionKeyGenerator 类要求密码长度为 8 - 32 个字符。密码必须包含大小写字母的混合形式,而且至少包括 一个数字或符号字符。 在内部,getEncryptionKey() 方法调用 EncryptionKeyGenerator 类的 validateStrongPassword() 方法,并且密码无效时会引发 异常。 validateStrongPassword() 方法是一个公共方法,这样应用程序代码无需调用 getEncryptionKey() 方法即可进行密码检 查,从而避免导致错误。 将密码扩展到 256 位 Adobe AIR 1.5 和更高版本 在过程的后期,密码的长度必须为 256 位。代码并不要求每个用户输入长度刚好为 256 位(32 个字符)的密码,而是通过重 复密码字符来创建更长的密码。 以下是 concatenatePassword() 方法的代码: 如果密码长度小于 256 位,则代码将密码与密码自身连接在一起,使其达到 256 位。 如果不能刚好达到这一长度,则缩短最后 一次重复的内容,以便刚好得到 256 位。 生成或检索 256 位 salt 值 Adobe AIR 1.5 和更高版本 下一步是获得 256 位 salt 值,后面的一个步骤中会将此值与密码组合在一起。 salt 是向用户输入的值添加或与之组合在一起而 形成密码的一个随机值。结合使用 salt 和密码确保了即使用户选择真实单词或常用词汇作为密码,系统所使用的 “ 密码加 salt” 组合也是一个随机值。这有助于防御字典攻击,攻击者在字典攻击中使用单词列表尝试猜出密码。 此外,通过生成 salt 值并将 其存储在加密本地存储区中,该值与数据库文件所在计算机上的用户帐户相关联。 如果应用程序是第一次调用 getEncryptionKey() 方法,则代码将创建一个随机的 256 位 salt 值。否则,代码从加密本地存储区 加载 salt 值。 使用 XOR 运算符组合 256 位密码和 salt Adobe AIR 1.5 和更高版本 代码现在拥有一个 256 位密码和一个 256 位 salt 值。 然后,代码使用按位 XOR 运算将 salt 和连接而成的密码组合为一个值。 实际上,这种方法创建的 256 位密码由整个可用字符范围内的字符组成。 即使实际输入的密码主要由字母数字字符组成也是如 此。 如此提高随机性的优点在于:无须用户输入长而复杂的密码,即可使可能密码的集合变得非常大。216ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 对密钥进行哈希处理 Adobe AIR 1.5 和更高版本 将连接而成的密码与 salt 组合在一起后,下一步就是进一步加强对此值的保护,具体而言就是使用 SHA-256 哈希算法对此值 进行哈希处理。 对值进行哈希处理使攻击者更难以对其进行反向工程。 从哈希值提取加密密钥 Adobe AIR 1.5 和更高版本 加密密钥必须为刚好 16 个字节( 128 位)长的 ByteArray。 SHA-256 哈希算法的结果的长度始终为 256 位。因此,最后一 步是从哈希处理的结果中选择 128 位作为实际的加密密钥。 并不一定要使用前 128 位作为加密密钥。可以选择从某任意点开始的一系列位,可以每隔一位选择一位,或使用某些其他方式 来选择位。 重要的是代码选择 128 个不同的位,并且每次都使用相同的 128 位。 使用 SQL 数据库的策略 Adobe AIR 1.0 和更高版本 应用程序可以通过各种方式来访问和使用本地 SQL 数据库。应用程序设计可能随应用程序代码的组织方式、操作执行方式的 序列和计时等的不同而不同。所选技术可能影响开发应用程序的难易程度。它们可能影响在将来的更新中修改应用程序的难易 程度。它们还可能影响从用户的角度看应用程序性能的高低。 分发预填充的数据库 Adobe AIR 1.0 和更高版本 在应用程序中使用 AIR 本地 SQL 数据库时,应用程序期望一个特定结构的表、列等的数据库。某些应用程序还期望在数据库 文件中预填充特定数据。确保数据库具有正确结构的一种方法是,在应用程序代码中创建数据库。应用程序在加载时将检查在 特定位置中是否存在其数据库文件。如果该文件不存在,则应用程序将执行一组命令来创建数据库文件,创建数据库结构并用 初始数据填充表。 创建数据库及其表的代码常常很复杂。在应用程序的安装生存期内,它通常仅使用一次,但是仍增加了应用程序的大小和复杂 性。作为以编程方式创建数据库、结构和数据的一种替代方法,可以随应用程序分发预填充的数据库。要分发预定义的数据 库,请将数据库文件包括在应用程序的 AIR 包中。 与 AIR 包中包括的所有文件一样,捆绑的数据库文件安装在应用程序目录(由 File.applicationDirectory 属性表示的目录)中。 但是,该目录中的文件是只读的。将 AIR 包中的文件用作 “ 模板 ” 数据库。用户第一次运行该应用程序时,会将原始数据库文 件复制到用户的第 130 页的 “ 指向应用程序存储目录 ” (或其他位置),并在应用程序中使用该数据库。 使用本地 SQL 数据库的最佳做法 Adobe AIR 1.0 和更高版本 下面列出了一组建议的方法,在使用本地 SQL 数据库时,可以通过这些方法提高应用程序的性能、安全性和易维护性。 217ADOBE AIR HTML 开发人员指南 在 AIR 中使用本地 SQL 数据库 上次更新 2011/10/13 预创建数据库连接 Adobe AIR 1.0 和更高版本 尽管应用程序在首次加载时不执行任何语句,但是在运行语句时,提前(如在应用程序初始启动之后)实例化 SQLConnection 对象并调用其 open() 或 openAsync() 方法可以避免延迟。请参阅第 182 页的 “ 连接到数据库 ”。 重用数据库连接 Adobe AIR 1.0 和更高版本 如果在应用程序的整个执行时间内访问某个数据库,请保存对 SQLConnection 实例的引用,并在整个应用程序中重用它,而 不是先关闭再重新打开连接。请参阅第 182 页的 “ 连接到数据库 ”。 推荐使用异步执行模式 Adobe AIR 1.0 和更高版本 编写数据访问代码时,可能很想同步执行操作而不是异步执行,因为使用同步操作通常需要更短的代码,并且代码的复杂性更 低。但是,如第 198 页的 “ 使用同步和异步数据库操作 ” 中所述,同步操作可产生对用户而言很明显的性能影响,并损害用户 对应用程序的体验。单个操作所用的时间随操作、尤其是它所涉及的数据量的不同而不同。例如,仅向数据库中添加一行的 SQL INSERT 语句所用的时间要比检索成千上万行数据的 SELECT 语句所用的时间少。但是,使用同步执行来执行多个操作 时,这些操作通常串在一起。即使每个操作所用的时间非常短,但是在所有同步操作完成之前会冻结应用程序。因此,串在一 起的多个操作的累积时间可能足以停止应用程序。 将异步操作用作一种标准方法,尤其是对于涉及大量行的操作。有一种技术可拆分大型 SELECT 语句结果集的处理,如第 191 页的 “ 检索部分 SELECT 结果 ” 所述。但是,此技术只能在异步执行模式下使用。只有在使用异步编程无法实现某些功能时, 已考虑到应用程序的用户所要面临的性能折衷时,以及已测试应用程序以便了解对应用程序性能的影响程度时,才应使用同步 操作。 使用异步执行可能涉及更复杂的编码。但是,请记住只需编写一次代码,但是应用程序用户必须重复使用它(或快或 慢)。 在许多情况下,通过对要执行的每个 SQL 语句使用单独的 SQLStatement 实例,可以同时将多个 SQL 操作排队,这将使异步 代码在代码编写方式上与同步代码类似。有关详细信息,请参阅第 201 页的 “ 了解异步执行模式 ”。 使用单独的 SQL 语句,且不更改 SQLStatement 的 text 属性 Adobe AIR 1.0 和更高版本 对于在应用程序中多次执行的任何 SQL 语句,为每个 SQL 语句创建单独的 SQLStatement 实例。 SQL 命令在每次执行时都 使用该 SQLStatement 实例。例如,假定您要生成一个应用程序,它包括四个多次执行的不同 SQL 操作。在此情况下,创建 四个单独的 SQLStatement 实例,并调用每个语句的 execute() 方法来运行它。避免对所有 SQL 语句使用单个 SQLStatement 实例,每次执行语句之前都重新定义其 text 属性。 使用语句参数 Adobe AIR 1.0 和更高版本 使用 SQLStatement 参数 — 从不将用户输入连接到语句文本中。使用参数会使应用程序更安全,因为这样可消除 SQL 注入攻 击的可能性。这样就有可能在查询中使用对象(而不是仅使用 SQL 字面值)。这样还会提高语句的运行效率,因为可以重用语 句,每次执行它们时无需将其重新编译。有关详细信息,请参阅第 185 页的 “ 在语句中使用参数 ”。218 上次更新 2011/10/13 第 15 章 : 加密的本地存储区 Adobe® AIR® 运行时为安装在用户计算机的每个 AIR 应用程序都提供了一个永久加密的本地存储 (ELS)。此功能可保存和检 索存储在用户的本地硬盘驱动器中的加密数据(其他用户无法轻松解密)。为每个 AIR 应用程序使用一个单独的加密本地存储 区,每个 AIR 应用程序为每个用户使用一个单独的加密本地存储区。 注: 除了加密本地存储区之外, AIR 还可以对 SQL 数据库中存储的内容进行加密。有关详细信息,请参阅第 202 页的 “ 对 SQL 数据库使用加密 ”。 您可能想使用加密本地存储区来缓存必须保护的信息,如用于获取 Web 服务的登录凭据。 ELS 适合存储不得向其他用户公开 的信息。但是,使用同一用户帐户运行的其他进程仍可访问它存储的数据。因此,它不适用于合保护秘密应用程序数据,例如 DRM 或加密密钥。 在桌面平台上,通过在 Windows 中使用 DPAPI,在 Mac OS 和 iOS 中使用 KeyChain,以及在 Linux 中使用 KeyRing 或 KWallet, AIR 将加密本地存储区与每个应用程序和用户相关联。加密的本地存储区使用 AES-CBC 128 位加密。 在 Android 上, EncryptedLocalStorage 类存储的数据未加密。而该数据由操作系统提供的用户级别的安全性进行保护。 Android 操作系统为每个应用程序分配一个单独的用户 ID。应用程序只能访问自己的文件和在公共位置创建的文件(如移动 存储卡)。注意,在 Android 的 “ 根 ” 设备上,使用根权限运行的应用程序可以访问其他应用程序的文件。因此,在根设备 上,加密的本地存储不提供与非根设备上级别一样高的数据保护。 加密的本地存储区中的信息仅可用于应用程序安全沙箱中的 AIR 应用程序内容。 如果更新 AIR 应用程序,则更新后的版本仍能够访问加密本地存储区中的任何现有数据,以下情况除外: • 使用 stronglyBound 参数添加的项目设置为 true • 现有和更新版本发布的时间都早于 AIR 1.5.3,并且更新使用迁移签名进行签名。 加密本地存储区的限制 加密本地存储区中的数据由用户操作系统帐户凭据进行保护。除非可以用该用户的身份进行登录,否则其他实体无法访问存储 区中的数据。但是,已通过身份验证的用户运行的其他应用程序仍可访问这些数据。 由于用户必须经过身份验证才能使这些攻击生效,所以用户的隐私数据仍然受到保护(除非用户的帐户本身已被泄漏)。但 是,应用程序希望对用户保密的数据(如用于授权或数字版权管理的密钥)是不安全的。因此, ELS 不是存储此类信息的适当 位置。它只适合存储用户的隐私数据,如密码。 ELS 中的数据可能由于各种原因而丢失。例如,用户可能会卸载应用程序并删除加密的文件。或者,发行商 ID 可能由于更新 而发生更改。因此,应将 ELS 用作私有缓存,而不是永久性数据存储。 stronglyBound 参数已弃用,不应将其设置为 true。此参数设置为 true 后,不会对数据进行任何额外保护。同时,即使发行商 ID 保持不变,应用程序每次更新后都会丢失对数据的访问。 如果存储的数据超过 10MB,则加密的本地存储区的运行速度可能变慢。 当卸载 AIR 应用程序时,卸载程序不会删除存储在加密的本地存储区中的数据。 使用 ELS 的最佳做法包括: • 使用 ELS 存储例如密码等敏感用户数据(将 stronglyBound 设置为 false) • 不使用 ELS 存储应用程序机密(如 DRM 密钥或授权令牌)。 • 为应用程序提供在 ELS 数据丢失的情况下重新创建 ELS 中存储的数据的方法。例如,在必要时,通过提示用户重新输入帐 户凭据来实现此操作。 • 不要使用 stronglyBound 参数。 • 如果 stronglyBound 确实设置为 true,则在更新期间不要迁移存储的项目。而应在更新后重新创建数据。 219ADOBE AIR HTML 开发人员指南 加密的本地存储区 上次更新 2011/10/13 • 仅存储较少数量的数据。对于大量数据,请使用加密的 AIR SQL 数据库。 更多帮助主题 flash.data.EncryptedLocalStore 将数据添加到加密本地存储区 使用 EncryptedLocalStore 类的 setItem() 静态方法将数据存储在本地存储区中。数据存储在哈希表中(使用字符串作为键, 以字节数组的形式存储数据)。 例如,下面的代码将一个字符串存储在加密的本地存储区中: var str = "Bob"; var bytes = new air.ByteArray(); bytes.writeUTFBytes(str); air.EncryptedLocalStore.setItem("firstName", bytes); setItem() 方法的第三个参数(即 stronglyBound 参数)是可选参数。如果此参数设置为 true,则加密本地存储区会将存储的项 目绑定到存储 AIR 应用程序的数字签名和位: var str = "Bob"; var bytes = new air.ByteArray(); bytes.writeUTFBytes(str); air.EncryptedLocalStore.setItem("firstName", bytes, false); 对于将 stronglyBound 设置为 true 后存储的项目,在以后调用 getItem() 时,仅当调用方 AIR 应用程序与存储方应用程序相同 时才会成功(前提是应用程序目录中的文件未发生数据更改)。如果执行调用的 AIR 应用程序与执行存储的应用程序不同,则 当您对强绑定项目调用 getItem() 时,该应用程序将引发 Error 异常。如果您更新应用程序,则该应用程序将无法读取先前写入 到加密的本地存储区中的强绑定数据。忽略在移动设备上将 stronglyBound 设置为 true ;始终将该参数视为 false。 如果将 stronglyBound 参数设置为 false(默认值),则只有发行商 ID 需要保持不变,供应用程序读取数据。应用程序的位可以 更改(需由同一发行商对这些位进行签名),但不需要与存储数据的应用程序中的位完全相同。如果更新后的应用程序与原始 应用程序的发行商 ID 相同,则可继续访问这些数据。 注: 实际上,将 stronglyBound 设置为 true 不会增加任何额外数据保护。“ 恶意 ” 用户仍可更改应用程序,从而访问存储在 ELS 中的项目。而且,无论将 stronglyBound 设置为 true 还是 false,保护数据免受外部非用户威胁的强度都是一样的。出于以上原 因,建议不要将 stronglyBound 设置为 true。 访问加密的本地存储区中的数据 Adobe AIR 1.0 和更高版本 您可以使用 EncryptedLocalStore.getItem() 方法从加密的本地存储区中检索值,如下例所示: var storedValue = air.EncryptedLocalStore.getItem("firstName"); air.trace(storedValue.readUTFBytes(storedValue.length)); // "foo"220ADOBE AIR HTML 开发人员指南 加密的本地存储区 上次更新 2011/10/13 从加密的本地存储区中删除数据 Adobe AIR 1.0 和更高版本 您可以使用 EncryptedLocalStore.removeItem() 方法删除加密的本地存储区中的值,如下例所示: air.EncryptedLocalStore.removeItem("firstName"); 您可以通过调用 EncryptedLocalStore.reset() 方法清除加密的本地存储区中的所有数据,如下例所示: air.EncryptedLocalStore.reset();221 上次更新 2011/10/13 第 16 章 : 使用字节数组 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ByteArray 类允许读取和写入二进制数据流,该数据流本质上是字节数组。该类提供了一种访问最基本的数据的方法。因为计 算机数据由字节(即包含 8 位的组)组成,因此能够以字节为单位读取数据意味着您可以访问那些不存在类和访问方法的数 据。 ByteArray 类允许您在字节级分析任何数据流,从位图到通过网络的数据流。 利用 writeObject() 方法可以将具有序列化 Action Message Format (AMF) 格式的对象写入 ByteArray,而利用 readObject() 方法则可以从 ByteArray 中将序列化对象读取到原始数据类型的变量中。可以将显示对象以外的任何对象序列化,显示对象是 可以放在显示列表中的那些对象。如果自定义类可用于运行时,也可以将序列化对象重新指定给自定义类实例。将一个对象转 换为 AMF 格式之后,就可以通过网络连接有效传输该对象或将该对象保存到文件中。 此处描述的 Adobe® AIR® 应用程序示例将读取一个 .zip 文件,以该文件为例说明处理字节流、提取 .zip 文件包含的文件列表 并将其写入桌面的过程。 更多帮助主题 flash.utils.ByteArray flash.utils.IExternalizable Action Message Format 规范 读取并写入 ByteArray Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 ByteArray 类在 flash.utils 包中;如果代码包括 AIRAliases.js 文件,您也可以使用别名 air.ByteArray 来引用 ByteArray 类。 若要创建 ByteArray,请按以下示例中所示调用 ByteArray 构造函数: var stream = new air.ByteArray(); ByteArray 方法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 任何有意义的数据流均将以某种格式组织起来,以便于您分析并找到所需信息。例如,简单的员工文件中的记录可能包括 ID 号、姓名、地址、电话号码等等。 MP3 音频文件包含用于标识所下载文件的标题、作者、专辑、发行日期和流派的 ID3 标签。 通过格式您可以知道数据在数据流中的预期顺序。这样,您就可以采用智能方式读取字节流。 ByteArray 类包括几种方法,可以使数据流的读写更加容易。其中几种方法包括 readBytes() 和 writeBytes()、 readInt() 和 writeInt()、readFloat() 和 writeFloat()、readObject() 和 writeObject()、readUTFBytes() 和 writeUTFBytes()。利用以上方法可以 将数据从数据流读入特定数据类型的变量,也可以从特定数据类型的变量直接写入二进制数据流。 例如,以下代码读取一个简单的由字符串和浮点数组成的数组并将每个元素写入 ByteArray。此数组结构允许代码调用相应的 ByteArray 方法( writeUTFBytes() 和 writeFloat())来写入数据。 重复的数据模式使循环读取该数组成为可能。222ADOBE AIR HTML 开发人员指南 使用字节数组 上次更新 2011/10/13 // The following example reads a simple Array (groceries), made up of strings // and floating-point numbers, and writes it to a ByteArray. // define the grocery list Array var groceries = ["milk", 4.50, "soup", 1.79, "eggs", 3.19, "bread" , 2.35] // define the ByteArray var bytes = new air.ByteArray(); // for each item in the array for (i = 0; i < groceries.length; i++) { bytes.writeUTFBytes(groceries[i++]); //write the string and position to the next item bytes.writeFloat(groceries[i]);// write the float air.trace("bytes.position is: " + bytes.position); //display the position in ByteArray } air.trace("bytes length is: " + bytes.length);// display the length position 属性 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 position 属性存储指针的当前位置,该指针在读写过程中指向 ByteArray。position 属性的初始值为 0,如以下代码中所示: var bytes = new air.ByteArray(); air.trace("bytes.position is initially: " + bytes.position); // 0 当您读取或写入 ByteArray 时,您使用的方法将更新 position 属性以指向紧随上次所读取或写入字节后的位置。例如,以下 代码将一个字符串写入 ByteArray,随后 position 属性将指向 ByteArray 中该字符串后面紧邻的字节: var bytes = new air.ByteArray(); air.trace("bytes.position is initially: " + bytes.position); // 0 bytes.writeUTFBytes("Hello World!"); air.trace("bytes.position is now: " + bytes.position);// 12 同样,读取操作会使 position 属性值按照读取的字节数而相应增加。 var bytes = new air.ByteArray(); air.trace("bytes.position is initially: " + bytes.position); // 0 bytes.writeUTFBytes("Hello World!"); air.trace("bytes.position is now: " + bytes.position);// 12 bytes.position = 0; air.trace("The first 6 bytes are: " + (bytes.readUTFBytes(6)));//Hello air.trace("And the next 6 bytes are: " + (bytes.readUTFBytes(6)));// World! 请注意,您可以将 position 属性设置为 ByteArray 中的一个特定位置从而基于该偏移量进行读取或写入。 bytesAvailable 和 length 属性 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 length 和 bytesAvailable 属性分别指示 ByteArray 的长度为多少以及从当前位置到结尾处还剩多少字节。以下示例说明了您可 以通过什么方式使用这些属性。该示例将一个文本字符串写入 ByteArray 然后一次从 ByteArray 中读取一个字节,直到遇到 字符 “a” 或到达结尾 (bytesAvailable <= 0)。223ADOBE AIR HTML 开发人员指南 使用字节数组 上次更新 2011/10/13 var bytes = new air.ByteArray(); var text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus etc."; bytes.writeUTFBytes(text); // write the text to the ByteArray air.trace("The length of the ByteArray is: " + bytes.length);// 70 bytes.position = 0; // reset position while (bytes.bytesAvailable > 0 && (bytes.readUTFBytes(1) != 'a')) { //read to letter a or end of bytes } if (bytes.position < bytes.bytesAvailable) { air.trace("Found the letter a; position is: " + bytes.position); // 23 air.trace("and the number of bytes available is: " + bytes.bytesAvailable);// 47 } endian 属性 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 在存储多字节数字(即需要超过 1 个字节的内存来存储的数字),各种计算机可能彼此有所差异。例如,一个整数可能需要占 用 4 个字节,即 32 位内存。某些计算机首先将数字中的最高有效字节存储在最低的内存地址,而其他计算机则首先存储最低有 效字节。计算机的这一属性(即字节顺序属性)被称为 big endian (最高有效字节位于最前)或 little endian (最低有效字 节位于最前)。例如,数字 0x31323334 对于 big endian 和 little endian 字节顺序将分别存储为以下形式,其中 a0 代表 4 个 字节的最低内存地址而 a3 代表最高内存地址: 利用 ByteArray 类的 endian 属性可以为要处理的多字节数字表示此字节顺序。该属性可接受的值为 "bigEndian" 或 "littleEndian",并且 Endian 类定义了常量 BIG_ENDIAN 和 LITTLE_ENDIAN,从而通过这些字符串设置 endian 属性。 compress() 和 uncompress() 方法 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 利用 compress() 方法可以根据指定为参数的压缩算法压缩 ByteArray。利用 uncompress() 方法可以根据压缩算法对压缩的 ByteArray 进行解压缩。调用 compress() 和 uncompress() 之后,字节数组的长度将设置为新的长度并且 position 属性将设置 为结尾。 CompressionAlgorithm 类 (AIR) 定义了可用来指定压缩算法的常量。 ByteArray 类支持 deflate (仅限 AIR)和 zlib 算 法。 这种 deflate 压缩算法用于多种压缩格式,如 zlib、gzip 及一些 zip 实现等。在 http://www.ietf.org/rfc/rfc1950.txt 中对 zlib 压缩数据格式进行了说明;在 http://www.ietf.org/rfc/rfc1951.txt 中对 deflate 压缩算法进行了说明。 以下示例使用 deflate 算法压缩名为 bytes 的 ByteArray: bytes.compress(air.CompressionAlgorithm.DEFLATE); Big Endian Big Endian Big Endian Big Endian a0 a1 a2 a3 31 32 33 34 Little Endian Little Endian Little Endian Little Endian a0 a1 a2 a3 34 33 32 31224ADOBE AIR HTML 开发人员指南 使用字节数组 上次更新 2011/10/13 以下示例使用 deflate 算法对压缩的 ByteArray 进行解压缩: bytes.uncompress(CompressionAlgorithm.DEFLATE); 读取和写入对象 Flash Player 9 和更高版本, Adobe AIR 1.0 和更高版本 readObject() 和 writeObject() 方法可从 ByteArray 中读取并向其写入以序列化 Action Message Format (AMF) 格式编码的对 象。 AMF 是 Adobe 创建并由各种 ActionScript 3.0 类使用的专有消息协议,这些类包括 Netstream、 NetConnection、 NetStream、 LocalConnection 和 SharedObject。 单字节类型标记说明了编码数据遵循的类型。 AMF 使用以下 13 种数据类型: value-type = undefined-marker | null-marker | false-marker | true-marker | integer-type | double-type | string-type | xml-doc-type | date-type | array-type | object-type | xml-type | byte-array-type 编码数据将遵循类型标记,除非标记表示一个可能的值(例如 null、true 或 false),在这种情况下将不对任何数据进行编码。 存在两种版本的 AMF:AMF0 和 AMF3。AMF 0 通过引用支持发送复杂对象并允许端点还原对象关系。AMF 3 通过以下方 式对 AMF 0 进行了改进:通过引用发送对象 traits 和字符串,除对象引用外,还支持 ActionScript 3.0 中引入的新的数据类 型。ByteArray.objectEcoding 属性指定了用于对对象数据进行编码的 AMF 版本。flash.net.ObjectEncoding 类定义了用于指 定 AMF 版本的常量:ObjectEncoding.AMF0 和 ObjectEncoding.AMF3。 以下示例调用 writeObject() 将 XML 对象写入 ByteArray 中,随后将该 ByteArray 写入桌面上的 order 文件中。该示例在完 成时将在 AIR 窗口中显示消息 “Wrote order file to desktop!”
readObject() 方法从 ByteArray 中读取序列化 AMF 格式的对象并将其存储到指定类型的对象中。以下示例将桌面中的 order 文件读入 ByteArray (inBytes) 中并调用 readObject() 以将其存储在 orderXML 中,然后将其转换为 XML 对象文档 myXML, 并显示两个项和价格元素的值。该示例还显示了 objectEncoding 属性的值以及 order 文件内容的标头。
ByteArray 示例:读取 .zip 文件 Adobe AIR 1.0 和更高版本 该示例演示了如何读取包含若干不同类型文件的简单 .zip 文件。读取过程如下:从每个文件的元数据中提取相关数据,将每个 文件解压缩至 ByteArray 并将该文件写入桌面。 .zip 文件的一般结构基于 PKWARE Inc. 的规范(此规范位于 http://www.pkware.com/documents/casestudies/APPNOTE.TXT)。首先是 .zip 归档文件中第一个文件的文件标头和文 件数据,接下来依次是其余各文件的文件标头及文件数据。 (文件标头的结构将在后面介绍。)接下来, .zip 文件有可能包括数 据描述符记录(通常是在内存中创建输出 zip 文件而不是将其保存到磁盘的情况下包括该记录)。接下来是若干其他可选元 素:归档解密标头、归档额外数据记录、中央目录结构、中央目录记录的 Zip64 结尾、中央目录定位器的 Zip64 结尾和中央目 录记录的结尾。 本示例中所编写的代码仅用于分析不包含文件夹且不需要数据描述符记录的 zip 文件。它将忽略最后一个文件的数据后面的所 有信息。 每个文件的文件标头的格式如下: 文件标头签名 4 字节 所需版本 2 字节 一般用途位标记 2 字节 压缩方法 2 字节 (8=DEFLATE; 0=UNCOMPRESSED) 文件的最后修改时间 2 字节 文件的最后修改日期 2 字节 crc-32 4 字节 压缩后的大小 4 字节227ADOBE AIR HTML 开发人员指南 使用字节数组 上次更新 2011/10/13 文件标头的后面是实际的文件数据,既可以是压缩后的也可以是解压缩后的文件数据,具体取决于压缩方法标志。如果文件数 据为解压缩后的数据,则此标志为 0 ;如果该数据为使用 DEFLATE 算法压缩的数据,则为 8 ;如果采用的是其他压缩算法, 则为其他值。 该示例的用户界面由一个标签和一个文本区域 (taFiles) 组成。该应用程序将它在 zip 文件中遇到的各文件的以下信息写入文本 区域:文件名、压缩后的大小和解压缩后的大小。以下 MXML 文档为应用程序的 Flex 版本定义用户界面: 该示例的用户界面由一个标签和一个文本区域 (taFiles) 组成。该应用程序将它在 zip 文件中遇到的各文件的以下信息写入文本 区域:文件名、压缩后的大小和解压缩后的大小。以下 HTML 页定义了该应用程序的用户界面:
程序开头将执行以下任务: • 定义 bytes ByteArray var bytes = new air.ByteArray(); 解压缩后的大小 4 字节 文件名长度 2 字节 额外字段长度 2 字节 文件名 变量 额外字段 变量228ADOBE AIR HTML 开发人员指南 使用字节数组 上次更新 2011/10/13 • 定义用来存储文件标头中元数据的变量 // variables for reading fixed portion of file header var fileName = new String(); var flNameLength; var xfldLength; var offset; var compSize; var uncompSize; var compMethod; var signature; var output; • 定义用来表示 .zip 文件的 File (zfile) 和 FileStream (zStream) 对象,并指定将从中提取文件的 .zip 文件的位置(桌面目录 下名为 “HelloAIR.zip” 的文件)。 // File variables for accessing .zip file var zfile = air.File.desktopDirectory.resolvePath("HelloAIR.zip"); var zStream = new air.FileStream(); 在 Flex 中,程序代码从 init() 方法开始,该方法将作为根 mx:WindowedApplication 标签的 creationComplete 处理函数调用。 程序代码通过 init() 方法启动,该方法将作为 body 标签的 onload 事件处理函数调用。 function init() { 该程序将首先以 READ 模式打开 .zip 文件。 zStream.open(zfile, air.FileMode.READ); 然后将 bytes 的 endian 属性设置为 LITTLE_ENDIAN,以指示数字字段的字节顺序为最低有效字节位于最前。 bytes.endian = air.Endian.LITTLE_ENDIAN; 接下来, while() 语句开始了一个循环,直到文件流中的当前位置大于或等于文件大小时才停止循环。 while (zStream.position < zfile.size) { 循环中的第一个语句将文件流的前 30 个字节读入 ByteArray bytes 中。前 30 个字节组成了第一个文件标头的固定大小部分。 // read fixed metadata portion of local file header zStream.readBytes(bytes, 0, 30); 接下来,代码将从这 30 字节标头最前面的字节中读取一个整数 (signature)。 ZIP 格式定义指定每个文件标头的签名为十六进 制值 0x04034b50 ;如果签名不同,则表明代码已移出 zip 文件的文件部分且再没有可提取的文件。在此情况下,代码将立即退 出 while 循环而不是等待到达字节数组的结尾。 bytes.position = 0; signature = bytes.readInt(); // if no longer reading data files, quit if (signature != 0x04034b50) { break; } 代码的下一部分将在偏移量为 8 处读取标头字节并将值存储在变量 compMethod 中。该字节包含指示压缩此文件时所用压缩方 法的值。允许使用多种压缩方法,但实际上几乎所有 .zip 文件均使用 DEFLATE 压缩算法。如果当前文件以 DEFLATE 压缩 方式进行压缩,则 compMethod 为 8 ;如果文件未压缩,则 compMethod 为 0。 bytes.position = 8; compMethod = bytes.readByte(); // store compression method (8 == Deflate) 位于前 30 个字节之后的部分是标头的可变长度部分,包含了文件名并可能包含额外字段。变量 offset 用于存储此部分的大小。 该大小的计算方式为将文件名长度和额外字段长度相加,这两个长度可分别从标头中偏移量为 26 和 28 的位置读取。229ADOBE AIR HTML 开发人员指南 使用字节数组 上次更新 2011/10/13 offset = 0;// stores length of variable portion of metadata bytes.position = 26; // offset to file name length flNameLength = bytes.readShort();// store file name offset += flNameLength; // add length of file name bytes.position = 28;// offset to extra field length xfldLength = bytes.readShort(); offset += xfldLength;// add length of extra field 接下来程序将读取文件标头的可变长度部分,以将该部分的字节数存储在 offset 变量中。 // read variable length bytes between fixed-length header and compressed file data zStream.readBytes(bytes, 30, offset); 程序将从标头的可变长度部分中读取文件名并在文本区域中显示它,同时显示文件压缩后(已压缩)及解压缩后(原始)大 小。 bytes.position = 30; fileName = bytes.readUTFBytes(flNameLength); // read file name output += fileName + "
"; // write file name to text area bytes.position = 18; compSize = bytes.readUnsignedInt(); // store size of compressed portion output += "\tCompressed size is: " + compSize + '
'; bytes.position = 22; // offset to uncompressed size uncompSize = bytes.readUnsignedInt(); // store uncompressed size output += "\tUncompressed size is: " + uncompSize + '
'; 该示例从文件流中将文件的其余部分按照压缩后大小所指定的长度读入到 bytes 中,同时覆盖前 30 字节中的文件标头。即使文 件并未压缩,压缩后的大小也是精确的,因为在此情况下,压缩后的大小将等于文件未压缩时的大小。 // read compressed file to offset 0 of bytes; for uncompressed files // the compressed and uncompressed size is the same if (compSize == 0) continue; zStream.readBytes(bytes, 0, compSize); 接下来,示例将对压缩的文件进行解压缩并调用 outfile() 函数将文件写入输出文件流。它将向 outfile() 传递文件名和包含文件 数据的字节数组。 if (compMethod == 8) // if file is compressed, uncompress { bytes.uncompress(air.CompressionAlgorithm.DEFLATE); } outFile(fileName, bytes); // call outFile() to write out the file 右括号指示 while 循环、 init() 方法以及应用程序代码结束,不过 outFile() 方法除外。执行过程再次返回至 while 循环的开始处 并继续处理 .zip 文件中其余的字节:提取另一个文件,如果最后一个文件已处理完毕,则终止该 .zip 文件处理。当所有文件均 经过处理后,示例将 output 变量的内容写入 div 元素 taFiles 以便在屏幕上显示文件信息。 } // end of while loop document.getElementById("taFiles").innerHTML = output; } // end of init() method outfile() 函数将以 WRITE 模式打开桌面上的输出文件,为其指定 filename 参数提供的名称。然后该函数将把文件数据从 data 参数中写入输出文件流 (outStream) 并关闭该文件。230ADOBE AIR HTML 开发人员指南 使用字节数组 上次更新 2011/10/13 function outFile(fileName, data) { var outFile = air.File.desktopDirectory; // dest folder is desktop outFile = outFile.resolvePath(fileName); // name of file to write var outStream = new air.FileStream(); // open output file stream in WRITE mode outStream.open(outFile, air.FileMode.WRITE); // write out the file outStream.writeBytes(data, 0, data.length); // close it outStream.close(); } 231 上次更新 2011/10/13 第 17 章 : 在 AIR 中添加 PDF 内容 Adobe AIR 1.0 和更高版本 Adobe® AIR® 中运行的应用程序不仅可以呈现 SWF 和 HTML 内容,而且还能呈现 PDF 内容。 AIR 应用程序使用 HTMLLoader 类、WebKit 引擎和 Adobe® Reader® 浏览器插件来呈现 PDF 内容。在 AIR 应用程序中,PDF 内容可以沿应 用程序的全高和全宽进行拉伸,也可以作为界面的一部分。 Adobe Reader 浏览器插件控制 AIR 应用程序中的 PDF 文件显 示。对 Reader 工具栏界面(例如控件的位置、定位和可见性)的修改仍然存在于对 AIR 应用程序和浏览器中的 PDF 文件的 后续查看中。 重要说明: 要在 AIR 中呈现 PDF 内容,用户必须安装 Adobe Reader 或 Adobe® Acrobat® 版本 8.1 或更高版本。 检测 PDF 功能 Adobe AIR 1.0 和更高版本 如果用户没有 Adobe Reader 或 Adobe Acrobat 8.1 或更高版本,则无法在 AIR 应用程序中显示 PDF 内容。若要检测用户 是否能够呈现 PDF 内容,请首先检查 HTMLLoader.pdfCapability 属性。此属性设置为 HTMLPDFCapability 类的以下常量 之一: 在 Windows 上,如果用户的系统上运行的是 Adobe Acrobat 或 Adobe Reader 版本 7.x 或更高版本,即使安装了支持加载 PDF 的最新版本,也会使用当前运行的版本。在这种情况下,如果 pdfCapability 属性的值是 HTMLPDFCapability.STATUS_OK,则当 AIR 应用程序尝试加载 PDF 内容时,较旧版本的 Acrobat 或 Reader 会显示警报 (并且 AIR 应用程序中不会引发异常)。如果您的最终用户有可能遇到这种情况,则可以考虑向他们提供说明,告知他们在运 行应用程序的同时关闭 Acrobat。如果 PDF 内容在可以接受的时间范围内未加载,则您可能希望显示这些说明。 在 Linux 中, AIR 在由用户导出的 PATH (如果其包含 acroread 命令)中和 /opt/Adobe/Reader 目录中查找 Adobe Reader。 以下代码检测用户能否在 AIR 应用程序中显示 PDF 内容。如果用户无法显示 PDF,代码会跟踪对应于 HTMLPDFCapability 错误对象的错误代码: 常量 说明 HTMLPDFCapability.STATUS_OK 已检测到足够高的 Adobe Reader 版本( 8.1 或更高版本),可以将 PDF 内容加载到 HTMLLoader 对象中。 HTMLPDFCapability.ERROR_INSTALLED_READER_NOT_FO UND 未检测到任何 Adobe Reader 版本。 HTMLLoader 对象无法显示 PDF 内容。 HTMLPDFCapability.ERROR_INSTALLED_READER_TOO_OL D 已检测到 Adobe Reader,但版本太旧。 HTMLLoader 对象无法显示 PDF 内容。 HTMLPDFCapability.ERROR_PREFERRED_READER_TOO_OL D 检测到的 Adobe Reader 版本足够高( 8.1 或更高版本),但为处理 PDF 内容所安装的 Adobe Reader 版本早于 Reader 8.1。HTMLLoader 对象 无法显示 PDF 内容。 232ADOBE AIR HTML 开发人员指南 在 AIR 中添加 PDF 内容 上次更新 2011/10/13 if(air.HTMLLoader.pdfCapability == air.HTMLPDFCapability.STATUS_OK) { air.trace("PDF content can be displayed"); } else { air.trace("PDF cannot be displayed. Error code:", HTMLLoader.pdfCapability); } 加载 PDF 内容 Adobe AIR 1.0 和更高版本 可以通过创建 HTMLLoader 实例、设置其尺寸以及加载 PDF 的路径,将 PDF 添加到 AIR 应用程序。 可以像在浏览器中那样,将 PDF 添加到 AIR 应用程序。例如,可以将 PDF 加载到窗口的顶级 HTML 内容、对象标签、 frame 或 iframe 中。 以下示例从外部站点加载 PDF。将 iframe 的 src 属性值替换为可用外部 PDF 的路径。

PDF test