Skip to content

Instantly share code, notes, and snippets.

@denoww
Last active October 11, 2025 11:36
Show Gist options
  • Save denoww/dc0c6719925ab6575f6edd55302c4d4c to your computer and use it in GitHub Desktop.
Save denoww/dc0c6719925ab6575f6edd55302c4d4c to your computer and use it in GitHub Desktop.
loja_android_config.js
////////////////////////////////////////////////////////////////////////////////
// How to use
// 1 - Vá na página conteudo do app -
// 2 - Abra console do chrome e cole esse script inteiro
// 2 - execute o comando abaixo em seguida arrumando os parametros
////////////////////////////////////////////////////////////////////////////////
opt = {
'nomeApp': 'INFE Gestão de Condomínios',
'email': '[email protected]',
'telefone': '+551122936440',
'site': 'http://infe.com.br/',
'contatoUrl': 'https://www.seucondominio.com.br/contato?no_layout=true',
'descricaoBreve': 'Gestão financeira, administrativa e segurança eletrônica para condomínio',
};
/////////////////////////////
// Rode esse primeiro
// await rodarCriarApp(opt);
/////////////////////////////
/////////////////////////////
// Depois todos abaixo
/////////////////////////////
// await rodarPresencaLoja(opt);
// await rodarCriarVersao(opt);
// await rodarConteudoApp(opt);
/////////////////////////////
// Depois esse isolado
/////////////////////////////
// Nesse aqui você precisa entrar manualmente na pagina de "Permissões de acesso a fotos e vídeos"
// await rodarPermissaoFotos(opt);
// ////////////////////////////////////////////////////////////////////////////////
(function () {
function normalizar(txt) {
return (txt || "")
.toString()
.normalize("NFD")
.replace(/\p{Diacritic}/gu, "")
.trim()
.toLowerCase();
}
function isVisivel(el) {
return !!el && (el.offsetWidth || el.offsetHeight || el.getClientRects().length);
}
function isHabilitado(botao) {
const aria = botao.getAttribute('aria-disabled');
return !botao.disabled && aria !== 'true';
}
window.clickElemento = function(el) {
if(el == undefined || el == null){
console.log("clickElemento não encontrou elemento para clicar")
return;
}
// Dá um scroll pra garantir que não esteja coberto
try { el.scrollIntoView({ block: 'center' }); } catch {}
// Dispara eventos “reais” (alguns frameworks exigem)
el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
el.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
el.click();
}
function clicarBotaoDaSecao(secao, titulo) {
if (!secao) return false;
// 1) Tenta o botão com aria-label que contém o título (mais preciso)
let botao = secao.querySelector(`button[aria-label*="${titulo}"]`);
// 2) Se não achar, cai para o botão com label visual "Iniciar declaração" dentro da secão
if (!botao) {
botao = Array.from(secao.querySelectorAll('button'))
.find(b => (b.textContent || '').trim().toLowerCase() === 'iniciar declaração');
}
if (botao && isVisivel(botao)) {
botao.scrollIntoView({ block: 'center', behavior: 'instant' });
botao.click();
return true;
}
return false;
}
window.encontrarBarraDoBotao = function() {
// Escopo preferencial
return document.querySelector('publishing-bottom-bar, form-bottom-bar, [debug-id="publishing-bottom-bar"]')
|| document.querySelector('bottom-bar-base, [debug-id="bottom-bar"]')
|| document;
}
window.execEncontrarBotaoByDebugId = function (escopo, debugId) {
const candidatos = Array.from(
// escopo.querySelectorAll('button[debug-id="'+debugId+'"]')
escopo.querySelectorAll('[debug-id="'+debugId+'"]')
);
// 1) Primeiro tenta “main-button” com label “Salvar”
let btn = candidatos.find(b =>
b.matches('button[debug-id="'+debugId+'"]') &&
normalizar(b.textContent) === 'salvar'
);
if (btn && isVisivel(btn) && isHabilitado(btn)) return btn;
// 2) Qualquer botão visível com label “Salvar”
btn = candidatos.find(b =>
isVisivel(b) && isHabilitado(b)
);
if (btn) return btn;
// 3) Fallback: procura span de label dentro de botões
const spans = Array.from(escopo.querySelectorAll('button .mdc-button__label, button span'));
const spanSalvar = spans.find(s => normalizar(s.textContent) === 'salvar');
if (spanSalvar) {
const b = spanSalvar.closest('button');
if (b && isVisivel(b) && isHabilitado(b)) return b;
}
return null;
}
function encontrarSecaoPorTitulo(titulo) {
const alvo = normalizar(titulo);
const secoes = document.querySelectorAll('console-section[debug-id="policy-summary"], console-section');
for (const secao of secoes) {
// pega o heading dessa secão
const heading = secao.querySelector('[debug-id="header-text"] .simple-html-contents');
if (!heading) continue;
const hTxt = normalizar(heading.textContent);
if (hTxt === alvo && isVisivel(secao)) {
return secao;
}
}
return null;
}
window.getInputFromBoxInput = function(box) {
if (!box) return;
// Se o próprio box já for um input, usa ele diretamente
let input = box.tagName === 'INPUT' || box.tagName === 'TEXTAREA'
? box
: box.querySelector('input, textarea');
return input;
};
window.setTextoNoInputNoBoxInput = function(box, txt) {
let input = getInputFromBoxInput(box);
if (input) {
setTextoNoInput(input, txt);
}
}
window.setTextoNoInputByDebugId = function(cod, txt) {
let box = getElByDebugId(cod);
setTextoNoInputNoBoxInput(box, txt);
};
window.setTextoNoInputByArialLabelTxt = function(cod, txt) {
let box = getElByArialLabelTxt(cod);
setTextoNoInputNoBoxInput(box, txt);
};
window.clicarBotaoByDebugId = function(debugId){
let bot = encontrarBotaoByDebugId(debugId);
clickElemento(bot)
}
window.setTextoNoInput = function(input, txt) {
if (txt === undefined || txt === null) return; // não faz nada
input.value = txt;
input.dispatchEvent(new Event('input', { bubbles: true }));
input.dispatchEvent(new Event('change', { bubbles: true }));
};
window.clicarMenu = function(txtArial) {
try {
const el = getElByArialLabelTxt(txtArial);
if (!el) {
console.warn(`Elemento com aria-label contendo "${txtArial}" não encontrado.`);
return;
}
const link = el.querySelector('a');
if (!link) {
console.warn(`Nenhum <a> encontrado dentro do elemento "${txtArial}".`);
return;
}
if (typeof clickElemento === 'function') {
clickElemento(link);
} else {
console.warn('Função clickElemento não definida.');
}
} catch (e) {
console.error('Erro ao executar clicarMenu:', e);
}
}
window.getElByDebugId = function(debugId) {
return document.querySelector('[debug-id="'+debugId+'"');
}
window.getElByArialLabelTxt = function(txt) {
// return document.querySelector('[aria-label="'+txt+'"');
return Array.from(
document.querySelectorAll('[aria-label="'+txt+'"')
).filter(el => el.offsetParent !== null)[0];
}
// window.setTextoNoInputByArialLabel = function(arialLabelCode, txt){
// let input = getElByArialLabelTxt(arialLabelCode)
// setTextoNoInput(input, txt)
// }
window.voltarPaginaConteudoApp = function () {
// procura no body o botão com o aria-label específico
// const botao = document.querySelector('a[aria-label="Voltar para Conteúdo do app"');
const botao = getElByArialLabelTxt("Voltar para Conteúdo do app")
if (!botao || !isVisivel(botao)) {
console.warn('⚠️ Botão "Voltar para Conteúdo do app" não encontrado ou não visível.');
return false;
}
clickElemento(botao);
console.log('🔙 Clique executado no botão "Voltar para Conteúdo do app".');
return true;
};
window.encontrarBotaoByDebugId = function(debugId){
const barra = encontrarBarraDoBotao();
return execEncontrarBotaoByDebugId(barra, debugId) || execEncontrarBotaoByDebugId(document, debugId);
}
// Função pública
window.clicarBotaoProximo = function () {
const ids = ['button-next', 'next-button'];
for (const id of ids) {
if (encontrarBotaoByDebugId(id)) {
return clicarBotaoByDebugId(id);
}
}
};
window.clicarBotaoSalvar = function () {
clicarBotaoByDebugId('main-button');
};
window.clicarBotaoSalvarRascunho = function () {
clicarBotaoByDebugId('save-draft-button');
};
window.salvarEVoltarPaginaConteudoApp = async function (opt) {
await sleep(5000);
clicarBotaoSalvar();
await sleep(5000);
voltarPaginaConteudoApp();
await sleep(5000);
};
// Função pública
window.abrirSecaoConteudoApp = function (titulo) {
const secao = encontrarSecaoPorTitulo(titulo);
if (!secao) {
console.warn(`Seção não encontrada para título: "${titulo}"`);
return false;
}
const ok = clicarBotaoDaSecao(secao, titulo);
if (!ok) {
console.warn(`Botão não encontrado/visível na seção: "${titulo}"`);
}
return ok;
};
window.clicarNosTextos = function(textos){
setTimeout(function() {
var elements = document.querySelectorAll('*');
elements.forEach(function(element) {
// console.log(element.textContent)
textos.forEach(function(texto) {
try {
if (element.textContent.match(texto, "i")) {
element.click()
}
} catch {
}
});
});
}, 1000);
}
window.marcarCheckBox = function(textos){
clicarNosTextos(textos)
}
window.sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
})();
///////////////////////////////////////////
///////////////////////////////////////////
// rodarConteudoApp
///////////////////////////////////////////
///////////////////////////////////////////
async function conteudoAnuncios(opt) {
let nomeSecao = 'Anúncios'
abrirSecaoConteudoApp(nomeSecao);
await sleep(1000);
marcarCheckBox([/Não, meu app não tem anúncios/]);
await salvarEVoltarPaginaConteudoApp();
console.log('✅ Seção '+nomeSecao+' concluída');
}
async function conteudoAppsGovernamentais(opt) {
let nomeSecao = 'Apps governamentais'
abrirSecaoConteudoApp(nomeSecao);
await sleep(1000);
marcarCheckBox([/Não/]);
await salvarEVoltarPaginaConteudoApp();
console.log('✅ Seção '+nomeSecao+' concluída');
}
async function conteudoIdPublicidade(opt) {
let nomeSecao = 'ID de publicidade'
abrirSecaoConteudoApp(nomeSecao);
await sleep(1000);
marcarCheckBox([/Sim/]);
await sleep(800);
marcarCheckBox([/Usados para coletar dados sobre a forma como os usuários utilizam o app ou o desemp/]);
await salvarEVoltarPaginaConteudoApp();
console.log('✅ Seção '+nomeSecao+' concluída');
}
async function conteudoRecursosFinanceiros(opt) {
let nomeSecao = 'Recursos financeiros'
abrirSecaoConteudoApp(nomeSecao);
await sleep(3000);
marcarCheckBox([/Meu app não oferece recursos financeiros/]);
await sleep(3000);
clicarBotaoProximo();
await salvarEVoltarPaginaConteudoApp();
console.log('✅ Seção '+nomeSecao+' concluída');
}
async function conteudoSaude(opt) {
let nomeSecao = 'Apps de saúde'
abrirSecaoConteudoApp(nomeSecao);
await sleep(1000);
marcarCheckBox([/Meu app não tem recursos de saúde/]);
await salvarEVoltarPaginaConteudoApp();
console.log('✅ Seção '+nomeSecao+' concluída');
}
async function conteudoPoliticaPrivacidade(opt) {
let nomeSecao = 'Política de Privacidade'
abrirSecaoConteudoApp(nomeSecao);
await sleep(4000);
let nomeAppEncoded = encodeURIComponent(opt.nomeApp);
let url = `https://www.seucondominio.com.br/politica-privacidade?no_layout=true&appName=${nomeAppEncoded}`
setTextoNoInputByDebugId('privacy-policy-url-input', url)
await salvarEVoltarPaginaConteudoApp();
console.log('✅ Seção '+nomeSecao+' concluída');
}
async function conteudoAcessoApps(opt) {
let nomeSecao = 'Acesso de apps'
abrirSecaoConteudoApp(nomeSecao);
await sleep(1000);
marcarCheckBox([/Todas ou algumas funcionalidades do app são restritas./]);
await sleep(1000);
clicarNosTextos([/Adicionar instruções/])
await sleep(2000);
setTextoNoInputByDebugId('name-input', "User")
setTextoNoInputByDebugId('username-input', '[email protected]')
setTextoNoInputByDebugId('password-input', 'testestaging')
marcarCheckBox([/Nenhuma outra informação é necessária para acessar meu app/]);
await sleep(1000);
clicarBotaoByDebugId('apply-button');
await salvarEVoltarPaginaConteudoApp();
console.log('✅ Seção '+nomeSecao+' concluída');
}
async function conteudoAppsClassificacaoConteudo(opt) {
let nomeSecao = 'Classificações de conteúdo'
abrirSecaoConteudoApp(nomeSecao);
await sleep(2000);
let botIniciar = document.querySelector('[debug-id="get-started-start-button"]') || document.querySelector('[debug-id="edit-button"]')
clickElemento(botIniciar);
await sleep(4000);
setTextoNoInputByDebugId('email-address-input', opt.email)
await sleep(1000);
marcarCheckBox([
/Todos os Outros Tipos de Aplicações/,
/Concordo com os Termos de Uso/
]);
await sleep(4000);
clicarBotaoProximo();
await sleep(1000);
marcarCheckBox([/Não/]);
// marcarCheckBox([/Não/]);
// await sleep(1000);
// marcarCheckBox([/Não/]);
await sleep(5000);
clicarBotaoSalvar()
await sleep(5000);
clicarBotaoProximo();
await salvarEVoltarPaginaConteudoApp();
console.log('✅ Seção '+nomeSecao+' concluída');
}
async function conteudoPublicoAlvo(opt) {
let nomeSecao = 'Público-alvo e conteúdo'
abrirSecaoConteudoApp(nomeSecao);
await sleep(4000);
marcarCheckBox([
/13 a 15/,
/16 a 17/,
/Maiores de 18 anos/,
]);
await sleep(3000);
clicarBotaoProximo();
await salvarEVoltarPaginaConteudoApp();
console.log('✅ Seção '+nomeSecao+' concluída');
}
async function conteudoSegurancaDados(opt) {
async function execPagina1(){
marcarCheckBox([/Sim/]);
await sleep(1000);
marcarCheckBox([/Sim/]);
await sleep(1000);
marcarCheckBox([/Nome de usuário e senha/]);
await sleep(1000);
setTextoNoInputByDebugId('account-deletion-url', opt.contatoUrl)
marcarCheckBox([/Sim/]);
await sleep(1000);
setTextoNoInputByDebugId('data-deletion-url', opt.contatoUrl)
console.log("pagina 1 executada")
}
async function execPagina2(){
let accordions = Array.from(
document.querySelectorAll('[debug-id="console-section-expand-button-icon"')
).filter(el => el.offsetParent !== null);
async function abrirAccordion(number){
clickElemento(accordions[number]) // abrir accorion informações pessoas
await sleep(2000);
}
// abrirAccordion(0)
marcarCheckBox([
/Local aproximado/,
/Local exato/,
]);
await sleep(3000);
abrirAccordion(1)
marcarCheckBox([
/Nome/,
/Endereço de e-mail/,
/IDs de usuários/,
/Endereço/,
/Número de telefone/,
]);
await sleep(3000);
abrirAccordion(13)
marcarCheckBox([
/Identificadores do dispositivo e outros IDs/,
]);
await sleep(3000);
console.log("pagina 2 executada")
}
async function preencherItenDoAccordionPagina3(bot){
clickElemento(bot);
await sleep(3000);
marcarCheckBox([
/Estes dados são transmitidos do dispositivo do usuário a você /,
/Estes dados são transferidos a terceiros, tanto no próprio dispositivo do usuário quanto para fora dele/,
])
await sleep(3000);
marcarCheckBox([
/Sim, os dados coletados são processados de maneira efêmera/,
/Os usuários podem escolher se os dados são coletados/,
/Usados para funcionalidades do app, como ativação de certos recursos ou autenticação dos usuários/,
])
await sleep(3000);
clicarBotaoByDebugId('save-button');
await sleep(5000);
}
async function preencherAccordionPagina3(acc){
clickElemento(acc) // abrir accordion
await sleep(2000); // esperar aparecer os botoes
let botoesDoAccordion = Array.from(
document.querySelectorAll('[aria-label^="Abrir perguntas"]')
).filter(el => el.offsetParent !== null);
for (const bot of botoesDoAccordion) {
await preencherItenDoAccordionPagina3(bot)
}
}
async function execPagina3(){
let accordions = Array.from(
document.querySelectorAll('[debug-id="console-section-expand-button-icon"')
).filter(el => el.offsetParent !== null);
for (const accordion of accordions) {
await preencherAccordionPagina3(accordion)
// await sleep(2000);
}
console.log("pagina 3 executada")
}
let nomeSecao = 'Segurança dos dados'
abrirSecaoConteudoApp(nomeSecao);
await sleep(2000);
clicarBotaoProximo();
await sleep(2000);
await execPagina1() // pagina 1
await sleep(5000);
clicarBotaoProximo();
await sleep(4000);
await execPagina2() // pagina 2
await sleep(4000);
clicarBotaoProximo();
await sleep(2000);
await execPagina3() // pagina 3
await sleep(2000);
clicarBotaoProximo();
// salvar
await salvarEVoltarPaginaConteudoApp();
console.log('✅ Seção '+nomeSecao+' concluída');
}
async function rodarConteudoApp(opt) {
clicarMenu("Conteúdo do app")
await sleep(5000);
await conteudoAcessoApps(opt);
await conteudoIdPublicidade(opt);
await conteudoAppsGovernamentais(opt);
await conteudoAnuncios(opt);
await conteudoRecursosFinanceiros(opt);
await conteudoSaude(opt);
await conteudoPoliticaPrivacidade(opt);
await conteudoPublicoAlvo(opt);
await conteudoSegurancaDados(opt);
await conteudoAppsClassificacaoConteudo(opt);
console.log('🎉 Conteudo: Todas as seções foram preenchidas com sucesso!');
}
///////////////////////////////////////////
///////////////////////////////////////////
// rodarPresencaLoja
///////////////////////////////////////////
///////////////////////////////////////////
async function lojaConfigLoja(opt) {
async function salvarEFechar(){
await sleep(3000);
clicarBotaoSalvar();
await sleep(3000);
clickElemento(getElByArialLabelTxt('Fechar'));
}
nomeSecao = "Configurações da loja"
clicarMenu(nomeSecao)
await sleep(4000);
// editar categoria financeiro
clickElemento(getElByDebugId("edit-app-category-section-button"))
await sleep(4000);
clickElemento(document.querySelector('[debug-id="category-dropdown"] [buttondecorator]'))
await sleep(3000);
clicarNoTexto(/Finanças/)
// clickElemento(document.querySelector('[id="a819A6D5E-2259-42FD-8A37-DEC0B82F7AB8--191"]'))
await salvarEFechar();
// editar detalhes
clickElemento(getElByDebugId("edit-store-listing-section-button"))
await sleep(3000);
setTextoNoInputByDebugId('email-input', opt.email)
setTextoNoInputByDebugId('phone-input', opt.telefone)
setTextoNoInputByDebugId('website-input', opt.site)
await salvarEFechar();
console.log('✅ Seção '+nomeSecao+' concluída');
await sleep(5000);
}
async function lojaDetalhesDoApp(opt) {
nomeSecao = "Páginas Detalhes do app"
clicarMenu(nomeSecao)
await sleep(3000);
let botIniciar = document.querySelector('[essfield="editListingAction"] a') || document.querySelector('[debug-id="get-started-create-default-listing-button"]');
clickElemento(botIniciar)
await sleep(3000);
setTextoNoInputByArialLabelTxt('Nome do app', opt.nomeApp)
setTextoNoInputByArialLabelTxt('Breve descrição do app', opt.descricaoBreve)
await sleep(3000);
clicarBotaoSalvarRascunho()
await sleep(5000);
}
async function rodarPresencaLoja(opt) {
await lojaConfigLoja(opt);
await lojaDetalhesDoApp(opt);
console.log('🎉 Loja: Todas as seções foram preenchidas com sucesso!');
}
window.clicarNoTexto = function(txt){
clicarNosTextos([txt]);
}
///////////////////////////////////////////
///////////////////////////////////////////
// rodarCriarVersao
///////////////////////////////////////////
///////////////////////////////////////////
async function versaoProducao(opt) {
async function arrumarPaises(opt) {
let abaPaises = getElByArialLabelTxt('Países / regiões')
clickElemento(abaPaises);
await sleep(5000);
clicarNoTexto(/Adicionar países \/ regiões/);
// clicarNoTexto(/Editar países \/ regiões/);
await sleep(10000);
clickElemento(getElByArialLabelTxt('Selecionar todas as linhas'));
await sleep(2000);
clicarBotaoSalvar();
}
async function criarVersao(opt) {
clicarBotaoByDebugId('create-android-release-button')
await sleep(8000);
setTextoNoInputByDebugId('whats-new', "<pt-BR>\nApp para condomínios\n</pt-BR>")
setTextoNoInputByDebugId('version', "1.0")
await sleep(1000);
clicarBotaoByDebugId('save-button')
}
nomeSecao = "Produção"
clicarMenu(nomeSecao)
await sleep(5000);
await arrumarPaises(opt)
await sleep(5000);
await criarVersao(opt)
console.log('✅ Seção '+nomeSecao+' concluída');
await sleep(5000);
}
async function rodarCriarVersao(opt) {
await versaoProducao(opt);
console.log('🎉 rodarCriarVersao executada com sucesso!');
}
///////////////////////////////////////////
///////////////////////////////////////////
// rodarPermissaoFotos
///////////////////////////////////////////
///////////////////////////////////////////
async function fotosArumarPermissoes(opt) {
// nomeSecao = "Produção"
// clicarMenu(nomeSecao)
// await sleep(1000);
let txtImage = 'Permite o usuário selecionar e enviar fotos da galeria para o app (perfil, comprovantes e anexos em chamados/ocorrências). Somente itens escolhidos; sem leitura em segundo plano. Uso exclusivo dessa função; envio criptografado.'
setTextoNoInputByArialLabelTxt('Descreva como seu app usa a permissão READ_MEDIA_IMAGES', txtImage)
let txtVideo = 'Permite o usuário selecionar e enviar vídeos da galeria (registros de ocorrências/documentos audiovisuais). Apenas itens escolhidos; sem coleta em segundo plano. Uso restrito ao envio; transmissão criptografada.'
setTextoNoInputByArialLabelTxt('Descreva como seu app usa a permissão READ_MEDIA_VIDEO', txtImage)
await sleep(1000);
clicarBotaoSalvar();
// console.log('✅ Seção '+nomeSecao+' concluída');
await sleep(5000);
}
async function rodarPermissaoFotos(opt) {
await fotosArumarPermissoes(opt);
console.log('🎉 Loja: Todas as seções foram preenchidas com sucesso!');
}
///////////////////////////////////////////
///////////////////////////////////////////
// rodarCriarApp
///////////////////////////////////////////
///////////////////////////////////////////
async function appCriar(opt) {
clickElemento(document.querySelector('[debug-id="create-app-button"] a'));
await sleep(5000);
setTextoNoInputByDebugId('app-name-input', opt.nomeApp);
marcarCheckBox([
/App/,
/Grátis/,
/Confirme se o app atende às Polític/,
/Aceitar a legislação de exportação/,
]);
await sleep(2000);
let botSalvar = document.querySelector('[debug-id="create-app-button"] button')
clickElemento(botSalvar);
await sleep(20000);
}
async function rodarCriarApp(opt) {
await appCriar(opt);
console.log('🎉 rodarCriarApp executado com sucesso!');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment