A sua app Capacitor mantém o ecrã web, enquanto o transporte e a apresentação da conversa permanecem nativos.
Instalar e sincronizar os pacotes Capacitor publicados
Num host novo, inicialize o Capacitor uma vez, instale os pacotes de plataforma Capacitor correspondentes e instale o wrapper DobroDesk e o pacote de protocolo partilhado na mesma versão do release. Adicione cada plataforma nativa uma vez e sincronize depois os projetos.
# Run once for a new host.
npx cap init "Your app" com.example.app --web-dir=www
npm install @capacitor/core@8.5.3 @capacitor/cli@8.5.3 @capacitor/ios@8.5.3 @capacitor/android@8.5.3 @dobrodesk/capacitor-sdk@0.2.0 @dobrodesk/mobile-protocol@0.2.0
npx cap add ios --packagemanager CocoaPods
npx cap add android
npx cap syncRegistar o repositório Android incluído
Adicione o caminho Maven local do wrapper Capacitor nas definições Android do host. O wrapper aplica org.jetbrains.kotlin.android sem escolher uma versão, por isso declare os plugins Kotlin e Android antes das linhas include geradas. O host mínimo testado do Capacitor 6.2.1 usa Android Gradle Plugin 8.13.2, Kotlin Gradle Plugin 2.2.0, Gradle 8.14.3 e JDK 17. O host atual gerado do Capacitor 8.5.3 usa AGP 8.13.0, Kotlin 2.2.20 e JDK 21. Mantenha as versões geradas pela versão Capacitor instalada. PREFER_SETTINGS mantém compatível o repositório do módulo Android oficial do Capacitor enquanto os artefactos DobroDesk são resolvidos a partir do pacote instalado.
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id 'com.android.application' version '8.13.0' apply false
id 'com.android.library' version '8.13.0' apply false
id 'org.jetbrains.kotlin.android' version '2.2.20' apply false
}
import org.gradle.api.initialization.resolve.RepositoriesMode
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
google()
mavenCentral()
maven { url = uri("$rootDir/../node_modules/@dobrodesk/capacitor-sdk/native/maven") }
}
}
// Keep the generated include and apply-from lines below this block.Definir os requisitos das plataformas nativas
O wrapper publicado requer iOS 15.1 ou posterior e Android API 26 ou posterior. Ambos os perfis Android testados usam compile SDK 36 e minSdk 26. O perfil mínimo do Capacitor 6.2.1 usa JDK 17. Para esse perfil, defina distributionUrl em android/gradle/wrapper/gradle-wrapper.properties como https://services.gradle.org/distributions/gradle-8.14.3-all.zip. Os hosts atuais do Capacitor 8.5.3 usam JDK 21 com o wrapper e a combinação compatível gerados. Defina o destino iOS antes de pod install e aumente minSdkVersion do projeto Android gerado de 24 para 26.
# ios/App/Podfile
platform :ios, "15.1"
# android/variables.gradle
minSdkVersion = 26
compileSdkVersion = 36
# android/gradle/wrapper/gradle-wrapper.properties for Capacitor 6.2.1
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zipConfigurar e apresentar o wrapper nativo
O wrapper suporta Capacitor 6 a 8. Depois de instalar os pacotes, sincronizar os projetos nativos e configurar o repositório, forneça credentialProvider a partir da sua aplicação host.
O ecrã web do host continua a ser uma WebView Capacitor normal, mas o widget e o transporte DobroDesk são nativos. Não carregue o renderer web do widget na WebView como substituto desta integração.
import { DobroDeskCapacitorClient } from "@dobrodesk/capacitor-sdk";
import type { DobroDeskSdkConfig } from "@dobrodesk/mobile-protocol";
const config: DobroDeskSdkConfig = {
apiOrigin: "https://dobrodesk.com",
integrationId: "wgt_0123456789abcdef0123456789abcdef",
accountScope: currentCustomer.id,
credentialProvider: async () => ({
authorizationToken: await loadDobroDeskToken(),
}),
};
const client = new DobroDeskCapacitorClient(config);
await client.presentWidget();Usar um acionador personalizado ou uma superfície integrada
Use launcher: hidden quando o seu aplicativo controla o acionador. Para uma superfície integrada, defina largura e altura estáveis antes da montagem para evitar mudanças no layout durante o carregamento.
O botão personalizado deve ser acessível pelo teclado e expor aria-controls e aria-expanded. Passe o callback onError tipado se o host precisar do seu próprio estado de recuperação. A função dispose do exemplo remove o listener do botão e liberta a superfície sem reiniciar a sessão nem o rascunho.
mountWidget faz parte do pacote publicado do Mobile SDK 0.2.0. Use-o para uma superfície nativa limitada e chame await handle.dispose() quando o host remover o contentor.
import type {
DobroDeskCapacitorClient,
DobroDeskEmbeddedWidget,
} from "@dobrodesk/capacitor-sdk";
type SupportPanelOptions = Readonly<{
onError?: (error: unknown) => void;
}>;
export async function mountSupportPanel(
client: DobroDeskCapacitorClient,
{ onError }: SupportPanelOptions = {},
) {
const supportSlot = document.querySelector<HTMLElement>("#support-slot");
const helpButton = document.querySelector<HTMLButtonElement>("#help-button");
if (
!supportSlot ||
!helpButton ||
!supportSlot.isConnected ||
!helpButton.isConnected
) {
throw new Error("Connect #support-slot and #help-button before mounting");
}
Object.assign(supportSlot.style, { width: "100%", height: "560px" });
helpButton.setAttribute("aria-controls", "support-slot");
let visible = true;
let mountedHandle: DobroDeskEmbeddedWidget | undefined;
const toggle = () => {
visible = !visible;
mountedHandle?.setVisible(visible);
helpButton.setAttribute("aria-expanded", String(visible));
};
const onClose = () => {
visible = false;
helpButton.setAttribute("aria-expanded", "false");
};
helpButton.addEventListener("click", toggle);
try {
mountedHandle = await client.mountWidget(
supportSlot,
{ locale: "en", view: "home" },
{ onClose, onError },
);
mountedHandle.setVisible(true);
helpButton.setAttribute("aria-expanded", "true");
} catch (error) {
helpButton.removeEventListener("click", toggle);
onError?.(error);
throw error;
}
if (!mountedHandle) throw new Error("Support widget did not mount");
const handle = mountedHandle;
return {
handle,
dispose: async () => {
helpButton.removeEventListener("click", toggle);
await handle.dispose();
},
};
}Separar ciclos híbridos e nativos
O credentialProvider fornecido pelo host deve chamar um endpoint backend que devolva um JWT de identidade do cliente de curta duração. Não deve expor um support API token ou signing secret no bundle web. Chame closeWidget quando a rota do host for destruída, resetSession quando a conversa for descartada e logout antes de trocar de conta.
O presenter nativo respeita a definição do sistema para reduzir movimento quando não existe override. Mantenha as transições da página host independentes para que uma alteração de rota WebView não crie um segundo widget nativo.
Tratar carregamento, visibilidade e acessibilidade
Use hooks de carregamento ou eventos tipados para o estado da tela hospedeira. A superfície mostra o carregamento das mensagens, a espera e as tentativas novamente para evitar um segundo indicador sobre o campo de entrada.
Oculte ou mostre a superfície durante uma navegação temporária mantendo o cliente. O widget respeita as preferências do sistema para reduzir movimento. Remover ou fechar a vista não descarta a sessão nem o rascunho.
- Ao montar novamente, reutilize o mesmo cliente e dimensões estáveis do contêiner.
- Use a função de visibilidade para ocultar temporariamente, sem redefinir a sessão.
- Finalize a sessão apenas ao sair ou trocar de conta de forma intencional.
Verificar o fluxo Capacitor
- Execute npx cap doctor depois de npx cap sync e abra o widget a partir do ecrã web. Confirme que a apresentação é nativa e que não aparece um segundo iframe do widget web.
- Teste start, resume, send com uma idempotency key estável, refresh e flushOutbox enquanto alterna a disponibilidade da rede.
- Chame logout antes de alterar o cliente assinado e confirme que o cliente seguinte não herda a sessão nativa anterior.