html2apk 0.9.0 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,50 @@
4
4
 
5
5
  Use ele quando voce ja tem um app web, por exemplo uma pasta com `index.html`, `style.css`, `app.js` e imagens, e quer gerar um `.apk` instalavel no Android ou um `.aab` para loja.
6
6
 
7
+ ## Como contribuir sem quebrar o padrão
8
+
9
+ O html2apk agora é um projeto aberto, mas a regra mais importante para novas features é simples: antes de implementar, entenda como o código atual trabalha. Evite criar uma segunda arquitetura para resolver algo que a ponte existente já resolve.
10
+
11
+ Antes de mandar qualquer feature nova, o contribuinte precisa estudar o fluxo atual da aplicação e confirmar que a solução segue a mesma estratégia das funções existentes. Não envie código que cria atalhos, caminhos paralelos, outro padrão de bridge, outro jeito de tratar permissão ou outra forma de comunicar JavaScript com Java sem uma justificativa técnica muito clara. Primeiro adapte a ideia ao desenho que já funciona no projeto; só proponha uma abordagem nova se o padrão atual realmente não atender.
12
+
13
+ Exemplo de postura esperada: "quero colocar uma nova função no projeto; antes de escrever, vou ver como as outras funções foram colocadas, como o código lida com elas, qual é o fluxo completo e por que esse fluxo existe". Essa investigação vem antes da implementação. Ela mostra onde a nova função deve nascer, como deve normalizar argumentos, qual action deve chamar, como o Java deve responder, onde documentar e como testar. É esse cuidado que permite criar algo novo sem quebrar a aplicação.
14
+
15
+ As funções interpretadas seguem um caminho bem definido:
16
+
17
+ ```text
18
+ JavaScript do app
19
+ -> função global em português
20
+ -> aliases quando fizer sentido
21
+ -> normalização de argumentos
22
+ -> cordova.exec(action)
23
+ -> dispatcher Java
24
+ -> permissão/thread/subsistema Android
25
+ -> CallbackContext
26
+ -> Promise no JavaScript
27
+ ```
28
+
29
+ Quando uma feature nova entra, ela deve atravessar esse caminho em vez de criar uma forma paralela de comunicação. Isso evita duplicação, bugs difíceis de testar e diferença de comportamento entre o early bridge, o plugin Cordova, a interface desktop e o app final.
30
+
31
+ Checklist antes de abrir PR ou commit:
32
+
33
+ - Entenda a arquitetura existente antes de alterar arquivos. Se ainda não sabe por onde uma função interpretada nasce, passa pela bridge e chega ao Java, pare e leia o código antes de implementar.
34
+ - Confirme que a feature nova não está criando conflito com APIs, helpers, normalizadores, actions ou eventos que já existem.
35
+ - Evite estratégias novas desnecessárias. Se uma função parecida já usa `cordova.exec`, dispatcher Java, `CallbackContext`, permissão pendente ou evento `CustomEvent`, a nova feature deve seguir esse caminho.
36
+ - Leia funções parecidas antes de escrever código novo. Se for arquivo, veja `salvarArquivo`, `baixarArquivo` e `FileProvider`. Se for permissão, veja câmera, microfone, notificação e localização. Se for evento, veja `aoEvento`, notificação e compartilhamento recebido.
37
+ - Mantenha nomes em PT-BR como API principal e aliases em inglês apenas quando combinarem com o padrão existente.
38
+ - Adicione a função no early bridge e no plugin JS com a mesma assinatura pública.
39
+ - Reuse normalizadores e helpers existentes; não trate payload com string solta se o projeto já usa objeto estruturado.
40
+ - No Java, entre pelo dispatcher de `action` existente e retorne JSON consistente.
41
+ - Se precisar de permissão runtime, preserve callback pendente, busy state e abertura de configurações quando o Android exigir.
42
+ - Se tocar arquivos, preserve sanitização de nome, armazenamento interno, MediaStore quando aplicável e FileProvider.
43
+ - Se tocar operações longas, use a thread adequada e não trave a WebView.
44
+ - Atualize `plugin.xml` apenas com permissões, intent filters ou dependências realmente necessárias.
45
+ - Atualize runtime console, aba "Códigos interpretados", laboratório USB, README/SOBRE quando a feature for pública.
46
+ - Adicione ou ajuste testes em `test/config.test.js` para provar que JS, Java, UI e docs continuam alinhados.
47
+ - Rode `npm test` antes de enviar.
48
+
49
+ O objetivo não é impedir criatividade; é proteger o comportamento previsível da ferramenta. Uma contribuição boa parece nativa no projeto: usa os mesmos nomes, passa pelos mesmos pontos, retorna no mesmo formato e respeita as mesmas fronteiras entre build, desktop, bridge JS e Java Android.
50
+
7
51
  ## O Mais Importante
