Extensões do iOS no Xamarin.iOS
Criando extensões no vídeo do iOS
As extensões, conforme introduzidas no iOS 8, são especializadas UIViewControllers
e apresentadas pelo iOS dentro de contextos padrão, como na Central de Notificações, como tipos de teclado personalizados solicitados pelo usuário para executar entrada especializada ou outros contextos, como editar uma foto em que a extensão pode fornecer filtros de efeitos especiais.
Todas as extensões são instaladas em conjunto com um aplicativo de contêiner (com ambos os elementos gravados usando as APIs unificadas de 64 bits) e são ativadas de um ponto de extensão específico em um aplicativo host. E como eles serão usados como suplementos às funções existentes do sistema, eles devem ser de alto desempenho, enxutos e robustos.
Pontos de extensão
Tipo | Descrição | Ponto de extensão | Aplicativo Host |
---|---|---|---|
Ação | Editor ou visualizador especializado para um determinado tipo de mídia | com.apple.ui-services |
Qualquer |
Provedor de documentos | Permite que o aplicativo use um armazenamento de documentos remoto | com.apple.fileprovider-ui |
Aplicativos que usam um UIDocumentPickerViewController |
Teclado | Teclados alternativos | com.apple.keyboard-service |
Qualquer |
Edição de fotos | Manipulação e edição de fotos | com.apple.photo-editing |
Photos.app editor |
Compartilhar | Compartilha dados com redes sociais, serviços de mensagens, etc. | com.apple.share-services |
Qualquer |
Hoje | "Widgets" que aparecem na tela Hoje ou na Central de Notificações | com.apple.widget-extensions |
Hoje e Central de Notificações |
Pontos de extensão adicionais foram adicionados no iOS 10 e iOS 12. Você pode encontrar a tabela completa de todos os tipos com suporte no Guia de Programação de Extensão de Aplicativo iOS.
Limitações
As extensões têm várias limitações, algumas das quais são universais para todos os tipos (por exemplo, nenhum tipo de extensão pode acessar as câmeras ou microfones), enquanto outros tipos de extensão podem ter limitações específicas em seu uso (por exemplo, teclados personalizados não podem ser usados para campos de entrada de dados seguros, como senhas).
As limitações universais são:
- As estruturas de interface do usuário do Kit de Integridade e do Kit de Eventos não estão disponíveis
- As extensões não podem usar modos de plano de fundo estendidos
- As extensões não podem acessar as câmeras ou microfones do dispositivo (embora possam acessar arquivos de mídia existentes)
- As extensões não podem receber dados do Air Drop (embora possam transmitir dados via Air Drop)
- UIActionSheet e UIAlertView não estão disponíveis; as extensões devem usar UIAlertController
- Vários membros de UIApplication não estão disponíveis: UIApplication.SharedApplication, UIApplication.OpenUrl, UIApplication.BeginIgnoringInteractionEvents e UIApplication.EndIgnoringInteractionEvents
- O iOS impõe um limite de uso de memória de 16 MB nas extensões de hoje.
- Por padrão, as extensões de teclado não têm acesso à rede. Isso afeta a depuração no dispositivo (a restrição não é imposta no simulador), pois o Xamarin.iOS requer acesso à rede para que a depuração funcione. É possível solicitar acesso à rede definindo o
Requests Open Access
valor no Info.plist do projeto comoYes
. Consulte o Guia de teclado personalizado da Apple para obter mais informações sobre as limitações de extensão de teclado.
Para limitações individuais, consulte o Guia de Programação de Extensão de Aplicativo da Apple.
Distribuindo, instalando e executando extensões
As extensões são distribuídas de dentro de um aplicativo de contêiner, que, por sua vez, é enviado e distribuído por meio da App Store. As extensões distribuídas com o aplicativo são instaladas nesse ponto, mas o usuário deve habilitar cada extensão explicitamente. Os diferentes tipos de extensões são ativados de maneiras diferentes; vários exigem que o usuário navegue até o aplicativo Configurações e habilite-os a partir daí. Enquanto outros são ativados no ponto de uso, como ativar uma extensão de compartilhamento ao enviar uma foto.
O aplicativo no qual a Extensão é usada (em que o usuário encontra o Ponto de Extensão) é chamado de aplicativo Host, pois é o aplicativo que hospeda a Extensão quando ela é executada. O aplicativo que instala a Extensão é o aplicativo Contêiner, pois é o aplicativo que continha a Extensão quando ela foi instalada.
Normalmente, o aplicativo de contêiner descreve a extensão e orienta o usuário pelo processo de habilitá-la.
Depurar e lançar versões de extensões
Os limites de memória para executar extensões de aplicativo são significativamente menores do que os limites de memória aplicados a um aplicativo em primeiro plano. Os simuladores que executam o iOS têm menos restrições aplicadas às extensões e você pode executar sua extensão sem problemas. No entanto, executar a mesma extensão em um dispositivo pode levar a resultados inesperados, incluindo falha da extensão ou encerramento agressivo pelo sistema. Portanto, certifique-se de criar e testar a extensão em um dispositivo antes de enviá-la.
Você deve garantir que as seguintes configurações sejam aplicadas ao projeto de contêiner e a todas as extensões referenciadas:
- Crie um pacote de aplicativos na configuração de versão .
- Nas configurações do projeto de build do iOS, defina a opção Comportamento do vinculador como Vincular somente SDKs do Framework ou Vincular tudo.
- Nas configurações do projeto de depuração do iOS, desmarque a opção Habilitar depuração e Habilitar criação de perfil.
Ciclo de vida da extensão
Uma extensão pode ser tão simples quanto um único UIViewController ou extensões mais complexas que apresentam várias telas de interface do usuário. Quando o usuário encontra um Ponto de Extensão (como ao compartilhar uma imagem), ele terá a oportunidade de escolher entre as Extensões registradas para esse Ponto de Extensão.
Se eles escolherem uma das extensões do seu aplicativo, ela UIViewController
será instanciada e iniciará o ciclo de vida normal do Controlador de Exibição. No entanto, ao contrário de um aplicativo normal, que é suspenso, mas geralmente não encerrado quando o usuário termina de interagir com eles, as extensões são carregadas, executadas e encerradas repetidamente.
As extensões podem se comunicar com seus aplicativos Host por meio de um objeto NSExtensionContext . Algumas extensões têm operações que recebem retornos de chamada assíncronos com os resultados. Esses retornos de chamada serão executados em threads em segundo plano e a Extensão deve levar isso em consideração; por exemplo, usando NSObject.InvokeOnMainThread se quiserem atualizar a interface do usuário. Consulte a seção Comunicação com o aplicativo host abaixo para obter mais detalhes.
Por padrão, as extensões e seus aplicativos de contêiner não podem se comunicar, apesar de serem instalados juntos. Em alguns casos, o aplicativo de contêiner é essencialmente um contêiner de "remessa" vazio cuja finalidade é atendida depois que a extensão é instalada. No entanto, se as circunstâncias exigirem, o aplicativo de contêiner e a extensão poderão compartilhar recursos de uma área comum. Além disso, uma Extensão Today pode solicitar que seu aplicativo de contêiner abra uma URL. Esse comportamento é mostrado no widget Event Countdown.
Criando uma extensão
As extensões (e seus aplicativos de contêiner) devem ser binários de 64 bits e criados usando as APIs Unificadas do Xamarin.iOS. Ao desenvolver uma extensão, suas soluções conterão pelo menos dois projetos: o aplicativo de contêiner e um projeto para cada extensão fornecida pelo contêiner.
Requisitos do projeto do aplicativo de contêiner
O aplicativo de contêiner usado para instalar a extensão tem os seguintes requisitos:
- Ele deve manter uma referência ao projeto de extensão.
- Deve ser um aplicativo completo (deve ser capaz de iniciar e executar com êxito), mesmo que não faça nada além de fornecer uma maneira de instalar uma extensão.
- Ele deve ter um Identificador de Pacote que é a base para o Identificador de Pacote do projeto de Extensão (consulte a seção abaixo para obter mais detalhes).
Requisitos do projeto de extensão
Além disso, o projeto da Extensão tem os seguintes requisitos:
Ele deve ter um Identificador de Pacote que comece com o Identificador de Pacote do aplicativo de contêiner. Por exemplo, se o aplicativo de contêiner tiver um identificador de pacote de , o identificador da
com.myCompany.ContainerApp
extensão poderá sercom.myCompany.ContainerApp.MyExtension
:Ele deve definir a chave
NSExtensionPointIdentifier
, com um valor apropriado (comocom.apple.widget-extension
para um widget da Central de Notificações Hoje ), em seuInfo.plist
arquivo.Ele também deve definir a
NSExtensionMainStoryboard
chave ou aNSExtensionPrincipalClass
chave em seuInfo.plist
arquivo com um valor apropriado:- Use a
NSExtensionMainStoryboard
chave para especificar o nome do Storyboard que apresenta a interface do usuário principal para a Extensão (menos.storyboard
). Por exemplo,Main
para oMain.storyboard
arquivo. - Use a
NSExtensionPrincipalClass
chave para especificar a classe que será inicializada quando a extensão for iniciada. O valor deve corresponder ao valor Register do seuUIViewController
:
- Use a
Tipos específicos de extensões podem ter requisitos adicionais. Por exemplo, a classe principal de uma Extensão do Centro de Notificações ou Today deve implementar INCWidgetProviding.
Importante
Se você iniciar seu projeto usando um dos modelos de extensões fornecidos pelo Visual Studio para Mac, a maioria (se não todos) desses requisitos será fornecida e atendida automaticamente pelo modelo.
Passo a passo
No passo a passo a seguir, você criará um widget Hoje de exemplo que calcula o dia e o número de dias restantes no ano:
Criando a solução
Para criar a solução necessária, faça o seguinte:
Primeiro, crie um novo projeto iOS, Single View App e clique no botão Avançar :
Chame o projeto
TodayContainer
e clique no botão Avançar :Verifique o Nome do Projeto e o Nome da Solução e clique no botão Criar para criar a solução:
Em seguida, no Gerenciador de Soluções, clique com o botão direito do mouse na Solução e adicione um novo projeto de Extensão do iOS do modelo Extensão Hoje:
Chame o projeto
DaysRemaining
e clique no botão Avançar :Revise o projeto e clique no botão Criar para criá-lo:
A solução resultante agora deve ter dois projetos, conforme mostrado aqui:
Criando a interface do usuário da extensão
Em seguida, você precisará projetar a interface para o widget Hoje . Isso pode ser feito usando um Storyboard ou criando a interface do usuário no código. Ambos os métodos serão abordados abaixo em detalhes.
Usando storyboards
Para criar a interface do usuário com um Storyboard, faça o seguinte:
No Gerenciador de Soluções, clique duas vezes no arquivo do
Main.storyboard
projeto de extensão para abri-lo para edição:Selecione o rótulo que foi adicionado automaticamente à interface do usuário por modelo e dê a ele o nome
TodayMessage
na guia Widget do Gerenciador de propriedades:Salve as alterações no Storyboard.
Usando código
Para criar a interface do usuário no código, faça o seguinte:
No Gerenciador de Soluções, selecione o projeto DaysRemaining , adicione uma nova classe e chame-a
CodeBasedViewController
de :Novamente, no Gerenciador de Soluções, clique duas vezes no arquivo da
Info.plist
Extensão para abri-lo para edição:Selecione a Visualização de origem (na parte inferior da tela) e abra o
NSExtension
nó:Remova a
NSExtensionMainStoryboard
chave e adicione umNSExtensionPrincipalClass
com o valorCodeBasedViewController
:Salve suas alterações.
Em seguida, edite o CodeBasedViewController.cs
arquivo e faça com que ele fique parecido com o seguinte:
using System;
using Foundation;
using UIKit;
using NotificationCenter;
using CoreGraphics;
namespace DaysRemaining
{
[Register("CodeBasedViewController")]
public class CodeBasedViewController : UIViewController, INCWidgetProviding
{
public CodeBasedViewController ()
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Add label to view
var TodayMessage = new UILabel (new CGRect (0, 0, View.Frame.Width, View.Frame.Height)) {
TextAlignment = UITextAlignment.Center
};
View.AddSubview (TodayMessage);
// Insert code to power extension here...
}
}
}
Observe que o [Register("CodeBasedViewController")]
corresponde ao valor especificado para o NSExtensionPrincipalClass
acima.
Codificando a extensão
Com a interface do usuário criada, abra o TodayViewController.cs
ou o CodeBasedViewController.cs
arquivo (com base no método usado para criar a interface do usuário acima), altere o método ViewDidLoad e faça com que ele se pareça com o seguinte:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Calculate the values
var dayOfYear = DateTime.Now.DayOfYear;
var leapYearExtra = DateTime.IsLeapYear (DateTime.Now.Year) ? 1 : 0;
var daysRemaining = 365 + leapYearExtra - dayOfYear;
// Display the message
if (daysRemaining == 1) {
TodayMessage.Text = String.Format ("Today is day {0}. There is one day remaining in the year.", dayOfYear);
} else {
TodayMessage.Text = String.Format ("Today is day {0}. There are {1} days remaining in the year.", dayOfYear, daysRemaining);
}
}
Se estiver usando o método de interface do usuário baseado em código, substitua o // Insert code to power extension here...
comentário pelo novo código acima. Depois de chamar a implementação base (e inserir um Label para a versão baseada em código), esse código faz um cálculo simples para obter o dia do ano e quantos dias restam. Em seguida, ele exibe a mensagem no Rótulo (TodayMessage
) que você criou no design da interface do usuário.
Observe como esse processo é semelhante ao processo normal de escrever um aplicativo. Uma extensão tem o mesmo ciclo de vida que um controlador de exibição em um aplicativo, exceto que as extensões não têm modos em segundo plano e não são suspensas UIViewController
quando o usuário termina de usá-las. Em vez disso, as extensões são inicializadas e desalocadas repetidamente conforme necessário.
Criando a interface do usuário do aplicativo de contêiner
Para este passo a passo, o aplicativo de contêiner é simplesmente usado como um método para enviar e instalar a extensão e não fornece nenhuma funcionalidade própria. Edite o arquivo do Main.storyboard
TodayContainer e adicione algum texto definindo a função da extensão e como instalá-la:
Salve as alterações no Storyboard.
Testando a extensão
Para testar sua extensão no Simulador do iOS, execute o aplicativo TodayContainer . A exibição principal do contêiner será exibida:
Em seguida, aperte o botão Início no Simulador, deslize de cima para baixo na tela para abrir a Central de Notificações, selecione a guia Hoje e clique no botão Editar:
Adicione a extensão DaysRemaining à visualização Hoje e clique no botão Concluído :
O novo widget será adicionado à visualização Hoje e os resultados serão exibidos:
Comunicação com o aplicativo host
O exemplo de Extensão Hoje que você criou acima não se comunica com seu aplicativo host (a tela Hoje ). Se o fizesse, ele usaria a propriedade ExtensionContext das TodayViewController
classes or CodeBasedViewController
.
Para extensões que receberão dados de seus aplicativos host, os dados estão na forma de uma matriz de objetos NSExtensionItem armazenados na propriedade InputItems do ExtensionContext do arquivo .UIViewController
Outras extensões, como extensões de edição de fotos, podem distinguir entre o usuário concluir ou cancelar o uso. Isso será sinalizado de volta para o aplicativo host por meio dos métodos CompleteRequest e CancelRequest da propriedade ExtensionContext .
Para obter mais informações, consulte o Guia de Programação de Extensão de Aplicativo da Apple.
Comunicação com o aplicativo pai
Um grupo de aplicativos permite que diferentes aplicativos (ou um aplicativo e suas extensões) acessem um local de armazenamento de arquivo compartilhado. Grupos de aplicativo podem ser usados para dados como:
Para obter mais informações, consulte a seção Grupos de Aplicativos da nossa documentação Trabalhando com Recursos .
Serviços MobileCoreServices
Ao trabalhar com extensões, use um Uniform Type Identifier (UTI) para criar e manipular dados trocados entre o aplicativo, outros aplicativos e/ou serviços.
A MobileCoreServices.UTType
classe estática define as seguintes propriedades auxiliares relacionadas às definições da kUTType...
Apple:
kUTTypeAlembic
-Alembic
kUTTypeAliasFile
-AliasFile
kUTTypeAliasRecord
-AliasRecord
kUTTypeAppleICNS
-AppleICNS
kUTTypeAppleProtectedMPEG4Audio
-AppleProtectedMPEG4Audio
kUTTypeAppleProtectedMPEG4Video
-AppleProtectedMPEG4Video
kUTTypeAppleScript
-AppleScript
kUTTypeApplication
-Application
kUTTypeApplicationBundle
-ApplicationBundle
kUTTypeApplicationFile
-ApplicationFile
kUTTypeArchive
-Archive
kUTTypeAssemblyLanguageSource
-AssemblyLanguageSource
kUTTypeAudio
-Audio
kUTTypeAudioInterchangeFileFormat
-AudioInterchangeFileFormat
kUTTypeAudiovisualContent
-AudiovisualContent
kUTTypeAVIMovie
-AVIMovie
kUTTypeBinaryPropertyList
-BinaryPropertyList
kUTTypeBMP
-BMP
kUTTypeBookmark
-Bookmark
kUTTypeBundle
-Bundle
kUTTypeBzip2Archive
-Bzip2Archive
kUTTypeCalendarEvent
-CalendarEvent
kUTTypeCHeader
-CHeader
kUTTypeCommaSeparatedText
-CommaSeparatedText
kUTTypeCompositeContent
-CompositeContent
kUTTypeConformsToKey
-ConformsToKey
kUTTypeContact
-Contact
kUTTypeContent
-Content
kUTTypeCPlusPlusHeader
-CPlusPlusHeader
kUTTypeCPlusPlusSource
-CPlusPlusSource
kUTTypeCSource
-CSource
kUTTypeData
-Database
kUTTypeDelimitedText
-DelimitedText
kUTTypeDescriptionKey
-DescriptionKey
kUTTypeDirectory
-Directory
kUTTypeDiskImage
-DiskImage
kUTTypeElectronicPublication
-ElectronicPublication
kUTTypeEmailMessage
-EmailMessage
kUTTypeExecutable
-Executable
kUTExportedTypeDeclarationsKey
-ExportedTypeDeclarationsKey
kUTTypeFileURL
-FileURL
kUTTypeFlatRTFD
-FlatRTFD
kUTTypeFolder
-Folder
kUTTypeFont
-Font
kUTTypeFramework
-Framework
kUTTypeGIF
-GIF
kUTTypeGNUZipArchive
-GNUZipArchive
kUTTypeHTML
-HTML
kUTTypeICO
-ICO
kUTTypeIconFileKey
-IconFileKey
kUTTypeIdentifierKey
-IdentifierKey
kUTTypeImage
-Image
kUTImportedTypeDeclarationsKey
-ImportedTypeDeclarationsKey
kUTTypeInkText
-InkText
kUTTypeInternetLocation
-InternetLocation
kUTTypeItem
-Item
kUTTypeJavaArchive
-JavaArchive
kUTTypeJavaClass
-JavaClass
kUTTypeJavaScript
-JavaScript
kUTTypeJavaSource
-JavaSource
kUTTypeJPEG
-JPEG
kUTTypeJPEG2000
-JPEG2000
kUTTypeJSON
-JSON
kUTType3dObject
-k3dObject
kUTTypeLivePhoto
-LivePhoto
kUTTypeLog
-Log
kUTTypeM3UPlaylist
-M3UPlaylist
kUTTypeMessage
-Message
kUTTypeMIDIAudio
-MIDIAudio
kUTTypeMountPoint
-MountPoint
kUTTypeMovie
-Movie
kUTTypeMP3
-MP3
kUTTypeMPEG
-MPEG
kUTTypeMPEG2TransportStream
-MPEG2TransportStream
kUTTypeMPEG2Video
-MPEG2Video
kUTTypeMPEG4
-MPEG4
kUTTypeMPEG4Audio
-MPEG4Audio
kUTTypeObjectiveCPlusPlusSource
-ObjectiveCPlusPlusSource
kUTTypeObjectiveCSource
-ObjectiveCSource
kUTTypeOSAScript
-OSAScript
kUTTypeOSAScriptBundle
-OSAScriptBundle
kUTTypePackage
-Package
kUTTypePDF
-PDF
kUTTypePerlScript
-PerlScript
kUTTypePHPScript
-PHPScript
kUTTypePICT
-PICT
kUTTypePKCS12
-PKCS12
kUTTypePlainText
-PlainText
kUTTypePlaylist
-Playlist
kUTTypePluginBundle
-PluginBundle
kUTTypePNG
-PNG
kUTTypePolygon
-Polygon
kUTTypePresentation
-Presentation
kUTTypePropertyList
-PropertyList
kUTTypePythonScript
-PythonScript
kUTTypeQuickLookGenerator
-QuickLookGenerator
kUTTypeQuickTimeImage
-QuickTimeImage
kUTTypeQuickTimeMovie
-QuickTimeMovie
kUTTypeRawImage
-RawImage
kUTTypeReferenceURLKey
-ReferenceURLKey
kUTTypeResolvable
-Resolvable
kUTTypeRTF
-RTF
kUTTypeRTFD
-RTFD
kUTTypeRubyScript
-RubyScript
kUTTypeScalableVectorGraphics
-ScalableVectorGraphics
kUTTypeScript
-Script
kUTTypeShellScript
-ShellScript
kUTTypeSourceCode
-SourceCode
kUTTypeSpotlightImporter
-SpotlightImporter
kUTTypeSpreadsheet
-Spreadsheet
kUTTypeStereolithography
-Stereolithography
kUTTypeSwiftSource
-SwiftSource
kUTTypeSymLink
-SymLink
kUTTypeSystemPreferencesPane
-SystemPreferencesPane
kUTTypeTabSeparatedText
-TabSeparatedText
kUTTagClassFilenameExtension
-TagClassFilenameExtension
kUTTagClassMIMEType
-TagClassMIMEType
kUTTypeTagSpecificationKey
-TagSpecificationKey
kUTTypeText
-Text
kUTType3DContent
-ThreeDContent
kUTTypeTIFF
-TIFF
kUTTypeToDoItem
-ToDoItem
kUTTypeTXNTextAndMultimediaData
-TXNTextAndMultimediaData
kUTTypeUniversalSceneDescription
-UniversalSceneDescription
kUTTypeUnixExecutable
-UnixExecutable
kUTTypeURL
-URL
kUTTypeURLBookmarkData
-URLBookmarkData
kUTTypeUTF16ExternalPlainText
-UTF16ExternalPlainText
kUTTypeUTF16PlainText
-UTF16PlainText
kUTTypeUTF8PlainText
-UTF8PlainText
kUTTypeUTF8TabSeparatedText
-UTF8TabSeparatedText
kUTTypeVCard
-VCard
kUTTypeVersionKey
-VersionKey
kUTTypeVideo
-Video
kUTTypeVolume
-Volume
kUTTypeWaveformAudio
-WaveformAudio
kUTTypeWebArchive
-WebArchive
kUTTypeWindowsExecutable
-WindowsExecutable
kUTTypeX509Certificate
-X509Certificate
kUTTypeXML
-XML
kUTTypeXMLPropertyList
-XMLPropertyList
kUTTypeXPCService
-XPCService
kUTTypeZipArchive
-ZipArchive
Consulte o seguinte exemplo:
using MobileCoreServices;
...
NSItemProvider itemProvider = new NSItemProvider ();
itemProvider.LoadItem(UTType.PropertyList ,null, (item, err) => {
if (err == null) {
NSDictionary results = (NSDictionary )item;
NSString baseURI =
results.ObjectForKey("NSExtensionJavaScriptPreprocessingResultsKey");
}
});
Para obter mais informações, consulte a seção Grupos de Aplicativos da nossa documentação Trabalhando com Recursos .
Precauções e considerações
As extensões têm significativamente menos memória disponível do que os aplicativos. Espera-se que eles tenham um desempenho rápido e com o mínimo de intrusão no usuário e no aplicativo em que estão hospedados. No entanto, uma Extensão também deve fornecer uma função distinta e útil para o aplicativo de consumo com uma interface do usuário de marca que permita ao usuário identificar o desenvolvedor da Extensão ou o aplicativo de contêiner ao qual ele pertence.
Considerando esses requisitos rígidos, você só deve implantar extensões que tenham sido completamente testadas e otimizadas para desempenho e consumo de memória.
Resumo
Este documento abordou Extensões, o que são, o tipo de Pontos de Extensão e as limitações conhecidas impostas a uma Extensão pelo iOS. Ele discutiu a criação, distribuição, instalação e execução de extensões e o ciclo de vida da extensão. Ele forneceu um passo a passo da criação de um widget Today simples mostrando duas maneiras de criar a interface do usuário do widget usando Storyboards ou código. Ele mostrou como testar uma extensão no Simulador do iOS. Por fim, discutiu brevemente a comunicação com o Host App e algumas precauções e considerações que devem ser tomadas ao desenvolver uma extensão.