PushMesh
Entrar Criar conta
Abrir navegação das seções

Índice

Migração de plataforma 2026

iOS 27 torna o UISceneDelegate obrigatório e o Google Play passou a exigir targetSdk 36 — o que muda no seu aplicativo, o que não muda em nada no SDK, e o passo a passo com código.

Migração de plataforma 2026

Duas exigências externas encostam no seu aplicativo em 2026, as duas com data marcada e as duas decididas fora do PushMesh. Esta página diz o que muda, como saber se você é afetado e o passo a passo da migração — incluindo o que não muda, que é a parte que costuma gerar susto sem motivo.

A boa notícia, antes de tudo: nenhuma das duas mudanças exige mexer na sua integração com o PushMesh. O trabalho é do seu aplicativo, e esta página é o mapa dele.


O que muda e quando

QuandoQuem exigeO quê
31/08/2026 — em vigorGoogle PlayAplicativo novo ou atualização só é aceito na loja mirando targetSdk 36 (Android 16). Extensão até 01/11/2026, pedida pelo Play Console
setembro/2026AppleCom o SDK final do iOS 27, aplicativo que não adotou o ciclo de vida de cena (UISceneDelegate) não sobe

A frase que merece atenção é a última. Aplicativo que não sobe não pega token do APNs, não registra e não recebe push nenhum — e a trava é pelo SDK com que se compila, não pela versão do aparelho do usuário. Ou seja: recompilar o seu aplicativo de sempre com o Xcode do iOS 27, sem migrar, já basta para ele não abrir. O aparelho que já tem o aplicativo instalado continua rodando.


Como saber se você é afetado

iOS — duas perguntas

É o teste oficial da própria Apple (nota técnica TN3187):

  1. O Info.plist do aplicativo tem a chave UIApplicationSceneManifest com configurações declaradas?
  2. O AppDelegate implementa application(_:configurationForConnecting:options:)?

Se a resposta das duas é “não”, o aplicativo precisa migrar. A maioria dos aplicativos UIKit escritos antes de 2025 está nesse caso — inclusive todo aplicativo gerado por expo prebuild hoje (ver a seção Expo).

Android — uma pergunta

grep -rn "targetSdk" android/app/build.gradle android/build.gradle

Se não aparece 36 (ou maior), o próximo envio à Play Store não é aceito.


iOS 27 — a migração

Quatro passos. O código Swift abaixo é o do nosso próprio aplicativo de laboratório, já migrado: ele compilou, subiu no simulador e registrou com token APNs real.

1. Crie o SceneDelegate. É a cena que cria a janela agora, com UIWindow(windowScene:) no lugar do UIWindow(frame:) que o AppDelegate usava:

import UIKit

final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
  var window: UIWindow?

  func scene(_ cena: UIScene, willConnectTo sessao: UISceneSession,
             options: UIScene.ConnectionOptions) {
    guard let cenaDeJanela = cena as? UIWindowScene else { return }
    let janela = UIWindow(windowScene: cenaDeJanela)
    janela.rootViewController = SeuViewControllerRaiz()
    janela.makeKeyAndVisible()
    window = janela
  }
}

2. Ligue a cena no AppDelegate com application(_:configurationForConnecting:options:):

func application(_ app: UIApplication,
                 configurationForConnecting sessao: UISceneSession,
                 options: UIScene.ConnectionOptions) -> UISceneConfiguration {
  let cfg = UISceneConfiguration(name: "Padrao", sessionRole: sessao.role)
  cfg.delegateClass = SceneDelegate.self
  return cfg
}

3. Declare o manifesto de cena no Info.plist:

<key>UIApplicationSceneManifest</key>
<dict>
    <key>UIApplicationSupportsMultipleScenes</key>
    <false/>
    <key>UISceneConfigurations</key>
    <dict>
        <key>UIWindowSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneConfigurationName</key>
                <string>Padrao</string>
                <key>UISceneDelegateClassName</key>
                <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
            </dict>
        </array>
    </dict>
</dict>

Se o aplicativo carrega a interface de um storyboard, acrescente a chave UISceneStoryboardFile com o nome dele no mesmo dicionário — o sistema monta a janela sozinho e o passo 4 não se aplica a você.

4. Mova para a cena o que era da janela. Tudo o que o seu didFinishLaunchingWithOptions fazia de interface — criar UIWindow, definir rootViewController — passa para o scene(_:willConnectTo:options:). O resto do método, que é onde as inicializações moram, fica onde está.

O passo a passo completo, incluindo cenários de múltiplas cenas e CarPlay, é a nota técnica TN3187 da Apple.


O que NÃO muda

