html2apk 0.9.0 → 0.11.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 +217 -5
- package/package.json +15 -4
- package/src/desktop/main.js +551 -25
- package/src/desktop/renderer/index.html +1 -1
- package/src/desktop/renderer/renderer.js +517 -35
- package/src/desktop/renderer/styles.css +13 -3
- package/src/runtime-manager/index.js +79 -17
- package/src/templates/cordova-plugin-html2apk-bridge/plugin.xml +33 -0
- package/src/templates/cordova-plugin-html2apk-bridge/src/android/FloatingIconService.java +33 -0
- package/src/templates/cordova-plugin-html2apk-bridge/src/android/Html2ApkBridge.java +5187 -1634
- package/src/templates/cordova-plugin-html2apk-bridge/www/html2apk-bridge.js +485 -12
- package/src/templates/html2apk-early-bridge.js +485 -12
- package/src/templates/html2apk-runtime-console.js +169 -29
- package/examples/minimal/dist/MeuApp-1.0.0-debug.apk +0 -0
- package/examples/minimal/dist/MeuApp-1.0.0-release.aab +0 -0
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
|
|
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,10 +512,18 @@ 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()` |
|
|
@@ -451,9 +533,23 @@ Exemplos de aliases:
|
|
|
451
533
|
| `removerSeguro()` | `deleteSecure()` |
|
|
452
534
|
| `aoEvento()` | `onEvent()` |
|
|
453
535
|
| `aoMinimizar()` | `onMinimize()` |
|
|
536
|
+
| `aoConectarUSB()` | `onUSBConnect()` |
|
|
537
|
+
| `aoDesconectarUSB()` | `onUSBDisconnect()` |
|
|
538
|
+
| `aoConectarFone()` | `onHeadphoneConnect()` |
|
|
539
|
+
| `aoDesconectarFone()` | `onHeadphoneDisconnect()` |
|
|
540
|
+
| `aoMudarVolume()` | `onVolumeChange()` |
|
|
541
|
+
| `aoAbrirTeclado()` | `onKeyboardOpen()` |
|
|
542
|
+
| `aoFecharTeclado()` | `onKeyboardClose()` |
|
|
543
|
+
| `aoSacudirCelular()` | `onPhoneShake()` |
|
|
544
|
+
| `aoVirarCelularParaBaixo()` | `onPhoneFaceDown()` |
|
|
545
|
+
| `aoAproximarObjeto()` | `onProximityNear()` |
|
|
546
|
+
| `aoTirarPrint()` | `onScreenshot()` |
|
|
547
|
+
| `aoMudarOrientacao()` | `onOrientationChange()` |
|
|
548
|
+
| `aoNFC()` | `onNFC()` |
|
|
549
|
+
| `aoReceberNotificacao()` | `onNotificationReceived()` |
|
|
454
550
|
| `obterLinkInicial()` | `getInitialLink()` |
|
|
455
551
|
|
|
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`.
|
|
552
|
+
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
553
|
|
|
458
554
|
Como tratar retornos:
|
|
459
555
|
|
|
@@ -470,6 +566,7 @@ No seu JavaScript do app:
|
|
|
470
566
|
```js
|
|
471
567
|
toast("Mensagem");
|
|
472
568
|
vibrar(250);
|
|
569
|
+
await aguardar(5000);
|
|
473
570
|
|
|
474
571
|
await notificar({
|
|
475
572
|
titulo: "Pedido aprovado",
|
|
@@ -532,6 +629,14 @@ fullscreen(true);
|
|
|
532
629
|
|
|
533
630
|
`notificar()` nao obriga clique, botao nem funcao. So `titulo` e `texto` ja geram uma notificacao normal. `aoClicar`, `acoes`/`actions` e `open` sao opcionais.
|
|
534
631
|
|
|
632
|
+
`aguardar(ms)` e `loading(ms)` pausam o fluxo com Promise, sem travar a WebView:
|
|
633
|
+
|
|
634
|
+
```js
|
|
635
|
+
await toast("Comecando");
|
|
636
|
+
await aguardar(5000);
|
|
637
|
+
await toast("Continuando");
|
|
638
|
+
```
|
|
639
|
+
|
|
535
640
|
`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
641
|
|
|
537
642
|
Em `aoClicar`, voce pode passar uma funcao diretamente:
|
|
@@ -637,9 +742,10 @@ Arquivos, galeria e compartilhamento:
|
|
|
637
742
|
|
|
638
743
|
```js
|
|
639
744
|
const imagem = await escolherImagem();
|
|
640
|
-
const imagens = await escolherImagens({
|
|
745
|
+
const imagens = await escolherImagens({ multiplas: true });
|
|
641
746
|
const pdf = await escolherArquivo({ tipos: ["application/pdf"] });
|
|
642
747
|
const arquivos = await escolherArquivos({ multiplo: true });
|
|
748
|
+
const pasta = await escolherPasta();
|
|
643
749
|
|
|
644
750
|
await salvarArquivo({
|
|
645
751
|
nome: "relatorio.txt",
|
|
@@ -647,9 +753,75 @@ await salvarArquivo({
|
|
|
647
753
|
conteudo: "Conteudo salvo pelo app"
|
|
648
754
|
});
|
|
649
755
|
|
|
650
|
-
await compartilhar({
|
|
756
|
+
await compartilhar({
|
|
757
|
+
titulo: "Material",
|
|
758
|
+
texto: "Veja isso",
|
|
759
|
+
url: "https://exemplo.com",
|
|
760
|
+
arquivo: imagem
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
aoReceberCompartilhamento((dados) => {
|
|
764
|
+
console.log("Compartilhamento recebido", dados.tipo, dados.uri || dados.texto);
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
const texto = await ocr(imagem);
|
|
768
|
+
console.log(texto.texto);
|
|
769
|
+
|
|
770
|
+
await falar("Ola mundo", { idioma: "pt-BR", velocidade: 1 });
|
|
771
|
+
const voz = await ouvir({ idioma: "pt-BR" });
|
|
772
|
+
console.log(voz.texto);
|
|
773
|
+
|
|
774
|
+
aoConectarBT((dispositivo) => {
|
|
775
|
+
console.log("Bluetooth conectado", dispositivo.nome);
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
aoReceberDadosBT((dados) => {
|
|
779
|
+
console.log("Dados Bluetooth", dados);
|
|
780
|
+
});
|
|
781
|
+
|
|
782
|
+
aoDarErroBT((erro) => {
|
|
783
|
+
console.log("Erro Bluetooth", erro.mensagem || erro.message);
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
const dispositivos = await procurarBT();
|
|
787
|
+
if (dispositivos[0]) {
|
|
788
|
+
await conectarBT(dispositivos[0].id);
|
|
789
|
+
await enviarBT({ mensagem: "Ola por Bluetooth" });
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
aoConectarWiFi((dispositivo) => {
|
|
793
|
+
console.log("Wi-Fi conectado", dispositivo.nome || dispositivo.host);
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
aoReceberDadosWiFi((dados) => {
|
|
797
|
+
console.log("Dados Wi-Fi", dados);
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
aoDarErroWiFi((erro) => {
|
|
801
|
+
console.log("Erro Wi-Fi", erro.mensagem || erro.message);
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
const dispositivosWifi = await procurarWiFi();
|
|
805
|
+
if (dispositivosWifi[0]) {
|
|
806
|
+
await conectarWiFi(dispositivosWifi[0].id);
|
|
807
|
+
await enviarWiFi({ mensagem: "Ola por Wi-Fi" });
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
await share_me(); // compartilha o APK do proprio app aberto
|
|
651
811
|
```
|
|
652
812
|
|
|
813
|
+
`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 }`.
|
|
814
|
+
|
|
815
|
+
`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 }`.
|
|
816
|
+
|
|
817
|
+
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.
|
|
818
|
+
|
|
819
|
+
`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"`.
|
|
820
|
+
|
|
821
|
+
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.
|
|
822
|
+
|
|
823
|
+
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.
|
|
824
|
+
|
|
653
825
|
`salvarArquivo()` tem dois modos:
|
|
654
826
|
|
|
655
827
|
- `salvarArquivo({ nome, conteudo })` abre o seletor nativo para o usuario escolher onde salvar, como ja acontecia.
|
|
@@ -684,7 +856,8 @@ await baixarArquivo("https://exemplo.com/relatorio.pdf", "relatorio.pdf");
|
|
|
684
856
|
await abrirArquivo("relatorio.pdf");
|
|
685
857
|
|
|
686
858
|
await baixarBase64("foto.png", base64DaImagem, {
|
|
687
|
-
mimeType: "image/png"
|
|
859
|
+
mimeType: "image/png",
|
|
860
|
+
galeria: true
|
|
688
861
|
});
|
|
689
862
|
|
|
690
863
|
const arquivo = await escolherArquivo();
|
|
@@ -695,6 +868,8 @@ if (arquivo) {
|
|
|
695
868
|
|
|
696
869
|
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
870
|
|
|
871
|
+
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`.
|
|
872
|
+
|
|
698
873
|
Papel de parede:
|
|
699
874
|
|
|
700
875
|
```js
|
|
@@ -853,6 +1028,27 @@ const abertos = await appsAbertos();
|
|
|
853
1028
|
|
|
854
1029
|
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
1030
|
|
|
1031
|
+
Tela, volume e ciclo do app:
|
|
1032
|
+
|
|
1033
|
+
```js
|
|
1034
|
+
const volume = await volumeAtual();
|
|
1035
|
+
console.log(volume.midia.atual, volume.midia.maximo);
|
|
1036
|
+
|
|
1037
|
+
await definirVolume("midia", 0.5, { mostrarUI: true });
|
|
1038
|
+
await aumentarVolume("midia", 1);
|
|
1039
|
+
await diminuirVolume("midia", 1);
|
|
1040
|
+
|
|
1041
|
+
const imagem = await capturarTela();
|
|
1042
|
+
document.querySelector("img.preview").src = imagem.dataUrl;
|
|
1043
|
+
|
|
1044
|
+
await minimizarApp();
|
|
1045
|
+
|
|
1046
|
+
// Use somente depois de salvar estado importante:
|
|
1047
|
+
// await fecharApp();
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
`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.
|
|
1051
|
+
|
|
856
1052
|
Eventos nativos:
|
|
857
1053
|
|
|
858
1054
|
```js
|
|
@@ -865,11 +1061,27 @@ aoEvento("botao:voltar", console.log);
|
|
|
865
1061
|
aoEvento("link:aberto", (evento) => console.log(evento.url));
|
|
866
1062
|
aoEvento("rede:mudou", console.log);
|
|
867
1063
|
aoEvento("bateria:mudou", console.log);
|
|
1064
|
+
aoConectarUSB((dados) => console.log("USB conectado", dados));
|
|
1065
|
+
aoDesconectarUSB(() => console.log("USB desconectado"));
|
|
1066
|
+
aoReceberNotificacao((dados) => console.log("Notificação recebida", dados));
|
|
868
1067
|
aoEvento("notificacao:clicada", console.log);
|
|
1068
|
+
aoConectarFone((dados) => console.log("Fone conectado", dados.dispositivo));
|
|
1069
|
+
aoDesconectarFone(() => console.log("Fone desconectado"));
|
|
1070
|
+
aoMudarVolume((dados) => console.log("Volume de mídia", dados.midia.atual));
|
|
1071
|
+
aoAbrirTeclado((dados) => console.log("Teclado abriu", dados.alturaTeclado));
|
|
1072
|
+
aoFecharTeclado(() => console.log("Teclado fechou"));
|
|
1073
|
+
aoMudarOrientacao((dados) => console.log("Orientação", dados.orientacao));
|
|
1074
|
+
aoSacudirCelular((dados) => console.log("Sacudiu", dados.forca));
|
|
1075
|
+
aoVirarCelularParaBaixo(() => console.log("Tela para baixo"));
|
|
1076
|
+
aoAproximarObjeto((dados) => console.log("Objeto perto", dados.distancia));
|
|
1077
|
+
aoTirarPrint((dados) => console.log("Print detectado", dados.uri));
|
|
1078
|
+
aoNFC((dados) => console.log("Tag NFC", dados.id, dados.mensagens));
|
|
869
1079
|
|
|
870
1080
|
parar();
|
|
871
1081
|
```
|
|
872
1082
|
|
|
1083
|
+
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.
|
|
1084
|
+
|
|
873
1085
|
Deep links:
|
|
874
1086
|
|
|
875
1087
|
```js
|
package/package.json
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "html2apk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
|
+
"author": { "name": "Dev Caio Multiversando", "email": "dev@caio.local" },
|
|
5
|
+
|
|
4
6
|
"description": "Node CLI and library to turn an HTML/CSS/JS folder into an Android APK through Cordova.",
|
|
5
7
|
"main": "index.js",
|
|
6
8
|
"bin": {
|
|
7
|
-
"html2apk": "
|
|
9
|
+
"html2apk": "bin/html2apk.js"
|
|
8
10
|
},
|
|
9
11
|
"type": "commonjs",
|
|
10
12
|
"license": "MIT",
|
|
11
13
|
"files": [
|
|
12
14
|
"bin",
|
|
13
15
|
"src",
|
|
14
|
-
"examples",
|
|
16
|
+
"examples/minimal/app.json",
|
|
17
|
+
"examples/minimal/index.html",
|
|
15
18
|
"index.js",
|
|
16
19
|
"html2apk.png",
|
|
17
20
|
"README.md"
|
|
@@ -21,7 +24,9 @@
|
|
|
21
24
|
"doctor": "node bin/html2apk.js doctor",
|
|
22
25
|
"desktop": "node bin/html2apk-desktop.js",
|
|
23
26
|
"build-desktop-win": "node scripts/build-desktop-portable.js",
|
|
24
|
-
"
|
|
27
|
+
"build-desktop-deb": "npx electron-builder --linux deb",
|
|
28
|
+
|
|
29
|
+
"test": "node --test test/config.test.js",
|
|
25
30
|
"build-win": "pkg . --targets node20-win-x64 --output dist/html2apk.exe",
|
|
26
31
|
"build-linux": "pkg . --targets node20-linux-x64 --output dist/html2apk-linux",
|
|
27
32
|
"build-mac": "pkg . --targets node20-macos-x64 --output dist/html2apk-macos"
|
|
@@ -60,6 +65,12 @@
|
|
|
60
65
|
"portable"
|
|
61
66
|
],
|
|
62
67
|
"icon": "html2apk.png"
|
|
68
|
+
},
|
|
69
|
+
"linux": {
|
|
70
|
+
"target": [
|
|
71
|
+
"deb"
|
|
72
|
+
],
|
|
73
|
+
"icon": "html2apk.png"
|
|
63
74
|
}
|
|
64
75
|
},
|
|
65
76
|
"devDependencies": {
|