8
52
 
9
53
  Na pratica, voce vai usar estes comandos:
@@ -303,6 +347,13 @@ O icone flutuante usa a permissao especial `SYSTEM_ALERT_WINDOW`. A bridge nativ
303
347
 
304
348
  Mesmo com a permissao declarada no manifesto, o usuario ainda precisa liberar manualmente nas configuracoes do Android. Depois de liberar, volte ao app e chame `iniciarIconeFlutuante()` novamente.
305
349
 
350
+ O icone tambem aceita opacidade:
351
+
352
+ ```js
353
+ await iniciarIconeFlutuante({ opacidade: 0.85 });
354
+ await definirOpacidadeIconeFlutuante(0.55);
355
+ ```
356
+
306
357
  ### Tema Automatico Do APK
307
358
 
308
359
  Use `themeMode: "auto"` ou `theme: "auto"` para o APK adaptar as barras nativas do Android a cor que esta visivel na tela. O html2apk observa a tela do WebView e ajusta status bar/navigation bar em tempo real.
@@ -386,7 +437,7 @@ Retorno:
386
437
 
387
438
  ## Bridge Nativa
388
439
 
389
- A v0.1 instala um plugin Cordova local com uma API global simples para recursos Android. Todas as funcoes retornam `Promise`, exceto os ouvintes `aoEvento`/atalhos, que retornam uma funcao para cancelar a escuta.
440
+ A v0.1 instala um plugin Cordova local com uma API global simples para recursos Android. Todas as funções retornam `Promise`, exceto os ouvintes `aoEvento`/atalhos, que retornam uma função para cancelar a escuta.
390
441
 
391
442
  O html2apk injeta `html2apk-early-bridge.js` e `cordova.js` automaticamente no HTML inicial do APK. A bridge inicial cria as funcoes interpretadas antes dos scripts do seu projeto; se uma funcao nativa for chamada antes do `deviceready`, ela espera o Android ficar pronto antes de executar.
392
443
 
@@ -417,6 +468,8 @@ Exemplos de aliases:
417
468
  | `escanearQRCode()` | `scanQRCode()` |
418
469
  | `escolherArquivo()` | `pickFile()` |
419
470
  | `escolherImagem()` | `pickImage()` |
471
+ | `escolherImagens()` | `pickImages()` |
472
+ | `escolherPasta()` | `pickFolder()` |
420
473
  | `salvarArquivo()` | `saveFile()` |
421
474
  | `lerArquivo()` | `readFile()` |
422
475
  | `listarArquivos()` | `listFiles()` |
@@ -429,7 +482,28 @@ Exemplos de aliases:
429
482
  | `definirPapelParede()` | `setWallpaper()` |
430
483
  | `infoPapelParede()` | `wallpaperInfo()` |
431
484
  | `abrirConfiguracaoPapelParede()` | `openWallpaperSettings()` |
485
+ | `capturarTela()` / `tirarPrint()` | `captureScreen()` / `takeScreenshot()` |
432
486
  | `compartilhar()` | `share()` |
