Série de Episódios sobre Mobile no Delphi Academy

Iniciamos recentemente uma série de episódios focados em Mobile no Delphi Academy.

Em 13/06, falamos sobre como iniciar com mobile no RAD, Delphi e C++ Builder (Iniciando com Aplicações Mobile Delphi e C++ Builder). Caso tenha perdido esta introdução, o vídeo está em nosso playlist. Neste episódio em particular, focado em conceitos, não há exemplos a serem baixados, mas os slides podem ser encontrados em nosso GitHub, bem como os exemplos de todos os demais episódios.

Hoje (27/06), o assunto foi relacionado com boas práticas na construção de interfaces para apps (Aplicações Mobile: Boas Práticas de UI), e o feedback foi excelente. A julgar pelo nível das perguntas, temos usuários criando aplicações extremamente avançadas com Delphi e C++ Builder para iOS e Android! Como de costume, o playlist e GitHub já estão atualizados com o vídeo de hoje e exemplos.

mobile

Mobile com Delphi e C++ Builder

 

No próximo episódio, programado para ser transmitido em 11/07, falaremos sobre acesso a dados no mobile, e então disponibilizaremos uma nova agenda com novos episódios. Dentre os assuntos em pauta, gostaríamos de avançar mais com a questão da UI e também acesso a dados, já que estes são assuntos com muitas possibilidades e variações, portanto merecem mais tempo.

Durante este planejamento, você está convidado a enviar sugestões de tópicos a serem abordados, simplesmente deixe seu comentário neste post e garanto que o mesmo será avaliado.

Abraços e até o próximo Delphi Academy!

Um Mecanismo de Cache de Dados para DataSnap

Hoje pela manhã, durante o Delphi Academy, discutimos sobre cache de dados para DataSnap. Basicamente o cenário onde você tem tabelas que sofrem nenhuma ou poucas alterações ao longo do período, as quais você não precisa refazer a consulta a todo tempo, para todos os usuários.

Estou disponibilizando o exemplo abaixo, mas em um resumo, temos o seguinte:

  • Em uma aplicação DataSnap REST, adicionar um DataModule e configurar seu LifeCycle para Server, no ServerContainer. Com isso, ele terá uma única instância durante o ciclo de vida da aplicação
  • Neste DataModule, coloque um MemTable (ou Clientdataset se preferir) para cada tabela que deseja manter em cache
  • Defina uma conexão ao banco, e métodos (ou componentes para a execução das queries) para executar as consultas e carregar as tabelas em memória
  • Adicione um TFDEventAlerter e faça as devidas configurações: http://docwiki.embarcadero.com/Libraries/Tokyo/en/FireDAC.Comp.Client.TFDEventAlerter
  • Crie triggers de INSERT/UPDATE/DELETE que fará o “POST_EVENT” com o nome do evento alertando que a tabela sofreu alguma alteração. Este mesmo mecanismo está disponível para a maioria dos banco de dados: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Database_Alerts_(FireDAC)
  • No evento do OnAlert do  TFDEventAlerter, faça o refresh das tabelas e atualização dos datasets em memória

Com isso, você tem um mecanismo seguro e prático para manter as tabelas em memória sempre atualizadas.

Screen Shot 2017-05-30 at 17.34.14Screen Shot 2017-05-30 at 17.34.21

Os exemplos atualizados estão nestes links:

 

RAD Studio no TDC São Paulo!

Call4Papers

Este ano a Embarcadero terá uma trilha Delphi e C++ Builder no TDC São Paulo, e nós estamos muito entusiasmados em poder mostrar todo o poder do RAD para Windows, Android, iOS, macOS e Linux!

Você que é fera em Delphi ou C++ Builder, e gostaria de palestrar no evento, este é o link para submissões (somente até o dia 30/05):

http://thedevconf.com.br/tdc/2017/saopaulo/call4papers

Desde já convidamos toda a comunidade a se inscrever e participar conosco no evento. A Embarcadero terá também um box onde estaremos apresentando cases de sucesso em aplicações mobile e multicamadas ao vivo!

Vem!

 

