Press enter to see results or esc to cancel.

Atualizando seu projeto Xamarin Forms para o Prism 7

O Prism é um framework para desenvolvimento utilizando o padrão MVVM. Ele se encaixa muito bem no Xamarin Forms e possui diversos métodos já prontos que nos auxiliam a realizar diversas tarefas como navegação, bindings entre outros e ajuda a deixar a aplicação mais testável.

O Prism é open source e você pode acompanhar as issues, commites e todo o codigo fonte no GitHub.

Neste post irei tratar da migração da versão 6 para a 7. Caso você queira saber mais sobre o Prism clique aqui

O que há de novo?

Entre a disponibilização da ultima versão estável do Prism, 6.3.0, para a versão 7, se passaram 10 meses. Neste periodo a equipe que mantém o Prism colheu diversos feedbacks com a comunidade, corrigindo erros, aceitando contribuições de código da comunidades e desenvolvendo muitas melhorias.

Neste nova versão do Prism, muita coisa mudou. Existem alguns breaking changes que precisam ser alterados no código e você pode ver mais sobre eles nas releases notes clicando aqui.

Entre as melhorias, podemos destacar o suporte a .Net Standart, mudança na navegação de páginas com abas, remoção de páginas da stack de navegação e abstração do container de dependências.

Atualizando tudo

O primeiro passo para fazer a atualização é atualizar os pacotes nuget Prism.Forms, Prism.Unity e Prism.Core para a versão 7. Após feito isto, vc irá ver que seu projeto não compila mais..

Vamos realizar algumas mudanças para adequar a aplicação a nova versão do Prism, a maior parte destas mudanças serão realizadas no App.xaml.cs.

IPlatformInitializer

O primeiro passo e alterar o namespace de IPlatformInitializer de Microsoft.Practices.Unity para Prism. Isto é necessário devido a abstração do container e remoção da dependencia direta do container do Prism.

Você precisará realizar a mesma alteração nos Initializers que criamos em cada plataforma que também herdam de IPlatformInitializer (AndroidInitializer e iOSInitializer)

RegisterTypes – Registrando as páginas

Após isto, vamos refatorar o método RegisterTypes. Na versão 6 do Prism este método era implementado sem receber nenhum parametro. Na versão 7 ele passa a ter o parametro containerRegistry do tipo IContainerRegistry . Esta mudança ocorre para que o Prism fique independente de plataforma de container que a pessoa desenvolvedora escolher para usar. Desta forma, o registro de págians e a localização de ViewModels ficará a cargo do Prism. Repare que uma nova namespace foi adicionada a Prism.Ioc. Esta separação também ajuda em manter as responsabilidades do Prism e do Container de depencias isoladas.

Portanto, o registro de páginas e view models agora ficará a cargo do método RegisterForNavigation do objeto containerRegistry

Registrando os tipos

Após registradas as páginas e view models, vamos registrar nossas interfaces. Vou considerar o uso do container de injeção de dependencias Unity.

Atualize o pacote do Unity para a versão 5.5.5 ou maior.

Após ataulizar o pacote do Unity, vamos voltar a página App.xaml.cs para alterar o registro das interfaces. Até o momento, as interfaces estavam sendo registradas no objeto Container e caso quisessemos acessar o container em outro lugar do código prisavamos de uma propriedade do tipo IUnityContainer que recebia o objeto Container ao fim de todos os registros.

O registro dos nossos objetos no container de dependências será feito através container que é retornado pelo método GetContainer() do obejeto containerRegistry. Este método irá retornar a instância atual do container para manipulação. O objeto Container que era utilizado anteriormente para esta função, na versão 7 é apenas para resolver tipos e não registrá-los.
As dependências containuarão sendo registradas pelo método RegisterType como ocorria na versão 6, mas através do container retornado pelo método GetContainer()

Caso você precise acessar o container de fora da classe App.xaml.cs, crie uma nova variável do tipo IUnityContainer e atribua o retorno de GetContainer a ela. Faça esta atribuição ao fim de todos os registros de tipos para garantir que você está com a versão da instãncia do container que contém todas as dependências registradas. Veja abaixo:

Criando a variável IUnityContainer

public static IUnityContainer _unityContainer { get; set; }

Atribuindo o container atual a variavel exposta para acesso externo

containerRegistry.GetContainer().RegisterType(typeof(ICurrentDateService), typeof(CurrentDateService));

_unityContainer = containerRegistry.GetContainer() as UnityContainer;

