Podem crear un codi executable (anomenat script) que interactuï amb el nostre full de càlcul. Una manera senzilla d'executar aquest codi des de l'App Inventor és creant una funció que s'executi quan rep una ordre HTTP de tipus post. El nostre script tindrà, doncs, una adreça URL que ens permetrà executar-lo des de l'App Inventor.
En el nostre full de càlcul, anirem a la pestanya Extensions i triarem l'opció Apps Script. Se'ns obrirà una finestra similar a la següent:

Hem d'esborrar la funció buida myFunction i deixar l'espai en blanc. Ara hem de descarregar el nostre script, que més endavant comentarem. Si piquem l'enllaç se'ns obrirà. Copiem tot el text i l'enganxem a la finestra de l'editor d'scripts. Un cop enganxat, haurem de fer-hi un canvi. Haurem de modificar la primera línia per posar-hi el codi de la taula que hem trobat a l'apartat anterior.

Un cop personalitzat el programa l'hem de guardar, picant el botó que es mostra a continuació.
Picarem el botó Implementar.
En el desplegable triarem Nueva implementación i s'obrirà una finestra similar a la següent:

El primer cop que ho fem, haurem de picar en el botó que es mostra a continuació.
I triar l'opció Aplicación web. La finestra ens preguntarà en nom de qui volem que s'executi l'aplicació (li direm Yo) i qui hi té accés (li direm que qualsevol usuari). Finalment, picarem el botó Implementar.