Esta parte é a que acalma:

  • Os callbacks de push continuam no UIApplicationDelegate. O registro do token (didRegisterForRemoteNotificationsWithDeviceToken) e os avisos de notificação não se movem com a migração — e é exatamente ali que o nosso SDK se pendura, por swizzle. Migrado o ciclo de vida, o PushMesh continua funcionando sem nenhuma alteração de integração.
  • Nenhum SDK nosso lê launchOptions. É o caminho de código que a migração para cena costuma quebrar em aplicativos que tratam push “na mão”. O nosso laboratório migrado registrou e confirmou entrega (recebidos = 1) sem nenhuma mudança no SDK.
  • A inicialização é a mesma. Mesmos métodos, mesmos parâmetros, mesma promessa de entrega com recibo.

Um único cuidado é seu, não nosso: se o seu aplicativo lê launchOptions[.remoteNotification] para reagir ao toque que o abriu, esse trecho precisa migrar para a cena junto com a janela.


Android — targetSdk 36

No android/app/build.gradle do seu aplicativo:

android {
    defaultConfig {
        targetSdkVersion 36
    }
}

O módulo Android do nosso SDK segue o targetSdk do aplicativo hospedeiro — não há nada a mudar nele. O que muda é o comportamento que o Android 16 liga quando o alvo sobe.

O que muda mirando 36

As três mudanças do Android 16 que costumam pegar aplicativo real, na ordem de probabilidade:

  1. Edge-to-edge sem saída. No Android 15 dava para recusar com windowOptOutEdgeToEdgeEnforcement; mirando 36, o atributo é ignorado e o aplicativo vai até as bordas. Se o seu layout encosta na barra de status ou na de navegação, trate os insets.
  2. Orientação livre em tela grande. Em displays com largura mínima de 600dp (tablets, dobráveis, janela de desktop), screenOrientation, resizableActivity e as travas de proporção são ignorados — aplicativo travado em retrato vai girar. Existe escape temporário por atividade ou pelo aplicativo inteiro (PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY): use para ganhar tempo, não como destino.
  3. Volta preditiva ligada por padrão. onBackPressed deixa de ser chamado e KEYCODE_BACK não é mais despachado. Se o aplicativo intercepta o “voltar”, migre para as APIs de volta preditiva ou desligue temporariamente com android:enableOnBackInvokedCallback="false" no manifesto.

A referência completa é a página oficial de mudanças de comportamento do Android 16.

O que pega quem vem de versões antigas

Não é novidade do 36, mas atinge quem estava pulando versões: desde o Android 14 (API 34), a notificação de tela cheia (full-screen intent, estilo chamada recebida) exige concessão do usuário — o padrão na instalação passou a ser negado, exceto para aplicativos de chamada e alarme. Se o seu aplicativo usa setFullScreenIntent, confira NotificationManager.canUseFullScreenIntent() em tempo de execução em vez de assumir a permissão.

O que não vem do nosso SDK

Duas exigências que você pode riscar da sua lista por nossa conta:

  • Trampolim de notificação — o Android 12 proibiu notificação que abre atividade via broadcast intermediário. O toque nas nossas notificações vai direto por PendingIntent.getActivity (PushMeshMessageRouter.kt:329): correto por construção, nada a fazer.
  • Páginas de memória de 16 KB — a exigência atinge quem carrega biblioteca nativa (.so). Nosso módulo Android é Kotlin puro, sem nativo próprio.

Expo — dois problemas conhecidos, nenhum nosso

Franqueza primeiro: hoje, nas últimas versões publicadas, um aplicativo Expo tropeça duas vezes no Xcode novo. Os dois defeitos são da Expo, não do PushMesh — e os dois têm contorno:

  1. O template do prebuild ainda gera o ciclo de vida antigo. O aplicativo gerado nasce sem UISceneDelegate e não sobe quando compilado com o SDK do iOS 27 (expo/expo#46663, expo/expo#46664). A Expo já sinalizou que o prebuild passará a gerar o SceneDelegate sozinho; até lá, a migração da seção iOS acima é sua, aplicada no projeto gerado.

  2. expo-modules-jsi 57.0.5 e 57.0.6 não compilam com o toolchain recente do Xcode 26. O clang recusa SWIFT_RETURNS_RETAINED aplicado a construtor em RuntimeScheduler.h (expo/expo#49214, expo/expo#49426). O contorno confirmado na própria issue é travar as versões exatas no package.json:

    "overrides": {
      "expo-modules-core": "57.0.11",
      "expo-modules-jsi": "57.0.4"
    }

    (Em Yarn, a mesma ideia na chave resolutions.) Uma nuance importante: o defeito foi introduzido na 57.0.5, então “use o Xcode 26.2” só resolve para quem ainda está em expo-modules-jsi 57.0.4 ou anterior — com 57.0.5 ou 57.0.6, o build quebra no 26.2 também, e o caminho é o pin.


Se um passo não funcionar

É a página que precisa de correção, e queremos saber: contato@pushmesh.io. Conte o passo, a versão do Xcode ou do Android Gradle Plugin e o erro exato — “segui o guia e não subiu” com esses três dados vira correção de documentação, não tentativa e erro.