Leggere e produrre Barcode con Delphi XE5 (Android)
UPDATE: Nuovo blog post con la versione XE7
Introduzione
A costo di un certo livello di dipendenza da questa applicazione di terzi, il beneficio è di poterla sfruttare al massimo con poco sforzo, realizzando facilmente funzionalità che potrebbero essere sufficienti in un buon numero di situazioni.
Pro e contro
Contro
- Si genera una dipendenza con Barcode Scanner (anche se solo per quanto riguarda le funzionalità di lettura/produzione di barcode, non per l’esecuzione in sè della vostra app): i vostri utenti dovranno installare sui loro dispositivi anche questa applicazione (attualmente gratuita);
- La funzionalità di lettura (scan) dei barcode si basa sull’assunto che Barcode Scanner di chiuda dopo aver scansionato un codice e copi il codice letto nella clipboard del dispositivo; se future versioni dell’applicazione dovessero comportarsi diversamente, la vostra applicazione potrebbe non funzionare;
- questa soluzione non è crossplatform (è valida solo per Android)
Pro
- Tutta la complessità di implementazione viene delegata a Barcode Scanner (incluso il supporto a numerosi formati di codici a barre e la gestione della camera);
- Non è necessaria alcuna libreria di terze parti da compilare con la vostra applicazione;
- Sia la lettura che la produzione di codici a barre si risolve con una manciata di righe di codice!
Altri approcci e link di riferimento
- Articolo di Fernando Rizzatto (iOS, ZBar SDK)
- Video di Jim McKeeth (iOS + Android)
- Articolo di Pawel Glowacki sulla gestione degli eventi delle applicazioni
Intent
- Androidapi.JNI.GraphicsContentViewText, dove è definito il wrapper JIntent;
- Androidapi.JNI.JavaTypes, dove troviamo SharedActivity (una JActivity);
- FMX.Helpers.Android, che offre funzioni di utilità come StringToJString.
Primo step: produzione di un codice a barre
procedure TForm1.ButtonProduceClick(Sender: TObject);
var
Intent: JIntent;
begin
Intent := TJIntent.JavaClass.init(StringToJString('com.google.zxing.client.android.ENCODE'));
Intent.setPackage(StringToJString('com.google.zxing.client.android'));
Intent.putExtra(StringToJString('ENCODE_TYPE'), StringToJString('TEXT_TYPE'));
Intent.putExtra(StringToJString('ENCODE_FORMAT'), StringToJString(ComboBoxFormat.Items[ComboboxFormat.ItemIndex]));
Intent.putExtra(StringToJString('ENCODE_DATA'), StringToJString(Memo1.Lines.Text));
SharedActivityContext.startActivity(Intent);
end;
- Il valore ENCODE_DATA rappresenta il contenuto che vogliamo rendere con il barcode (ed è il contenuto di un memo presente sulla form della nostra applicazione);
- ENCODE_FORMAT rappresenta il tipo di codice a barre che vogliamo produrre (nel nostro esempio è preso da un combobox sulla form). I formati supportati attualmente sono i seguenti:
“UPC_A”, “UPC_E”, “EAN_8”, “EAN_13”, “CODE_39”, “CODE_93”, “CODE_128”, “ITF”, “RSS_14”, “RSS_EXPANDED”, “QR_CODE”, “DATA_MATRIX”.
var
Intent: JIntent;
begin
// empty the clipboard (to be sure not to match previous results)
FClipBoardService.SetClipboard('');
W aitingForResults := True;
// launch Barcode Scanner in SCAN mode
Intent := TJIntent.JavaClass.init(StringToJString('com.google.zxing.client.android.SCAN'));
Intent.setPackage(StringToJString('com.google.zxing.client.android'));
Intent.putExtra(StringToJString('SCAN_MODE'), StringToJString('ONE_D_MODE,QR_CODE_MODE,PRODUCT_MODE,DATA_MATRIX_MODE'));
SharedActivityContext.startActivity(Intent);
end;
Usiamo quindi un semplice workaround: intercettiamo l’evento che ci segnala che la nostra applicazione è di nuovo in primo piano (ottimo articolo di Pawel Glowacki) e leggiamo il contenuto degli appunti per catturare il testo corrispondente al barcode letto da Barcode Scanner.
Codice per agganciare gli eventi dell’applicazione e per ottenere un riferimento alla clipboard:
procedure TForm1.FormCreate(Sender: TObject);
begin
FWaitingForResults := False;
if not TPlatformServices.Current.SupportsPlatformService(IFMXClipboardService, IInterface(FClipBoardService)) then
raise Exception.Create('Cannot get access to clipboard service!');
if not TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, IInterface(FApplicationEventService)) then
raise Exception.Create('Cannot get application event service');
FApplicationEventService.SetApplicationEventHandler(ApplicationEventHandler);
end;
Codice per l’event-handler dei cambi di stato dell’applicazione:
function TForm1.ApplicationEventHandler(AAppEvent: TApplicationEvent;
AContext: TObject): Boolean;
var
LClipboardContent: string;
LFound: Boolean;
begin
case AAppEvent of
aeBecameActive:
begin
if WaitingForResults then
begin
WaitingForResults := False;
LClipboardContent := FClipBoardService.GetClipboard.AsString;
LFound := LClipboardContent <> '';
if LFound then
Log('Scan successful: ' + LClipboardContent)
else
Log('Scan failed (please retry)');
end;
end;
end;
Result := True;
end;
La procedura Log non fa altro che scrivere nel Memo della form principale.
Conclusioni e materiale
Questo è tutto. Come vedete si tratta di poche righe di codice e il meccanismo è semplice ma efficace.
Se le vostre esigenze di leggere e produrre barcode non sono particolarmente eccessive, un approccio come quello illustrato dovrebbe essere una soluzione sufficiente nella maggioranza dei casi.
Link: Codice sorgente Delphi XE5
Link: Demo APK (da installare sul vostro dispositivo Android)
UPDATE: Nuovo blog post con la versione XE7
Buon lavoro e a presto!
Andrea
Salve Andrea,
qualche altra soluzione senza usare il Barcode Scanner? qualche cosa diretta?
Saluti
Bleri
Nella sezione "Altri approcci" di questo blog post, ci sono link al lavoro di Fernando Rizzato e al video di Jim McKeeth in cui si usa la libreria ZXing compilandola direttamente nella app Delphi.
Così non si hanno dipendenze da applicazioni di terze parti come Barcode Scanner.
Buon lavoro e a presto,
Andrea
Grazie Andrea
Ottimo Articolo e il sorgente funziona sia su XE6 che XE7.
I would like to use the lib https://sourceforge.net/p/zbar/news/2012/03/zbar-android-sdk-version-01-released/ with delphi XE5, but the lib and. Jar and. So, You can use it with delphi XE5, how do? I need to read the barcode on my webcam!