Existem diversas outras mudanças que aconteceram nesta troca de versão. Neste post tentei citar o necessário para fazer sua aplicação rodar. Se você quiser ler mais sobre a atualização e mais coisas que você pode migrar no seu código fonte, não deixe de conferir o artigo da XamGirl e do Brian Lagunas.

Todas as mudanças também estão disponíveis nos Release Notes do Prism, veja aqui

App.xaml.cs antes da atualização

using Microsoft.Practices.Unity;
using Prism.Unity;
using UpdatePrism.ApplicationServices;
using UpdatePrism.ApplicationServices.Interfaces;
using Xamarin.Forms;

namespace UpdatePrism
{
    public partial class App : PrismApplication
    {
        public static IUnityContainer _unityContainer { get; set; }

        public App(IPlatformInitializer initializer) : base(initializer) { }
        
        protected override void OnInitialized()
        {
            InitializeComponent();

            MainPage = new NavigationPage(new MainPage());
        }

        protected override void RegisterTypes()
        {
            //Register Types
            Container.RegisterType(typeof(ICurrentDateService), typeof(CurrentDateService));

            //Register Pages
            Container.RegisterTypeForNavigation<MainPage, MainPageViewModel>();

            //Set Container to Unity Container for use out of App class
            _unityContainer = Container;
        }
    }
}

App.xaml.cs depois da atualização

using Prism;
using Prism.Ioc;
using Prism.Unity;
using Unity;
using UpdatePrism.ApplicationServices;
using UpdatePrism.ApplicationServices.Interfaces;
using Xamarin.Forms;

namespace UpdatePrism
{
    public partial class App : PrismApplication
    {
        public static IUnityContainer _unityContainer { get; set; }

        public App(IPlatformInitializer initializer) : base(initializer) { }
        
        protected override void OnInitialized()
        {
            InitializeComponent();

            MainPage = new NavigationPage(new MainPage());
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            //Register Types
            containerRegistry.RegisterForNavigation<MainPage, MainPageViewModel>();

            //Register Pages
            containerRegistry.GetContainer().RegisterType(typeof(ICurrentDateService), typeof(CurrentDateService));

            //Set Container to Unity Container for use out of App class
            _unityContainer = containerRegistry.GetContainer() as UnityContainer;
        }
    }
}

Você pode baixar o código fonte do exemplo deste post no meu GitHub.

Linker?

Se você usava Link all / Sdk and User assemblys no seu projeto, após a migração ele também terá parado de funcionar.

Caso você não conheça o funcionamento do Linker e como ele pode ajudar o app, leia o excelente artigo do Mahmoud Ali clicando aqui

Atualizar o arquivo de ignore do linker é um processo moroso e complicado. Após algum tempo, cheguei nesta configuração:

<?xml version="1.0" encoding="UTF-8" ?>
<linker>
    <assembly fullname="Prism.Forms">
        <type fullname="Prism.Common.ApplicationProvider" preserve="all" />
        <type fullname="Prism.Services.PageDialogService" preserve="all" />
        <type fullname="Prism.Services.DeviceService" preserve="all" />
        <type fullname="Prism.Ioc*" preserve="all" />
        <type fullname="Prism.Modularity*" preserve="all" />
        <type fullname="Prism.Navigation*" preserve="all" />
        <type fullname="Prism.Behaviors.PageBehaviorFactory" preserve="all">
            <method name=".ctor" />
        </type>
        <type fullname="Prism.Services.DependencyService" preserve="all">
            <method name=".ctor" />
        </type>
    </assembly>

    <assembly fullname="Prism">
        <type fullname="Prism.Navigation*" preserve="all" />
        <type fullname="Prism.Logging.EmptyLogger" preserve="all">
            <method name=".ctor" />
        </type>
    </assembly>

    <assembly fullname="Unity.Abstractions">
        <type fullname="*" />
    </assembly>

    <assembly fullname="Unity.Container">
        <type fullname="*" />
    </assembly>
</linker>

Com estes arquivos sendo ignorados o app ficou um pouco menor do que antes da atualização de versão e rodou normalmente.

Conclusão

A atualização do Prism permitiu maior flexibilidade na escolha do container de dependencias e também atualizou diversos recursos que estavam obsoletos na versão 6. Trouxe muitas melhorias como navagação de abas e o suporte a .net standart. Um problema da atualização foi a grande quantidade de breaking changes, mas com paciência conseguimos contorná-los.

 

Imagem utilizada no post Pixabay

 

#Ubuntu

 

Referências

Site Brian Lagunas

Xam Girl Blog

Release Notes

Tweet about this on TwitterShare on FacebookShare on LinkedInEmail this to someone
Comments

Leave a Comment