使用Apps Script API的Chrome应用

时间:2016-04-23 12:43:18

标签: javascript google-apps-script google-chrome-app

今天进入另一个路障,在我编写用于记录用户项目时间的桌面Chrome应用程序的道路上。

我想要做的(并且失败)是使用Apps Script API访问一个google工作表,该工作表保留了我想在Chrome App UI中填充下拉列表的信息(项目编号)。

更新 我已经重新阐述了这一点,以便明确我的问题。

我似乎无法实现从我的Chrome应用程序调用Apps脚本功能。我已经阅读了这个Execution API,但似乎仍然无法进行着色。由于某些原因,我不断得到"未捕获的ReferenceError:gapi未定义"在我的控制台中。

我设法做的是在开发者控制台中使用相同项目名称的Apps脚本和Chrome应用程序。不知道是否需要,但认为它可能只有1 Oauth2请求。

我的头部缺少什么东西?

非常感谢任何帮助或想法。

这是我的manifest.json

{
  "manifest_version": 2,
  "name": "TimeSheet",
  "description": "Small and easy desktop app for entering time spent on project files",
  "version": "0.1.0",
  "icons": {
    "128": "icon_128.png"
  },
  "app": {
    "background": {
      "scripts": ["background.js"]
    }
  },
  "permissions": [
    "identity",
    "app.window.alwaysOnTop"
    ],
  "oauth2": {
    "client_id": "clientid.apps.googleusercontent.com",
    "scopes": [
      "https://www.googleapis.com/auth/drive",
      "https://www.googleapis.com/auth/spreadsheets"

      ]
  },
  "key": "very long string"
}

这是在我的main.js

中运行的Oauth2代码
//This code confirms Oauth2 for access to google drive and related files

window.onload = function(){

  document.querySelector("#Oauth2").addEventListener("click", function(){

    chrome.identity.getAuthToken({"interactive": true}, function(token){
      console.log(token);

    });
  });

};

// ID of the script to call. Acquire this from the Apps Script editor,
// under Publish > Deploy as API executable.
var scriptId = "blah";
// Create execution request.
var request = {
    'function': 'getProjectNumbers',
};

// Make the request.
var op = gapi.client.request({
    'root': 'https://script.googleapis.com',
    'path': 'v1/scripts/' + scriptId + ':run',
    'method': 'POST',
    'body': request
});
// Log the results of the request.
op.execute(function(resp) {
  if (resp.error && resp.error.status) {
    // The API encountered a problem before the script started executing.
    console.log('Error calling API: ' + JSON.stringify(resp, null, 2));
  } else if (resp.error) {
    // The API executed, but the script returned an error.
    var error = resp.error.details[0];
    console.log('Script error! Message: ' + error.errorMessage);
    if (error.scriptStackTraceElements) {
      // There may not be a stacktrace if the script didn't start executing.
      console.log('Script error stacktrace:');
      for (var i = 0; i < error.scriptStackTraceElements.length; i++) {
        var trace = error.scriptStackTraceElements[i];
        console.log('\t' + trace.function + ':' + trace.lineNumber);
      }
    }
  } else {
    // Here, the function returns an array of strings.
    var projectNumbers = resp.response.result;
    console.log('Project numbers in spreadsheet:');
    projectNumbers.forEach(function(name){
      console.log(name);
    });
  }
});

这是应用程序脚本代码:

var projectDatabaseKey = 'blah'; //Project Database Sheet spreadsheet key
var pprojectDatabaseSheet = 'Project Database'; //Project Database  Sheet spreadsheet sheet

//Function to revieve data of project numbers for drop down list
function getProjectNumbers() {
  return SpreadsheetApp
   .openById(projectDatabaseKey).getSheetByName(projectDatabaseSheet)
   .getRange("A2:A" + (SpreadsheetApp.openById(projectDatabaseKey).getSheetByName(projectDatabaseSheet).getLastRow()))
   .getValues();
}

我真的不确定如何使用Oauth2令牌以及如何将其应用于apps脚本。

更新

好的,我曾尝试在不同的庄园中调用应用程序脚本,今天我正在尝试使用gapi-chrome-apps.js库来执行oauth2工作。

现在我的问题是我得到了这个错误,这可能是我猜的一系列事情:

  

POST https://www.googleapis.com/v1/scripts/blahblah:run 404()

     

gapi.client.request @ VM80 gapi-chrome-apps.js:105

     

getSheetsList @ gapiCallback.js:17

     

(匿名函数)@ gapiCallback.js:49

     

callbackWrapper @ VM80 gapi-chrome-apps.js:68

     

target。(匿名函数)@ extensions :: SafeBuiltins:19

     

safeCallbackApply @ extensions :: sendRequest:21

     

handleResponse @ extensions :: sendRequest:72

这个错误,来自gapi-chrome-apps.js脚本:

  

