Доступ к Google Drive API через Cordova

6 минут(ы) чтения
Google Console

С Cordova трудно работать. Особенно когда используешь с ней сторонние web-сервисы. Так и теперь, типичный парсер использующий Google Spreadsheet занял у меня почти 2 недели.

Обо всём этом по-порядку.
При разработке решил хранить и модифицировать клиентские данные в одной совместной таблице на Spreadsheet. Короче, сделать выгрузку в CSV легко не получилось, поэтому заюзал Apps Script. С ним можно взаимодействовать со многими Google сервисами по REST-API. Получилось вот так (наработки по выгрузке CSV сохранил здесь). Apps Script, в целом, мне не понравился. Такая древняя технология, основанная на EcmaScript 3, с простеньким веб-редактором, дебаггером, версионностью и легкой интеграцией с консолью Google.
Правильные шаги получения результата из Apps Script такие:
1. Загрузить gapi либу;
2. Показать окно с авторизацией;
3. Ввести логин+пароль и получить токен;
4. Исполтзовать токен для доступа к данным.
Успешно оттестировав на браузере при портировании под Cordova получил ошибку:

Refused to display… бла-бла-бла …in a frame because it set ‘X-Frame-Options’ to ‘SAMEORIGIN’.


Оказалось gapi не работает с cordova. Путем долгого чтения док и стэковерфлоу все же нашел решение.
Его листинг приложил ниже:

function googleOAuth(CLIENT_ID, SCOPES) {
  return new Promise((resolve, reject) => {
    if (!window.cordova) {
      window.gapi.auth.authorize({
        client_id: CLIENT_ID,
        scope: SCOPES,
        response_type: ‘token’,
        immediate: false
      }, (authResult) => {
        resolve(authResult);
      });
    } else {
      if (window.cordova.InAppBrowser) {
        const redirect_uri = ‘http://localhost/callback’;
        const browserRef = window.cordova.InAppBrowser.open(
          `https://accounts.google.com/o/oauth2/auth?client_id=${CLIENT_ID}` +
          `&redirect_uri=${redirect_uri}` +
          `&scope=${SCOPES.join(‘ ‘)}` +
          ‘&approval_prompt=force’ +
          ‘&response_type=token id_token’,
          ‘_blank’,
          ‘location=no,clearsessioncache=yes,clearcache=yes’
        );
        browserRef.addEventListener(‘loadstart’, (event) => {
          if ((event.url).indexOf(redirect_uri) === 0) {
            browserRef.removeEventListener(‘exit’, () => {
            });
            browserRef.close();
            let callbackResponse = (event.url).split(‘#’)[1];
            let responseParameters = (callbackResponse).split(‘&’);
            let parameterMap = [];
            for (let i = 0; i < responseParameters.length; i++) {
              parameterMap[responseParameters[i].split(‘=’)[0]] = responseParameters[i].split(‘=’)[1];
            }
            if (parameterMap.access_token !== undefined && parameterMap.access_token !== null) {
              resolve({
                access_token: parameterMap.access_token,
                expires_in: parameterMap.expires_in,
                id_token: parameterMap.id_token,
                token_type: parameterMap.token_type
              });
            } else {
              reject(‘Problem authenticating’);
            }
          }
        });
        browserRef.addEventListener(‘exit’, () => {
          reject(‘The sign in flow was canceled’);
        });
      } else {
        reject(‘Could not find InAppBrowser plugin’);
      }
    }
  });
}

Залив очередной билд на девайс получил уже другую ошибку. Теперь попросту не открывалось окно авторизации. Приложение ругалось на запросы через file:///
Пофиксил это установив плагин InAppBrowser.

Далее окно авторизации уже стало работать. Но с ошибкой. Не нравился мой callback-запрос.
В консоле убрал последний слэш в запросе http://localhost/callback

Далее приложение ругалось на невозможность выполнения запросов.
Пофиксил это, установив плагин whitelist и добавил в config.xml следующее содержимое:

<access origin=»*» launch-external=»yes» />
<allow-navigation href=»https://ssl.gstatic.com/*» />
<allow-navigation href=»https://apis.google.com/*» />
<allow-navigation href=»https://*.googleusercontent.com/*» />
<allow-navigation href=»https://accounts.google.com/*» />
<allow-navigation href=»https://www.googleapis.com/*» />
<allow-navigation href=»https://*.googleapis.com/*» />
<allow-intent href=»*» />
<allow-intent href=»https://*.googleapis.com/*» />
<allow-intent href=»https://apis.google.com/*» />

На всякий случай добавил вот такую мету в index.html:
<meta http-equiv=»Content-Security-Policy»
content=»default-src ; img-src ‘self’ data: blob: filesystem:; script-src ‘self’ ‘unsafe-inline’ ‘unsafe-eval’ ; style-src ‘self’ ‘unsafe-inline’ *»>
Короче говоря, пока занимался такой вот тривиальной задачей так устал, что думал вообще останавливать запил игрули. Но спустя две недели я получил необходимый массив значений на девайсе. Но вот, честно сказать, никакой радости от этого я уже не испытываю.

Либу cordova-google-oauth2 выложил с лицензией MIT.

Добавить комментарий