487
+ | `compartilharApp()` / `share_me()` | `shareApp()` |
488
+ | `aoReceberCompartilhamento()` | `onShareReceived()` |
489
+ | `obterCompartilhamentoInicial()` | `getInitialShare()` |
490
+ | `procurarBT()` | `scanBluetooth()` |
491
+ | `conectarBT()` | `connectBluetooth()` |
492
+ | `enviarBT()` | `sendBluetooth()` |
493
+ | `aoConectarBT()` | `onBluetoothConnect()` |
494
+ | `aoReceberDadosBT()` | `onBluetoothData()` |
495
+ | `aoDarErroBT()` | `onBluetoothError()` |
496
+ | `procurarWiFi()` | `scanWiFi()` |
497
+ | `conectarWiFi()` | `connectWiFi()` |
498
+ | `enviarWiFi()` | `sendWiFi()` |
499
+ | `aoConectarWiFi()` | `onWiFiConnect()` |
500
+ | `aoReceberDadosWiFi()` | `onWiFiData()` |
501
+ | `aoDarErroWiFi()` | `onWiFiError()` |
502
+ | `ocr()` | `recognizeText()` / `textFromImage()` |
503
+ | `falar()` | `speak()` / `textToSpeech()` |
504
+ | `pararFala()` | `stopSpeaking()` |
505
+ | `ouvir()` | `recognizeSpeech()` / `speechToText()` |
506
+ | `aguardar()` | `loading()` |
433
507
  | `copiarTexto()` | `copyText()` |
434
508
  | `lerTextoCopiado()` | `readText()` |
435
509
  | `abrirNoApp()` | `openInApp()` |
@@ -438,22 +512,47 @@ Exemplos de aliases:
438
512
  | `manterTelaLigada()` | `keepScreenOn()` |
439
513
  | `brilhoTela()` | `setScreenBrightness()` |
440
514
  | `definirCorTema()` | `setThemeColor()` |
515
+ | `volumeAtual()` | `getVolume()` |
516
+ | `definirVolume()` | `setVolume()` |
517
+ | `aumentarVolume()` | `increaseVolume()` |
518
+ | `diminuirVolume()` | `decreaseVolume()` |
441
519
  | `infoMemoria()` | `memoryInfo()` |
442
520
  | `infoArmazenamento()` | `storageInfo()` |
443
521
  | `infoDesempenho()` | `performanceInfo()` |
444
522
  | `appsAbertos()` | `openAppsMemory()` |
523
+ | `configurarIconeFlutuante()` | `configureFloatingIcon()` |
524
+ | `definirOpacidadeIconeFlutuante()` | `setFloatingIconOpacity()` |
525
+ | `minimizarApp()` | `minimizeApp()` |
526
+ | `fecharApp()` | `closeApp()` / `exitApp()` |
445
527
  | `obterLocalizacao()` | `getLocation()` |
446
528
  | `acompanharLocalizacao()` | `watchLocation()` |
447
529
  | `pararLocalizacao()` | `stopLocationWatch()` |
448
530
  | `autenticarBiometria()` | `authenticateBiometric()` |
531
+ | `solicitarBloqueio()` | `requestDeviceLock()` |
532
+ | `solicitarSegundoPlano()` | `requestBackgroundExecution()` |
533
+ | `configurarInicioAutomatico()` | `setAutoStartOnBoot()` |
449
534
  | `salvarSeguro()` | `saveSecure()` |
450
535
  | `lerSeguro()` | `readSecure()` |
451
536
  | `removerSeguro()` | `deleteSecure()` |
452
537
  | `aoEvento()` | `onEvent()` |
453
538
  | `aoMinimizar()` | `onMinimize()` |