Uncaught SyntaxError:位于0的JSON中的意外标记N

真的不确定导致这种情况的原因,这是我的更新代码:

//get listof sheets in spreadsheet
function getSheetsList(){
  var scriptId = "blahblah";
  // Initialize parameters for function call.
  var sheetId = "blahblah";
  // Create execution request.
  var requests = {
      'function': 'getSheetNames',
      'parameters': [sheetId],
      'devMode': true   // Optional.
  };
  // Make the request.
  gapi.client.request({
      'root': 'https://script.googleapis.com',
      'path': 'v1/scripts/' + scriptId + ':run',
      'method': 'POST',
      'body': requests,
      'callback': printSheetsList
  });
}
// Log the results of the request.
function printSheetsList(resp) {
  if (resp.error && resp.error.status) {
    // The API encountered a problem before the script started executing.
    console.log('Error calling API: ' + JSON.stringify(resp, null, 2));
  } else if (resp.error) {
    // The API executed, but the script returned an error.
    var error = resp.error.details[0];
    console.log('Script error! Message: ' + error.errorMessage);
  } else {
    // Here, the function returns an array of strings.
    var sheetNames = resp.response.result;
    console.log('Sheet names in spreadsheet:');
    sheetNames.forEach(function(name){
    console.log(name);
    });
  }
}
//Prompts the user for authorization and then proceeds to 
function authorize(params, callback) {
  gapi.auth.authorize(params, function(accessToken) {
    if (!accessToken) {
      console.log("Error getting authorization");
    } else {
      callback();
    }
  });
}
function gapiIsLoaded() {
  var params = { 'immediate': true };
  if (!(chrome && chrome.app && chrome.app.runtime)) {
    params.scope = "https://www.googleapis.com/auth/drive";
    params.client_id = "blahblah";
    gapi.auth.init(authorize.bind(null, params, getSheetsList));
  } else {
    authorize(params, getSheetsList);
  }
}

2 个答案:

答案 0 :(得分:2)

使用传统的GAPI无法运行,因为它会动态加载更多外部脚本和应用are not allowed to do that

一种可能的解决方案是在sandboxed page中运行GAPI代码,这可以克服远程代码限制。但是,这很麻烦,因为您需要使用postMessage来回传递数据。

另一种方法是尝试使用Google提供的库gapi-chrome-apps.js,该库适用于Chrome应用(并使用chrome.identity管理OAuth) - 但请注意此评论:

  

如果没有其他修改,此库可能不适合使用。

答案 1 :(得分:0)

根据您的帖子,您只是没有定义gapi。你可以像这样加载它

jQuery.getScript( "https://apis.google.com/js/api.js", onApiLoad );

其中onApiLoad是您在加载gapi时要调用的函数。

对于你的代码,我会将以下代码包装在这样的函数中:

function onApiLoad() {
    // Make the request.
    var op = gapi.client.request({
        'root': 'https://script.googleapis.com',
        'path': 'v1/scripts/' + scriptId + ':run',
        'method': 'POST',
        'body': request
    });
    // Log the results of the request.
    op.execute(function(resp) {
      if (resp.error && resp.error.status) {
        // The API encountered a problem before the script started executing.
        console.log('Error calling API: ' + JSON.stringify(resp, null, 2));
      } else if (resp.error) {
        // The API executed, but the script returned an error.
        var error = resp.error.details[0];
        console.log('Script error! Message: ' + error.errorMessage);
        if (error.scriptStackTraceElements) {
          // There may not be a stacktrace if the script didn't start executing.
          console.log('Script error stacktrace:');
          for (var i = 0; i < error.scriptStackTraceElements.length; i++) {
            var trace = error.scriptStackTraceElements[i];
            console.log('\t' + trace.function + ':' + trace.lineNumber);
          }
        }
      } else {
        // Here, the function returns an array of strings.
        var projectNumbers = resp.response.result;
        console.log('Project numbers in spreadsheet:');
        projectNumbers.forEach(function(name){
          console.log(name);
        });
      }
    });

}

编辑:没有jQuery,只有纯JS

感谢the second answer in this post,下面的代码是$ .getScript()的纯JS实现。它包含一个回调,所以下面的代码片段应该可以工作,假设你将代码包装在一个函数中,如上所述。

function getScript(source, callback) {
    var script = document.createElement('script');
    var prior = document.getElementsByTagName('script')[0];
    script.async = 1;
    prior.parentNode.insertBefore(script, prior);

    script.onload = script.onreadystatechange = function( _, isAbort ) {
        if(isAbort || !script.readyState || /loaded|complete/.test(script.readyState) ) {
            script.onload = script.onreadystatechange = null;
            script = undefined;

            if(!isAbort) { if(callback) callback(); }
        }
    };

    script.src = source;
}


getScript("https://apis.google.com/js/api.js", onApiLoad);