Exemplos Delphi Tour, Roadmap e mais…

O Delphi Tour acabou, mas as novidades da Embarcadero não!

Conforme prometido, neste link você encontra todos os exemplos utilizados durante o evento, e alguns adicionais: https://github.com/flrizzato/DelphiTour

flrizzato DelphiTour Repositório Delphi Tour Todas as edições iniciando por RAD Studio XE4

Estamos publicando também, no mesmo repositório, todos os exemplos das edições anteriores, iniciando pelo XE4. Fiquem a vontade para explorar!

Se tiver interesse nas mensagens gerais da apresentação, aqui temos também o PPT utilizado durante o evento:

Aproveitando este artigo, falamos durante o evento que teríamos o Roadmap atualizado em alguns dias, e aqui está ele: https://community.embarcadero.com/article/news/16519-rad-studio-roadmap-may-2018

Vale também a leitura dos comentários adicionais de nossos PMs sobre o Roadmap: https://community.embarcadero.com/blogs/entry/may-2017-roadmap-commentary-from-product-management

E para encerrar, mas não menos importante, teremos uma edição online do Delphi Tour (detalhes em breve), com tudo o que foi apresentado na edição presencial!

Uma vez mais, agradecemos a todos pela excelente público em todas as paradas, é realmente um privilégio poder falar com cada um de vocês.

 

Delphi Tour Report: Second Week

Image of the map

Delphi Tour Stops

During the second week of Delphi Tour I passed by Porto Alegre, Florianópolis, Chapecó and São Paulo.

Great public in all stops, and some important achievements. In the south of the country we have an active and vibrant community, and talking with the developers, we found some wonderful cases that we are going to publish as success cases in the upcoming months.

But the most surprising thing in my opinion are the universities we are adding to the academic program. In each city we heard about projects and researches done with RAD in schools and universities, and this model is something that we really want to replicate in the entire Latin America. This will not only educate new Delphi and C++ Builder developers, but also drive the innovation using our tools!

Special mention here to Unoesc, an university in Chapecó, and Guinter Pauli, Embarcadero MVP and teacher there. This is a place where the integration between the school and the companies established in the region really works.

As usual, let’s finish this report with some pictures from the stops, but also with a big “thank you” to everyone that in some manner made this happen!

Delphi Tour Report: Recife and Fortaleza

This week I was in Recife and Fortaleza, not for the beautiful beaches and sightseeing, but for the Delphi Tour!

Great audience as usual, and a lot of interest in our new compiler for Linux. People are really considering moving their servers (in special DataSnap) to this platform, in order to save some money with hosting, and improve the general performance as a plus.

Here are some pictures from the city as well from the venue.

Next week I’ll be in Porto Alegre, Florianópolis, Chapeço and São Paulo!

You can find the full schedule and the subscription page here:
http://embarcaderobr.com.br/tour/

Hope I can meet some of you in person in one of these stops! I’ll try to report in daily bases starting from next Tuesday, so stay tuned!

Um Chat via Bluetooth para Android, MacOS e Windows

File:ClassicBluetoothVsLowEnergyBluetooth.png

Introdução

A inspiração para este artigo surgiu durante uma POC que estamos fazendo com um cliente implementando uma solução RFID com mobile.

Mas qual a relação do RFID com Bluetooth? Bem, a principio nenhuma relação direta, exceto pelo fato de que a ampla maioria dos leitores RFID que suportam integração para mobile (Android) o fazem via comunicação Bluetooth SPP (serial port profile).

Bluetooth SPP é um dos muitos profiles suportados pela tecnologia Bluetooth. Na prática, estamos falando de comunicação serial (socket) sobre Bluetooth. Neste link você encontra uma lista de todos os profiles suportados oficialmente pelo Bluetooth standard, lembrando que diferentes devices suportam diferentes conjuntos de profiles.

Com isso chegamos ao chat via Bluetooth…

Bluetooth no Delphi e C++ Builder

O RAD Studio oferece suporte nativo para Bluetooth e BluetoothLE (low energy). Apenas para contextualizar, BluetoothLE é diferente de Bluetooth, e se presta a outras necessidadesd – principalmente a implementações de dispositivos IoT, como beacons e etc…