539
+ | `aoConectarUSB()` | `onUSBConnect()` |
540
+ | `aoDesconectarUSB()` | `onUSBDisconnect()` |
541
+ | `aoConectarFone()` | `onHeadphoneConnect()` |
542
+ | `aoDesconectarFone()` | `onHeadphoneDisconnect()` |
543
+ | `aoMudarVolume()` | `onVolumeChange()` |
544
+ | `aoAbrirTeclado()` | `onKeyboardOpen()` |
545
+ | `aoFecharTeclado()` | `onKeyboardClose()` |
546
+ | `aoSacudirCelular()` | `onPhoneShake()` |
547
+ | `aoVirarCelularParaBaixo()` | `onPhoneFaceDown()` |
548
+ | `aoAproximarObjeto()` | `onProximityNear()` |
549
+ | `aoTirarPrint()` | `onScreenshot()` |
550
+ | `aoMudarOrientacao()` | `onOrientationChange()` |
551
+ | `aoNFC()` | `onNFC()` |
552
+ | `aoReceberNotificacao()` | `onNotificationReceived()` |
454
553
  | `obterLinkInicial()` | `getInitialLink()` |
455
554
 
456
- Os eventos tambem aceitam aliases em ingles em `onEvent()`: `app:ready`, `app:background`, `app:resumed`, `back:button`, `link:opened`, `network:changed`, `battery:changed`, `location:changed`, `notification:received` e `notification:clicked`.
555
+ Os eventos tambem aceitam aliases em ingles em `onEvent()`: `app:ready`, `app:background`, `app:resumed`, `back:button`, `link:opened`, `share:received`, `sharing:received`, `bluetooth:connected`, `bluetooth:data`, `bluetooth:error`, `wifi:connected`, `wifi:data`, `wifi:error`, `usb:connected`, `usb:disconnected`, `headphone:connected`, `headphone:disconnected`, `volume:changed`, `keyboard:opened`, `keyboard:closed`, `phone:shaken`, `phone:faceDown`, `proximity:near`, `screenshot:taken`, `orientation:changed`, `nfc:received`, `network:changed`, `battery:changed`, `location:changed`, `notification:received` e `notification:clicked`.
457
556
 
458
557
  Como tratar retornos:
459
558
 
@@ -470,6 +569,7 @@ No seu JavaScript do app:
470
569
  ```js
471
570
  toast("Mensagem");
472
571
  vibrar(250);
572
+ await aguardar(5000);
473
573
 
474
574
  await notificar({
475
575
  titulo: "Pedido aprovado",
@@ -532,6 +632,14 @@ fullscreen(true);
532
632
 
533
633
  `notificar()` nao obriga clique, botao nem funcao. So `titulo` e `texto` ja geram uma notificacao normal. `aoClicar`, `acoes`/`actions` e `open` sao opcionais.
534
634
 
635
+ `aguardar(ms)` e `loading(ms)` pausam o fluxo com Promise, sem travar a WebView:
636
+
637
+ ```js
638
+ await toast("Comecando");
639
+ await aguardar(5000);
640
+ await toast("Continuando");
641
+ ```
642
+
535
643
  `agendarNotificacao()` agenda uma notificacao. Se voce passar um array para ela, ou usar `agendarNotificacoes()`, o html2apk agenda varias em sequencia. Cada item recebe `id` automatico se voce nao informar um.
536
644
 
537
645
  Em `aoClicar`, voce pode passar uma funcao diretamente:
@@ -636,10 +744,11 @@ Use OneSignal para pushes enviados remotamente pelo painel/API do OneSignal. Use
636
744
  Arquivos, galeria e compartilhamento:
637
745
 
638
746
  ```js
639
- const imagem = await escolherImagem();
640
- const imagens = await escolherImagens({ multiplo: true });
747
+ const imagem = await escolherImagem(); // Retorna: { uri, nome, tamanho, mimeType }
748
+ const imagens = await escolherImagens({ multiplas: true }); // Array de objetos
641
749
  const pdf = await escolherArquivo({ tipos: ["application/pdf"] });
642
750
  const arquivos = await escolherArquivos({ multiplo: true });
751
+ const pasta = await escolherPasta(); // Retorna: { uri, nome, treeUri }
643
752
 
