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