Voltando ao Bluetooth standard, este que você utiliza quando faz o pareamento de dois devices, ou ainda de seu smartphone com o rádio de seu carro, observe que no título do artigo não está mencionado suporte para iOS, e por uma razão bastante simples: o iOS não implementa Bluetooth SPP.

Por qual razão? Bem, perdemos a oportunidade de perguntar ao Steve (Jobs), então temos que nos contentar apenas com esta lista de profiles suportados: https://support.apple.com/en-us/HT204387.

Obviamente há uma explicação científica para o tema. Caso alguém saiba mais a respeito, acrescente aos comentários deste artigo!Com isso, o suporte a Bluetooth e BLE no RAD Studio também apresenta esta “limitação”, digamos assim.

Mais detalhes sobre versões e protocolos Bluetooth no Delphi e C++ estão neste link da documentação: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Using_Bluetooth.

Código pelo Amor de Deus?

Sim, já estamos chegando lá. Mas esta teoria é importante para compreender o que estamos fazendo.Para estabelecer uma conexão utilizando SPP, leia-se porta serial, utilizamos basicamente uma conexão socket, muito parecido com qualquer solução socket que você já tenha implementado.

Quando estabelecemos uma conexão socket via Bluetooth (formalmente um rfcomm server e respectivo client), devemos especificar um UUID. Esse cara funciona como um identificador único para que o client possa se conectar ao serviço correto, já que podemos criar múltiplos canais de comunicação de maneira simultânea. Uma boa discussão sobre este tema você encontra aqui: http://stackoverflow.com/questions/13964342/android-how-do-bluetooth-uuids-work.