644
753
  await salvarArquivo({
645
754
  nome: "relatorio.txt",
@@ -647,9 +756,75 @@ await salvarArquivo({
647
756
  conteudo: "Conteudo salvo pelo app"
648
757
  });
649
758
 
650
- await compartilhar({ texto: "Veja isso", url: "https://exemplo.com" });
759
+ await compartilhar({
760
+ titulo: "Material",
761
+ texto: "Veja isso",
762
+ url: "https://exemplo.com",
763
+ arquivo: imagem
764
+ });
765
+
766
+ aoReceberCompartilhamento((dados) => {
767
+ console.log("Compartilhamento recebido", dados.tipo, dados.uri || dados.texto);
768
+ });
769
+
770
+ const texto = await ocr(imagem);
771
+ console.log(texto.texto); // Retorna: { texto, blocos: [...] }
772
+
773
+ await falar("Ola mundo", { idioma: "pt-BR", velocidade: 1 });
774
+ const voz = await ouvir({ idioma: "pt-BR" });
775
+ console.log(voz.texto); // Retorna: { texto, error }
776
+
777
+ aoConectarBT((dispositivo) => {
778
+ console.log("Bluetooth conectado", dispositivo.nome);
779
+ });
780
+
781
+ aoReceberDadosBT((dados) => {
782
+ console.log("Dados Bluetooth", dados);
783
+ });
784
+
785
+ aoDarErroBT((erro) => {
786
+ console.log("Erro Bluetooth", erro.mensagem || erro.message);
787
+ });
788
+
789
+ const dispositivos = await procurarBT(); // Retorna: [{ id, nome, host }, ...]
790
+ if (dispositivos[0]) {
791
+ await conectarBT(dispositivos[0].id);
792
+ await enviarBT({ mensagem: "Ola por Bluetooth" });
793
+ }
794
+
795
+ aoConectarWiFi((dispositivo) => {
796
+ console.log("Wi-Fi conectado", dispositivo.nome || dispositivo.host);
797
+ });
798
+
799
+ aoReceberDadosWiFi((dados) => {
800
+ console.log("Dados Wi-Fi", dados);
801
+ });
802
+
803
+ aoDarErroWiFi((erro) => {
804
+ console.log("Erro Wi-Fi", erro.mensagem || erro.message);
805
+ });
806
+
807
+ const dispositivosWifi = await procurarWiFi(); // Retorna: [{ id, nome, host, porta }, ...]
808
+ if (dispositivosWifi[0]) {
809
+ await conectarWiFi(dispositivosWifi[0].id);
810
+ await enviarWiFi({ mensagem: "Ola por Wi-Fi" });
811
+ }
812
+
813
+ await share_me(); // compartilha o APK do proprio app aberto
651
814
  ```
652
815
 
816
+ `escolherImagem()` e `escolherImagens()` usam o Android Photo Picker no Android 13+ e caem automaticamente para o Storage Access Framework em Android antigo. Quando o Photo Picker esta disponivel, o html2apk nao solicita permissao ampla de armazenamento. O retorno segue o mesmo formato dos seletores: `{ uri, nome, mimeType, tamanho }`.
817
+
818
+ `compartilhar()` aceita texto, link, imagem, video, PDF, arquivo salvo pelo app, URI `content://` e lista de arquivos em `arquivo`/`arquivos`. O retorno confirma a abertura do share sheet com `{ ok: true }`.
819
+
820
+ Apps gerados tambem entram no menu Compartilhar do Android para `text/plain`, `image/*`, `video/*`, `application/pdf` e `*/*`. Use `obterCompartilhamentoInicial()` no boot se o app foi aberto por compartilhamento, e `aoReceberCompartilhamento()` para receber novos intents enquanto ele ja esta aberto.
821
+
822
+ `ocr()` usa ML Kit local para reconhecimento de texto em imagens. O processamento fica offline no aparelho. `falar()` usa o TextToSpeech do Android e `ouvir()` usa o reconhecedor de voz do sistema; ambos aceitam `idioma: "pt-BR"` ou `idioma: "auto"`.
823
+
824
+ Bluetooth usa RFCOMM classico entre apps html2apk. O aparelho que vai receber registra `aoConectarBT()`, `aoReceberDadosBT()` e, se quiser tratar falhas, `aoDarErroBT()`; isso inicia o servidor interno. O outro chama `procurarBT()`, escolhe um `id`, chama `conectarBT(id)` e envia JSON com `enviarBT(objeto)`. Para aparecer na busca, o aparelho precisa estar pareado ou visivel nas configuracoes Bluetooth do Android.
825
+
826
+ Wi-Fi local usa descoberta NSD e socket TCP entre apps html2apk na mesma rede ou hotspot. O aparelho que vai receber registra `aoConectarWiFi()`, `aoReceberDadosWiFi()` e `aoDarErroWiFi()`; isso inicia o servidor interno e anuncia o app na rede local. O outro chama `procurarWiFi()`, escolhe um `id`, chama `conectarWiFi(id)` e envia JSON com `enviarWiFi(objeto)`. Nao e Wi-Fi Direct: os dois aparelhos precisam estar conectados na mesma rede local, ou um deles precisa estar no hotspot do outro.
827
+
653
828
  `salvarArquivo()` tem dois modos:
654
829
 
655
830
  - `salvarArquivo({ nome, conteudo })` abre o seletor nativo para o usuario escolher onde salvar, como ja acontecia.
@@ -684,7 +859,8 @@ await baixarArquivo("https://exemplo.com/relatorio.pdf", "relatorio.pdf");
684
859
  await abrirArquivo("relatorio.pdf");
685
860
 
686
861
  await baixarBase64("foto.png", base64DaImagem, {
687
- mimeType: "image/png"
862
+ mimeType: "image/png",
863
+ galeria: true
688
864
  });
689
865
 
690
866
  const arquivo = await escolherArquivo();
@@ -695,6 +871,8 @@ if (arquivo) {
695
871
 
696
872
  Durante `baixarArquivo()`, `baixarBase64()` e `baixarArquivoLocal()`, o Android mostra uma notificacao de progresso quando a permissao `POST_NOTIFICATIONS` estiver liberada. No Android 13+, o html2apk pede essa permissao automaticamente; se o usuario negar, o download continua e o retorno vem com `notificationShown: false`.
697
873
 
874
+ Por padrao, o arquivo baixado fica no armazenamento do app para funcionar com `abrirArquivo()` e `compartilharArquivo()`. Para imagem ou video aparecer na galeria, passe `{ galeria: true }`; no Android 10+ o html2apk publica uma copia em `Pictures/html2apk` ou `Movies/html2apk` e retorna `publicUri`.
875
+
698
876
  Papel de parede:
699
877
 
700
878
  ```js
@@ -707,7 +885,7 @@ await salvarArquivo("wallpaper.jpg", foto.base64, {
707
885
 
708
886
  const resultado = await definirPapelParede("wallpaper.jpg", {
709
887
  alvo: "inicio" // "inicio", "bloqueio" ou "ambos"
710
- });
888
+ }); // Retorna: { applied, systemApplied, lockApplied, error }
711
889
 
712
890
  console.log(resultado.applied, resultado.systemApplied, resultado.lockApplied);
713
891
  ```
@@ -717,17 +895,19 @@ console.log(resultado.applied, resultado.systemApplied, resultado.lockApplied);
717
895
  Camera, QR Code, localizacao, biometria e storage seguro:
718
896
 
719
897
  ```js
720
- const foto = await tirarFoto({ base64: true });
898
+ const foto = await tirarFoto({ base64: true }); // Retorna: { base64, mimeType, uri }
721
899
 
722
- const qr = await escanearQRCode();
900
+ const qr = await escanearQRCode(); // Retorna: { text, format, cancelled }
723
901
  if (qr) {
724
902
  console.log(qr.text);
725
903
  }
726
904
 
727
905
  const local = await obterLocalizacao({ altaPrecisao: true, timeoutMs: 10000 });
906
+ // Retorna: { latitude, longitude, precisao, altitude, error }
728
907
  console.log(local.latitude, local.longitude);
729
908
 
730
- const watch = await acompanharLocalizacao({ intervaloMs: 5000 });
909
+ const watch = await acompanharLocalizacao({ intervaloMs: 5000 });
910
+ // Retorna: { watchId, error }
731
911
  const pararEvento = aoMudarLocalizacao((evento) => {
732
912
  console.log(evento.latitude, evento.longitude);
733
913
  });
@@ -738,13 +918,36 @@ pararEvento();
738
918
  const bio = await autenticarBiometria({
739
919
  titulo: "Confirmar acesso",
740
920
  descricao: "Use a biometria do aparelho"
741
- });
921
+ }); // Retorna: { authenticated, supported, canceled, message }
742
922
 
743
923
  if (bio.authenticated) {
744
924
  await salvarSeguro("token", "abc123");
745
925
  const token = await lerSeguro("token");
746
926
  await removerSeguro("token");
747
927
  }
928
+
929
+ const auth = await solicitarBloqueio({
930
+ titulo: "Acesso Restrito",
931
+ descricao: "Confirme sua senha de tela"
932
+ }); // Retorna: { autenticado, suportado, cancelado, mensagem }
933
+
934
+ if (auth.autenticado) {
935
+ // Acesso permitido
936
+ }
937
+
938
+ const bg = await solicitarSegundoPlano();
939
+ // Retorna: { ok, abriuInicioAutomatico, abriuOtimizacaoBateria }
940
+ if (bg.ok) {
941
+ toast("Obrigado por permitir rodar em segundo plano!");
942
+ }
943
+
944
+ // Para abrir o aplicativo sozinho quando o aparelho for ligado:
945
+ await configurarInicioAutomatico(true); // Retorna: { ok, enabled }
946
+
947
+ const inicio = await obterLinkInicial(); // Retorna string: "html2apk://boot" ou "https://..."
948
+ if (inicio === "html2apk://boot") {
949
+ console.log("App abriu sozinho pelo boot do aparelho");
950
+ }
748
951
  ```
749
952
 
750
953
  O retorno de arquivos tem este formato:
@@ -763,7 +966,8 @@ O retorno de arquivos tem este formato:
763
966
  Microfone:
764
967
 
765
968
  ```js
766
- const inicio = await ouvirMic();
969
+ const inicio = await ouvirMic();
970
+ // Retorna: { recording: true, settingsOpened: boolean, error: string }
767
971
  if (inicio.settingsOpened) {
768
972
  console.log("Libere Microfone nas configuracoes e tente novamente");
769
973
  } else {
@@ -853,6 +1057,27 @@ const abertos = await appsAbertos();
853
1057
 
854
1058
  Por privacidade, Android moderno pode limitar essa lista ao proprio app e alguns processos visiveis ao APK. Entao essa funcao nao deve ser tratada como gerenciador completo de tarefas do sistema.
855
1059
 
1060
+ Tela, volume e ciclo do app:
1061
+
1062
+ ```js
1063
+ const volume = await volumeAtual();
1064
+ console.log(volume.midia.atual, volume.midia.maximo);
1065
+
1066
+ await definirVolume("midia", 0.5, { mostrarUI: true });
1067
+ await aumentarVolume("midia", 1);
1068
+ await diminuirVolume("midia", 1);
1069
+
1070
+ const imagem = await capturarTela();
1071
+ document.querySelector("img.preview").src = imagem.dataUrl;
1072
+
1073
+ await minimizarApp();
1074
+
1075
+ // Use somente depois de salvar estado importante:
1076
+ // await fecharApp();
1077
+ ```
1078
+
1079
+ `capturarTela()` captura a tela do proprio APK/WebView, nao outros apps ou areas protegidas do sistema. `definirVolume()` aceita porcentagem entre 0 e 1 ou passos absolutos do stream.
1080
+
856
1081
  Eventos nativos:
857
1082
 
858
1083
  ```js
@@ -865,11 +1090,27 @@ aoEvento("botao:voltar", console.log);
865
1090
  aoEvento("link:aberto", (evento) => console.log(evento.url));
866
1091
  aoEvento("rede:mudou", console.log);
867
1092
  aoEvento("bateria:mudou", console.log);
1093
+ aoConectarUSB((dados) => console.log("USB conectado", dados));
1094
+ aoDesconectarUSB(() => console.log("USB desconectado"));
1095
+ aoReceberNotificacao((dados) => console.log("Notificação recebida", dados));
868
1096
  aoEvento("notificacao:clicada", console.log);
1097
+ aoConectarFone((dados) => console.log("Fone conectado", dados.dispositivo));
1098
+ aoDesconectarFone(() => console.log("Fone desconectado"));
1099
+ aoMudarVolume((dados) => console.log("Volume de mídia", dados.midia.atual));
1100
+ aoAbrirTeclado((dados) => console.log("Teclado abriu", dados.alturaTeclado));
1101
+ aoFecharTeclado(() => console.log("Teclado fechou"));
1102
+ aoMudarOrientacao((dados) => console.log("Orientação", dados.orientacao));
1103
+ aoSacudirCelular((dados) => console.log("Sacudiu", dados.forca));
1104
+ aoVirarCelularParaBaixo(() => console.log("Tela para baixo"));
1105
+ aoAproximarObjeto((dados) => console.log("Objeto perto", dados.distancia));
1106
+ aoTirarPrint((dados) => console.log("Print detectado", dados.uri));
1107
+ aoNFC((dados) => console.log("Tag NFC", dados.id, dados.mensagens));
869
1108
 
870
1109
  parar();
871
1110
  ```
872
1111
 
1112
+ Eventos de sensor e sistema seguem limites do Android/fabricante. `aoTirarPrint()` observa a MediaStore e depende do nome/pasta da captura; pode não disparar em alguns aparelhos. `aoNFC()` escuta tags enquanto o app está aberto em primeiro plano e exige NFC ligado no aparelho.
1113
+
873
1114
  Deep links:
874
1115
 
875
1116
  ```js
package/package.json CHANGED
@@ -1,17 +1,22 @@
1
1
  {
2
2
  "name": "html2apk",
3
- "version": "0.9.0",
3
+ "version": "12.0.0",
4
+ "author": {
5
+ "name": "Dev Caio Multiversando",
6
+ "email": "dev@caio.local"
7
+ },
4
8
  "description": "Node CLI and library to turn an HTML/CSS/JS folder into an Android APK through Cordova.",
5
9
  "main": "index.js",
6
10
  "bin": {
7
- "html2apk": "./bin/html2apk.js"
11
+ "html2apk": "bin/html2apk.js"
8
12
  },
9
13
  "type": "commonjs",
10
14
  "license": "MIT",
11
15
  "files": [
12
16
  "bin",
13
17
  "src",
14
- "examples",
18
+ "examples/minimal/app.json",
19
+ "examples/minimal/index.html",
15
20
  "index.js",
16
21
  "html2apk.png",
17
22
  "README.md"
@@ -21,7 +26,8 @@
21
26
  "doctor": "node bin/html2apk.js doctor",
22
27
  "desktop": "node bin/html2apk-desktop.js",
23
28
  "build-desktop-win": "node scripts/build-desktop-portable.js",
24
- "test": "node --test",
29
+ "build-desktop-deb": "npx electron-builder --linux deb",
30
+ "test": "node --test test/config.test.js",
25
31
  "build-win": "pkg . --targets node20-win-x64 --output dist/html2apk.exe",
26
32
  "build-linux": "pkg . --targets node20-linux-x64 --output dist/html2apk-linux",
27
33
  "build-mac": "pkg . --targets node20-macos-x64 --output dist/html2apk-macos"
@@ -60,6 +66,12 @@
60
66
  "portable"
61
67
  ],
62
68
  "icon": "html2apk.png"
69
+ },
70
+ "linux": {
71
+ "target": [
72
+ "deb"
73
+ ],
74
+ "icon": "html2apk.png"
63
75
  }
64
76
  },
65
77
  "devDependencies": {