导入和导出项目

由于 Apps 脚本项目位于 Google 云端硬盘中,因此开发者可以使用 Google Drive API 导入和导出 Apps 脚本源代码(不要与 Apps 脚本中的云端硬盘服务相混淆)。

例如,开发者可以在本地计算机上使用她最喜欢的代码编辑器编写新的 Apps 脚本代码,并使用 Git 等版本控制系统与其他开发者协作。版本最终确定后,她可以使用 REST API 将文件上传到 Google 云端硬盘(在 Google 云端硬盘中可以像使用任何其他 Apps 脚本项目一样使用这些文件)。

您可以在本地版本中进行代码更改,也可以使用 Google Drive API 将其同步到 Apps 脚本项目。您可以将现有项目从 Google 云端硬盘下载(导出)到本地机器。

功能和限制

如果要使用 Google Drive API 导入或导出项目,请注意以下事项:

  1. 服务器端脚本文件应以“.gs”结尾。您可能希望使用 .js 文件在本地进行开发,但请务必在导入到 Google 云端硬盘之前重命名文件以包含 .gs 扩展名。
  2. 客户端脚本文件必须以“.html”结尾。其中包括客户端 .html、.js 或 .css 文件。同样,您也可以使用其他扩展名进行本地开发,但在导入 Google 云端硬盘之前,务必使用 .html 扩展名。
  3. 将项目文件导入 Google 云端硬盘时,这些文件中的所有现有数据都将被覆盖。您无法附加或插入部分文本;必须更新整个文件。
  4. 服务器端脚本文件必须包含有效的 JavaScript。如果您的服务器 .js 文件中存在错误,Google Drive API 更新调用将失败并显示 5xx 错误。为防止出现这种情况,您可以在导入之前对代码执行 lint 检查。
  5. 无法导入空文件。如果您尝试上传空文件,Google Drive API 更新调用将失败,并显示 5xx 错误。
  6. 只能导入或导出独立脚本。无法通过 Google Drive API 访问绑定到容器的脚本。
  7. 只能导入或导出源代码。项目属性或日志等资源也不会通过 Google Drive API 公开。您无法通过 Google Drive API 执行脚本版本控制、发布或执行脚本等操作。
  8. 您可以使用不限于单个服务器 Code.gs 文件。您可以将服务器代码分布在多个文件中,以方便开发。所有服务器文件都会加载到同一个全局命名空间中,因此,如果要提供安全封装,请使用 JavaScript 类。

Drive API

借助 Google Drive API,开发者可以以编程方式访问 Google 云端硬盘中的文件。此 API 使用 GET 下载文件,并使用 PUT/POST 上传文件。如需查看详细文档和快速入门,请参阅 Google Drive API 概览页面

本指南将重点介绍使用以下调用通过“文件”资源列出和移动文件:

授权

向 Google Drive API 发出的所有请求都必须由经过身份验证的用户通过 OAuth 2.0 协议进行授权。如需了解详情,请参阅 Google Drive API 授权文档