Basicamente, existem algumas UUID previamente definidos (https://www.bluetooth.com/specifications/assigned-numbers/service-discovery), os quais atendem serviços específicos, e você pode definir seu próprio identificar para uma aplicação em particular.

Felizmente nosso TBluetooth implementa tudo o que precisamos, e de maneira simples – só pra variar 😉

Agora sim, código!

Antes de mais nada, lembre-se que os devices devem estar devidamente pareados para que a conexão Bluetooth ocorra. Existem forma de automatizar o pareamento, mas não para todas as plataformas.

Em linhas gerais, do ponto de vista do “client”, tudo que temos que fazer é estabelecer a conexão socket, e então enviar o que desejamos.Já do lado “server”, utilizaremos um TTask para manter o Socket Server “ouvindo” em segundo plano.

Este é o conceito geral.

Aqui temos o código de ambas as classes, um “writer” e um “reader“:

unit uBlueChat;

interface

uses SysUtils, System.Classes, System.StrUtils, System.Threading,
  System.Bluetooth, System.Types, System.Generics.Collections,
{$IFDEF MACOS}
  Macapi.CoreFoundation,
{$ENDIF}
  FMX.Memo;

type
  TTextEvent = procedure(const Sender: TObject; const AText: string;
    const aDeviceName: string) of object;

type
  TBlueChatWriter = class(TComponent)
  private
    fSendUUID: TGUID;

    fDeviceName: string;
    fBlueDevice: TBluetoothDevice;

    fSendSocket: TBluetoothSocket;
    procedure SetBlueDevice(Value: string);
  public
    constructor Create(AOwner: TComponent); override;

    function SendMessage(sMessage: string): boolean;
    property DeviceName: string read fDeviceName write SetBlueDevice;
  end;

type
  TBlueChatReader = class(TComponent)
  private
    fReadUUID: TGUID;

    fDeviceName: string;
    fTaskReader: ITask;

    fReadSocket: TBluetoothSocket;
    fServerSocket: TBluetoothServerSocket;

    FOnTextReceived: TTextEvent;
    procedure SetOnTextReceived(const Value: TTextEvent);
  public
    constructor Create(AOwner: TComponent); override;
    procedure StartReader;
    procedure StopReader;

    property OnTextReceived: TTextEvent read FOnTextReceived
      write SetOnTextReceived;
    property DeviceName: string read fDeviceName write fDeviceName;
  end;

implementation

{ TBlueChatSend }

const
  cTimeOut: integer = 5000;

function FindBlueDevice(DeviceName: string): TBluetoothDevice;
var
  i: integer;
  aBTDeviceList: TBluetoothDeviceList;
begin
  aBTDeviceList := TBluetoothManager.Current.CurrentAdapter.PairedDevices;
  for i := 0 to aBTDeviceList.Count - 1 do
    if aBTDeviceList.Items[i].DeviceName = DeviceName then
      exit(aBTDeviceList.Items[i]);
  Result := nil;
end;

constructor TBlueChatWriter.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  fBlueDevice := nil;
  fSendSocket := nil;

  fSendUUID := StringToGuid('{14800546-CF05-481F-BE41-4EC0246D862D}');
end;

function TBlueChatWriter.SendMessage(sMessage: string): boolean;
begin
  try
    try
      if fBlueDevice = nil then
        raise Exception.Create('Select a bluetooth device first...');

      fSendSocket := fBlueDevice.CreateClientSocket(fSendUUID, False);
      if fSendSocket = nil then
        raise Exception.Create('Cannot create client socket to ' + fDeviceName);

      fSendSocket.Connect;
      if fSendSocket.Connected then
        fSendSocket.SendData(TEncoding.ASCII.GetBytes(sMessage))
      else
        raise Exception.Create('Cannot connect to ' + fDeviceName);

      Result := True;
    except
      on E: Exception do
        raise Exception.Create('Exception raised sending message: ' +
          E.Message);
    end;
  finally
    if fSendSocket.Connected then
      fSendSocket.Close;
    FreeAndNil(fSendSocket);
  end;
end;

procedure TBlueChatWriter.SetBlueDevice(Value: string);
begin
  if Value <> fDeviceName then
  begin
    fDeviceName := Value;
    fBlueDevice := FindBlueDevice(fDeviceName);
    if fBlueDevice = nil then
      raise Exception.Create('Cannot find device ' + fDeviceName);
  end;
end;

{ TBlueChatRead }

constructor TBlueChatReader.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  fTaskReader := nil;
  fReadSocket := nil;
  fServerSocket := nil;

  fReadUUID := StringToGuid('{14800546-CF05-481F-BE41-4EC0246D862D}');
end;

procedure TBlueChatReader.SetOnTextReceived(const Value: TTextEvent);
begin
  FOnTextReceived := Value;
end;

procedure TBlueChatReader.StartReader;
var
  Data: TBytes;
begin
  if fServerSocket <> nil then
    FreeAndNil(fServerSocket);

  fServerSocket := TBluetoothManager.Current.CurrentAdapter.CreateServerSocket
    ('FMXBlueChat', fReadUUID, False);

  fTaskReader := TTask.Create(
    procedure()
    begin
      fReadSocket := nil;
      while (fTaskReader.Status <> TTaskStatus.Canceled) do
      begin
        try
          fReadSocket := fServerSocket.Accept(cTimeOut);
          if (fReadSocket <> nil) and (fReadSocket.Connected) then
          begin
            Data := fReadSocket.ReceiveData;
            if Length(Data) > 0 then
            begin
              if Assigned(FOnTextReceived) then
                FOnTextReceived(Self, TEncoding.ASCII.GetString(Data),
                  fDeviceName);
            end;
          end;
        except
          on E: Exception do
          begin
            FreeAndNil(fReadSocket);
            raise Exception.Create('Exception raised receiving message: ' +
              E.Message);
          end;
        end;
        FreeAndNil(fReadSocket);
      end;
    end);
  fTaskReader.Start;
end;

procedure TBlueChatReader.StopReader;
begin
  if fTaskReader <> nil then
    if fTaskReader.Status <> TTaskStatus.Canceled then
      fTaskReader.Cancel;
end;

end.

A interface visual, por sua vez, é algo bastante simples. Estou certo que você vai compreender facilmente como tudo está funcionando investigando o exemplo que estou disponibilizando nos links abaixo, mas o essencial mesmo está nestas classes.