Se'ns mostrarà una pantalla en la que se'ns indicarà l'adreça URL de l'aplicació, que haurem de copiar.
| URL script | https://script.google.com/macros/s/^^fycbxqrJpVA-KT1sUd8HIta643R3bH4ixpDahttayGSGjkpHUBjPQ/exec |
Un cop estiguem, podem picar el botó Listo.
Atenció: Hem de recordar que cal guardar el programa (botó del disquet) abans d'implementar, si no ho fem ens implementarà la darrera versió guardada que no serà l'actual.
Ara anem a comentar les diferents parts del nostre script. Podeu trobar informació sobre la programació en Google Apps Script en aquest web. Tenim una variable global que conté l'identificador del full de càlcul.
var ssId = "1d0176v9_8iFIaPGe3DjKUPCl3KdT4bt8NTICcwEwl1U"; // Identificador del full de càlcul
En l'aplicació, l'usuari podrà triar el gènere entre els que ja consten prèviament o afegir-ne un de mou. La funció miraGenere rep el gènere que ha enviat l'aplicació, comprova si ja està a la taula i si no ho està li afegeix.
function miraGenere(par){
var sheet = SpreadsheetApp.openById(ssId).getSheetByName("Generes"); // Agafem el full
var mida = sheet.getLastRow(); // Índex de la darrera filera
var elem = sheet.getDataRange().getValues();
var trobat = 0;
for(var j = 1; j < mida; j++){
var fil = elem[j]; // Agafem la filera
var gen = fil[0]; // Agafem el gènere
if(gen == par){
trobat = 1;
}
}
if(trobat == 0){
var camp = new Array(1); // Valors per guardar a la taula
camp[0] = par;
sheet.appendRow(camp);
}
}
La funció Gener prepara una llista amb tots els gèneres que hi ha a la taula, un per línia; aquesta llista s'enviarà a l'aplicació per poder posar el contingut del selector de gènere. A l'inici de la llista s'hi posa el títol del darrer llibre introduït, ja que l'aplicació el mostra; això serveix a l'usuari per poder comprovar que el darrer llibre s'ha introduït correctament.
function Gener(){
var sh = SpreadsheetApp.openById(ssId).getSheetByName("Llistat"); // Agafem el full
var total = sh.getLastRow(); // Índex de la darrera filera
var el = sh.getDataRange().getValues();
var filer = el[total - 1]; // Agafem la darrera filera del llistat de llibres
var llis = filer[2]; // Agafa el títol del darrer llibre introduït
var sheet = SpreadsheetApp.openById(ssId).getSheetByName("Generes"); // Agafem el full
var mida = sheet.getLastRow(); // Índex de la darrera filera
var elem = sheet.getDataRange().getValues();
var tot = +total - 1;
llis = llis + "\n" + tot;
for(var j = 1; j < mida; j++){
var fil = elem[j]; // Agafem la filera
var gen = fil[0]; // Agafem el gènere
llis = llis + "\n" + gen;
}
return llis;
}
La funció Cerca és la que es fa servir quan l'usuari està cercant un libre a la taula. El paràmetre és un vector que conté les dades de cerca que ha introduït l'usuari més un índex que serveix per saber a partir de quin resultat cal començar a mostrar. La funció retorna un llistat, de fins a un màxim de cinc resultats, en el que cada línia conté les dades d'un dels llibres que es correspon amb els paràmetres de cerca i les dades de cada llibre estan separades pel signe ^.
function Cerca(info){
var autor = info[0].toLowerCase();
var titol = info[1].toLowerCase();
var index = +info[2];
var sheet = SpreadsheetApp.openById(ssId).getSheetByName("Llistat"); // Agafem el full
var mida = sheet.getLastRow(); // Índex de la darrera filera
var elem = sheet.getDataRange().getValues();
var llis = "";
var c_full = 1; // Comptador de línies del full
var c_res = 0; // Comptador de resultats
while(c_full < mida){
var fil = elem[c_full]; // Agafem la filera
var aut = fil[1].toLowerCase();
var tit = fil[2].toLowerCase();
var toca = 0;
if((fil[6] == 0) || ((fil[6] == 1) && (info[3] == 1))){ // Mirem si està esborrat i si cal mostrar-lo
if((tit.indexOf(titol) >= 0) && (titol.length > 0) && (autor.length == 0)){
toca = 1;
}
if((aut.indexOf(autor) >= 0) && (autor.length > 0) && (titol.length == 0)){
toca = 1;
}
if((tit.indexOf(titol) >= 0) && (aut.indexOf(autor) >= 0) && (autor.length > 0) && (titol.length > 0)){
toca = 1;
}
}
if(toca == 1){ // Si s'ha de mostrar
c_res++;
if((c_res >= index) && (c_res < index+5)){
llis = llis + "\n";
for(var j = 0; j < fil.length; j++){
if(j > 0){
llis = llis + "^";
}
llis = llis + fil[j];
}
}
}
c_full++;
}
llis = c_res + llis;
return llis
}
La funció Llista serveix per generar el llistat de tots els llibres, que pot estar ordenat en l'ordre que han estat introduïts o en l'invers. El paràmetre és un vector que conté les dades necessàries. La funció retorna un llistat, de fins a un màxim de cinc resultats, en el que cada línia conté les dades d'un dels llibres i les dades de cada llibre estan separades pel signe ^.
function Llista(info){
var index = +info[1];
var sheet = SpreadsheetApp.openById(ssId).getSheetByName("Llistat"); // Agafem el full
var mida = sheet.getLastRow(); // Índex de la darrera filera
var elem = sheet.getDataRange().getValues();
var llis = "";
var c_res = 0; // Comptador de resultats
if(info[0] == "d"){
var c_full = 1; // Comptador de línies del full
while(c_full < mida){
var fil = elem[c_full]; // Agafem la filera
if((fil[6] == 0) || ((fil[6] == 1) && (info[2] == 1))){
c_res++;
if((c_res >= index) && (c_res < index+5)){
llis = llis + "\n";
for(var j = 0; j < fil.length; j++){
if(j > 0){
llis = llis + "^";
}
llis = llis + fil[j];
}
}
}
c_full++;
}
} else {
var c_full = mida - 1; // Comptador de línies del full
while(c_full >= 1){
var fil = elem[c_full]; // Agafem la filera
if((fil[6] == 0) || ((fil[6] == 1) && (info[2] == 1))){
c_res++;
if((c_res >= index) && (c_res < index+5)){
llis = llis + "\n";
for(var j = 0; j < fil.length; j++){
if(j > 0){
llis = llis + "^";
}
llis = llis + fil[j];
}
}
}
c_full--;
}
}
llis = c_res + llis;
return llis
}
Finalment, la funció doPost és la que s'executa quan es rep una ordre POST des de l'aplicació. La funció rep un conjunt de paràmetres que es corresponen amb les dades enviades des de l'AppInventor. Un dels paràmetres és l'acció que s'ha demanat a l'script i es fa una cosa o una altra segons el cas. Per a cada acció es preparen els paràmetres necessàris i es crida a la funció corresponent, entre les comentades més amunt. A més, es genera una resposta que serà retornada a l'aplicació.
function doPost(e){
var Accio = e.parameter.Accio;
if(Accio == "Generes"){
var llistat = Gener();
return ContentService.createTextOutput(llistat);
}
if(Accio == "Modif"){
var shh = SpreadsheetApp.openById(ssId).getSheetByName("Llistat"); // Agafem el full
var rang = shh.getLastRow(); // Índex de la darrera filera
var cont = shh.getDataRange().getValues();
var camp = new Array(7); // Valors per guardar a la taula
miraGenere(e.parameter.Genere);
camp[0] = e.parameter.Autor;
camp[1] = e.parameter.Titol;
camp[2] = e.parameter.Genere;
camp[3] = e.parameter.Editorial;
camp[4] = e.parameter.Any;
camp[5] = e.parameter.Esborrat;
camp[6] = e.parameter.Comentaris;
var valu = new Array(1); // Matriu de dades a escriure
valu[0] = camp; // Converteix el vector en una matriu d'una filera i dues columnes
var trobat = 0;
var pos = 1;
while((trobat == 0) && (pos < rang)){
var filact = cont[pos]; // Agafem la filera
if(filact[0] == e.parameter.Id){
trobat = 1;
}
pos++;
}
var resposta = 'Hi ha hagut un problema';
if(trobat == 1){
var rangeVal = shh.getRange(pos, 2, 1, 7);
rangeVal.setValues(valu); // Guarda els valors a les caselles, substituïnt els anteriors
resposta = 'El llibre "' + camp[1] + '" ha estat modificat';
}
return ContentService.createTextOutput(resposta);
}
if(Accio == "Afegir"){
var sh = SpreadsheetApp.openById(ssId).getSheetByName("Llistat"); // Agafem el full
var rang = sh.getLastRow(); // Índex de la darrera filera
var dades = sh.getDataRange().getValues();
var filera = dades[rang - 1]; // Agafem la darrera filera
var IdMax = filera[0]; // Màxim identificador, el que hi ha a la darrera filera
var camps = new Array(8); // Valors per guardar a la taula
miraGenere(e.parameter.Genere);
camps[0] = IdMax + 1;
camps[1] = e.parameter.Autor;
camps[2] = e.parameter.Titol;
camps[3] = e.parameter.Genere;
camps[4] = e.parameter.Editorial;
camps[5] = e.parameter.Any;
camps[6] = e.parameter.Esborrat;
camps[7] = e.parameter.Comentaris;
sh.appendRow(camps);
var resposta = 'El llibre "' + camps[2] + '" ha estat afegit';
return ContentService.createTextOutput(resposta);
}
if(Accio == "Cercar"){
var dades = new Array(4);
dades[0] = e.parameter.Autor;
dades[1] = e.parameter.Titol;
dades[2] = e.parameter.Index;
dades[3] = e.parameter.Esborrats;
var respo = Cerca(dades);
return ContentService.createTextOutput(respo);
}
if(Accio == "Llista"){
var dades = new Array(4);
dades[0] = e.parameter.Sentit;
dades[1] = e.parameter.Index;
dades[2] = e.parameter.Esborrats;
var respo = Llista(dades);
return ContentService.createTextOutput(respo);
}
var resultat = "Acció incorrecta" + "\n";
return ContentService.createTextOutput(resultat);
}
Ara ja podem passar a l'AppInventor.

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.