除了应用可能需要的其他范围(例如 https://www.googleapis.com/auth/drive)之外,尝试导入或导出 Google Apps 脚本项目的所有应用还必须请求特殊范围:

https://www.googleapis.com/auth/drive.scripts

列出现有项目

如需列出云端硬盘中的所有 Apps 脚本项目,请使用“文件”资源查询 MIME 类型为 application/vnd.google-apps.script 的文件。如需过滤响应以仅包含您拥有的文件,请添加搜索参数 'me' in owners

以下是一个示例请求和响应,其中显示了通过 JSON 响应返回的 Apps 脚本项目数组。

GET https://www.googleapis.com/drive/v2/files?q=mimeType%3D'application%2Fvnd.google-apps.script'+and+'me'+in+owners
Authorization:  Bearer ya29.fakebearerstring
{
 "kind": "drive#fileList",
 "etag": "\"kjsas92/f3zGUXczKMxEB_9ZTMRFOF3d1ZU\"",
 "selfLink": "https://www.googleapis.com/drive/v2/files?q=mimeType%3D'application/vnd.google-apps.script'+and+'me'+in+owners",
 "items": [
  {
   "kind": "drive#file",
   "id": "1vi0uwcMdHsRv1YFtgq7XdiTGSdqgjIYpdQNC0A_Udn79LOhH0vYL132D",
   "etag": "\"kjsas92/MTM3MDk3ODY5ODQyNg\"",
   "selfLink": "https://www.googleapis.com/drive/v2/files/1vi0uwcMdHsRv1YFtgq7XdiTGSdqgjIYpdQNC0A_Udn79LOhH0vYL132D",
   "alternateLink": "https://script.google.com/a/google.com/d/1vi0uwcMdHsRv1YFtgq7XdiTGSdqgjIYpdQNC0A_Udn79LOhH0vYL132D/edit?usp=drivesdk",
   "iconLink": "https://ssl.gstatic.com/docs/doclist/images/icon_11_script_list.png",
   "title": "Mail merge",
   "mimeType": "application/vnd.google-apps.script",
   "description": "",
   "labels": {
    "starred": false,
    "hidden": false,
    "trashed": true,
    "restricted": false,
    "viewed": true
   },
   "createdDate": "2013-06-11T19:24:45.188Z",
   "modifiedDate": "2013-06-11T19:24:58.426Z",
   "modifiedByMeDate": "2013-06-11T19:24:58.426Z",
   "lastViewedByMeDate": "2013-06-11T19:24:58.426Z",
   "parents": [
    {
     "kind": "drive#parentReference",
     "id": "0APdyIOzo7bWDUk9PVA",
     "selfLink": "https://www.googleapis.com/drive/v2/files/1vi0uwcMdHsRv1YFtgq7XdiTGSdqgjIYpdQNC0A_Udn79LOhH0vYL132D/parents/0APdyIOzo7bWDUk9PVA",
     "parentLink": "https://www.googleapis.com/drive/v2/files/0APdyIOzo7bWDUk9PVA",
     "isRoot": true
    }
   ],
   "exportLinks": {
    "application/json": "https://script.google.com/feeds/download/export?id=1234567890abcefghijklmnopqrstuvwxyz&format=json"
   },
   "userPermission": {
    "kind": "drive#permission",
    "etag": "\"kjsas92/259X2r5DVstv1CcIQTjt_RQPSW8\"",
    "id": "me",
    "selfLink": "https://www.googleapis.com/drive/v2/files/1vi0uwcMdHsRv1YFtgq7XdiTGSdqgjIYpdQNC0A_Udn79LOhH0vYL132D/permissions/me",
    "role": "owner",
    "type": "user"
   },
   "quotaBytesUsed": "0",
   "ownerNames": [
    "John Doe"
   ],
   "owners": [
    {
     "kind": "drive#user",
     "displayName": "John Doe",
     "picture": {
      "url": "https://lh4.googleusercontent.com/-yd1rIb6Pe2Y/AAAAAAAAAAI/AAAAAAAAAGs/PP5vTuZonik/s64/photo.jpg"
     },
     "isAuthenticatedUser": true,
     "permissionId": "1234566789"
    }
   ],
   "lastModifyingUserName": "John Doe",
   "lastModifyingUser": {
    "kind": "drive#user",
    "displayName": "John Doe",
    "picture": {
     "url": "https://lh4.googleusercontent.com/-yd1rIb6Pe2Y/AAAAAAAAAAI/AAAAAAAAAGs/PP5vTuZonik/s64/photo.jpg"
    },
    "isAuthenticatedUser": true,
    "permissionId": "1234566789"
   },
   "editable": true,
   "writersCanShare": true,
   "shared": false,
   "explicitlyTrashed": true,
   "appDataContents": false
  }
 ]
}

如果您知道 Apps 脚本项目的文件 ID,可以直接使用以下 API 调用提取该文件:

GET https://www.googleapis.com/drive/v2/files/1234567890abcefghijklmnopqrstuvwxyz
Authorization:  Bearer ya29.fakebearerstring

从云端硬盘中导出项目

从 API 获取 File 资源后,exportLinks 属性将包含要提取的网址,以获取 JSON 数据形式的项目内容。此网址的示例如下:

https://script.google.com/feeds/download/export?id=1234567890abcefghijklmnopqrstuvwxyz&format=json

向此网址发出请求,以检索项目本身的内容。 确保包含具有相同 OAuth Bearer 令牌的 Authorization 标头

以下是示例请求和响应:

GET https://script.google.com/feeds/download/export?id=1234567890abcefghijklmnopqrstuvwxyz&format=json
Authorization:  Bearer ya29.fakebearerstring
{
  "files": [
    {
      "id":"9basdfbd-749a-4as9b-b9d1-d64basdf803",
      "name":"Code",
      "type":"server_js",
      "source":"function doGet() {\n  return HtmlService.createHtmlOutputFromFile(\u0027index\u0027);\n}\n"
    },
    {
      "id":"3asf7c0d-1afb-4a9-8431-5asdfc79e7ae",
      "name":"index",
      "type":"html",
      "source":"\u003chtml\u003e\n  \u003cbody\u003e\n    Hello, world!\n  \u003c/body\u003e\n\u003c/html\u003e"
    }
  ]
}

上面的示例包含 HTML 服务指南中一个简单 Web 应用的代码。请注意,您会返回一个 Files 数组,其中每个数组都有以下 4 个属性:

id 项目中文件的内部标识符,更新期间引用此文件需要。
name 不带扩展名的文件名称,如“脚本编辑器”中所示。
type 两种类型的文件是 server_js 和 html。
source 文件中包含的经过编码的源代码。

将项目导入云端硬盘

如需更新现有项目,请使用适当的 fileId 对文件 update API 进行 HTTP PUT 调用。以下示例展示了媒体上传部分的一个示例交易。使用其中一个客户端库,您的应用可以轻松地在同一上传调用中添加元数据和媒体。请注意,在这种情况下,Content-Type 标头会指定所上传内容的类型。

PUT https://www.googleapis.com/upload/drive/v2/files/1234567890abcefghijklmnopqrstuvwxyz
Authorization:  Bearer ya29.fakebearerestring
Content-Type:  application/vnd.google-apps.script+json
{
  "files": [
    {
      "id":"9basdfbd-749a-4as9b-b9d1-d64basdf803",
      "name":"Code",
      "type":"server_js",
      "source":"function doGet() {\n  return HtmlService.createHtmlOutputFromFile(\u0027index\u0027);\n}\n"
    },
    {
      "id":"3asf7c0d-1afb-4a9-8431-5asdfc79e7ae",
      "name":"index",
      "type":"html",
      "source":"\u003chtml\u003e\n  \u003cbody\u003e\n    New message!!\n  \u003c/body\u003e\n\u003c/html\u003e"
    }
  ]
}

在项目中创建新文件

如需在项目中创建新文件,请针对没有 id 属性的文件发送 PUT 请求。如果您添加的文件具有未知标识符,系统将抛出错误消息。

删除项目中的文件

如需从项目中删除文件,请发送一个 PUT 请求,该请求不包含该文件(但包含项目中的所有其他文件)。导入过程中未发送回的任何文件都将从服务器中删除。

重命名项目中的文件

如需重命名项目中的文件,请使用现有的 id 发送 PUT 请求,但发送新的 name。请注意,服务器会忽略所有尝试更改为 type 的操作。

创建新项目

如需创建新项目,请向文件 insert API 发送 POST 请求。与 update 调用非常相似,您可以使用客户端库来添加项目名称和说明等元数据。

下面是一个媒体上传交易示例。这将在您的云端硬盘中创建一个名为“Untitled”的项目。网址中 convert 参数是必需的。与 update 调用一样,Content-Type 标头是必需的。

POST https://www.googleapis.com/upload/drive/v2/files?convert=true
Authorization:  Bearer ya29.fakebearerestring
Content-Type:  application/vnd.google-apps.script+json
{
  "files": [
    {
      "name":"Code",
      "type":"server_js",
      "source":"function doGet() {\n  return HtmlService.createHtmlOutputFromFile(\u0027index\u0027);\n}\n"
    },
    {
      "name":"index",
      "type":"html",
      "source":"\u003chtml\u003e\n  \u003cbody\u003e\n    Hello, world!!\n  \u003c/body\u003e\n\u003c/html\u003e"
    }
  ]
}