Con il rilascio delle ultime versioni dell’SDK Cascades for BlackBerry 10 sono state implementate le parti mancanti delle API relative alla gestione dei DataProvider per le geolocalizzazioni di POI all’interno del controllo MapView. Fino ad oggi, se volevamo implementare nella nostra applicazione la visualizzazione di una mappa avevamo due scelte:
- utilizzare le API di Google, OpenStreetMap o Bing all’interno di una WebView
- utilizzare il componente MapView e costruire su di esso un layer (da mantenere allineato) sul quale visualizzare i POI.
Quest’ultimo ovviamente comportava un notevole lavoro sulla UI che come conseguenza portava a non avere la user experience che ci si aspetta da un’applicazione “nativa” sviluppata per BlackBerry 10.
Grazie al rilascio delle nuove API, abbiamo la possibilità di utilizzare pienamente le mappe BlackBerry e i relativi Provider, così da poter garantire all’utente la stessa esperienza d’uso delle mappe BlackBerry nella nostra applicazione.
Integrare il componente GeoLocation nella nostra applicazione è semplice e veloce. Supponiamo di avere un’applicazione che a seguito di una selezione dell’utente debba visualizzare una mappa con riportata la nostra posizione e quella della farmacia più vicina a noi.
Come prima cosa aggiungiamo nel file .PRO il riferimento alle seguenti librerie:
- lbbcascadesmaps
- lQtLocationSubset
- lGLESv1_CM
Queste librerie consentono di poter accedere al servizio di geolocalizzazione e alle mappe BlackBerry.
TEMPLATE = app
TARGET = app
CONFIG += qt warn_on debug_and_release cascades
INCLUDEPATH += ../src
SOURCES += ../src/*.cpp
HEADERS += ../src/*.hpp ../src/*.h
LIBS += -lbbsystem
LIBS += -lbb
LIBS += -lbbdevice
LIBS += -lbbdata -lbbcascadesmaps -lQtLocationSubset -lGLESv1_CM
lupdate_inclusion {
SOURCES += ../assets/*.qml
SOURCES += ../assets/component/*.qml
}
...
...
Aggiungiamo nel file “bar-descriptor.xml“, nella sezione Permission, l’autorizzazione a utilizzare il servizio di geolocalizzazione e l’accesso a internet
... ... <!-- Request permission to execute native code. Required for native applications. --> <permission system="true">run_native</permission> <permission>read_geolocation</permission> <permission>access_internet</permission> <permission>access_location_services</permission> ... ...
Adesso, aggiungiamo nella classe di avvio della nostra applicazione il codice che crea e associa i POI da geolocalizzare
...
...
#include <bb/cascades/maps/MapView>
#include <bb/cascades/maps/MapData>
#include <bb/cascades/maps/DataProvider>
#include <bb/platform/geo/Point>
#include <bb/platform/geo/GeoLocation>
#include <bb/platform/geo/Marker>
#include <bb/UIToolkitSupport>
...
...
using namespace bb::cascades::maps;
using namespace bb::platform::geo;
// start applicazione
HelpMe::HelpMe(bb::cascades::Application *app)
: QObject(app)
, m_appConfig(new AppConfig(this))
{
...
...
// Creo l'oggetto root dell'applicazione
AbstractPane *root = qml->createRootObject<AbstractPane>();
// recupero l'oggetto MapView
QObject* mapViewAsQObject = root->findChild<QObject*>(QString("mapViewPoiPharmacy"));
// se l'oggetto viene trovato, crea l'oggetto che visualizza la posizione del device
if (mapViewAsQObject) {
// cast dell'oggetto al tipo corretto
mapView = qobject_cast<bb::cascades::maps::MapView*>(mapViewAsQObject);
// imposta la visibilità del tasto "Naviga To..."
mapView->setCaptionGoButtonVisible(true);
// se l'oggetto mapView è valido, crea il PIN che identifica
// la posizione del device e lo aggiunge ai dati della mappa
if (mapView) {
// crea l'archivio dei dati della mappa
DataProvider* myDeviceLocDataProv = new DataProvider("my-device-location-data-provider");
// lo aggiunge alla mappa
mapView->mapData()->addProvider(myDeviceLocDataProv);
// crea il bullet
deviceLocation = new GeoLocation("current-position-id");
deviceLocation->setName("Posizione corrente");
deviceLocation->setDescription("Riporta la mia attuale posizione sulla mappa.");
// Per identificare diversamente la nostra posizione
// modifichiamo il simbolo del Marker (PIN del POI)
Marker myPosMarker = Marker(UIToolkitSupport::absolutePathFromUrl(
QUrl("asset:///images/my_position_mark.png")), QSize(60, 60),
QPoint(29, 29), QPoint(29, 1));
deviceLocation->setMarker(myPosMarker);
myDeviceLocDataProv->add(deviceLocation);
}
}
// attiva l'applicazione
app->setScene(root);
}
...
...
Aggiungiamo inoltre il metodo che si occuperà di visualizzare i POI dopo che il dispositivo avrà determinato la posizione corretta.
...
...
/*
* imposta la posizione corrente e quella del poi più vicino
*/
void HelpMe::updateDeviceLocation(double lat, double lon, double poiLat, double poiLon) {
// imposta la mia posizione
if (deviceLocation) {
deviceLocation->setLatitude(lat);
deviceLocation->setLongitude(lon);
}
mapView->setLatitude(lat);
mapView->setLongitude(lon);
// imposta la posizione del POI
GeoLocation *pharmPos = new GeoLocation("pharmacy-position-id");
pharmPos->setLatitude(poiLat);
pharmPos->setLongitude(poiLon);
pharmPos->setName("Posizione farmacia più vicina");
pharmPos->setDescription("Farmacia di test, via della Prova 5 - Monza");
mapView->mapData()->add(pharmPos);
}
...
...
A questo punto non resta che aggiungere nella nostra pagina QML che visualizza la mappa l’oggetto PositionSource per gestire il GPS.
...
...
attachedObjects: [
PositionSource {
// componente Qt per gestire il GPS
id: positionSource
updateInterval: 1000
// attiva/disattiva il GPS
active: retrieveGpsPosition
onPositionChanged: {
// quando la posizione viene individuata, le coordinate vengono lette, la mappa è
// resa visibile e il GPS viene spento. Quindi si richiama il C++ per
// visualizzare sulla mappa la nostra posizione e il POI più vicino
lat.text = positionSource.position.coordinate.latitude;
lon.text = positionSource.position.coordinate.longitude;
mapview.visible = true;
gpsLoadIndicator.stop();
retrieveGpsPosition = false;
_helpme.updateDeviceLocation(positionSource.position.coordinate.latitude, positionSource.position.coordinate.longitude, latitudePOI, longitudePOI);
}
}
]
...
...
Vediamo adesso il codice completo.
Sorgente “FindMe.qml”
/**
* FindMe.qml
*
* Summary: visualizza la mappa con la mia posizione e un la prima farmacia vicina
*
* Author: Nicola D'Amico
* Italian Developer for BlackBerry® smartphones
* Monza (MB) - Italy
*
* Date: 15.05.2013
*
* Twitter: http://twitter.com/WhiteSharkIT
* Linkedin: http://it.linkedin.com/in/nicoladamico
*
* Copyright © 2013-2018 Nicola D'Amico. All rights reserved.
*/
import bb.cascades 1.0
import QtMobility.sensors 1.2
import bb.cascades.maps 1.0
import QtMobilitySubset.location 1.1
Page {
// ------------------------------------------------------------------
// retrieveGpsPosition: indica se il GPS è attivo e deve essere
// trovata la posizione
// latitudePOI: latitudine della farmacia
// longitudePOI: longitudine della farmacia
// ------------------------------------------------------------------
property bool retrieveGpsPosition: false
property double latitudePOI: 45.58169
property double longitudePOI: 9.301695
Container {
id: root
layout: DockLayout {
}
// activityIndicator visualizzato durante la ricerca della posizione
ActivityIndicator {
id: gpsLoadIndicator
preferredWidth: 400
preferredHeight: 400
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
}
// componente MapView utilizzato per visualizzare i POI
MapView {
id: mapview
objectName: "mapViewPoiPharmacy"
altitude: _appConfig.Altitude
preferredWidth: _appConfig.DisplayWidth
preferredHeight: _appConfig.DisplayHeight
visible: false
}
// container che visualizza le coordinate della nostra posizione
Container {
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Top
topPadding: 5
leftPadding: 5
bottomPadding: 5
background: Color.create("#ddffffff")
Container {
layout: StackLayout {
orientation: LayoutOrientation.LeftToRight
}
horizontalAlignment: HorizontalAlignment.Center
Label {
// latitudine
id: lat
textStyle {
base: SystemDefaults.TextStyles.SmallText
color: Color.Black
fontWeight: FontWeight.Bold
}
}
Label {
// longitudine
id: lon
textStyle {
base: SystemDefaults.TextStyles.SmallText
color: Color.Black
fontWeight: FontWeight.Bold
}
}
}
}
}
attachedObjects: [
PositionSource {
// componente Qt per gestire il GPS
id: positionSource
updateInterval: 1000
// attiva/disattiva il GPS
active: retrieveGpsPosition
onPositionChanged: {
// quando la posizione viene individuata, le coordinate vengono lette, la mappa è
// resa visibile e il GPS viene spento. Quindi si richiama il C++ per
// visualizzare sulla mappa la nostra posizione e il POI più vicino
lat.text = positionSource.position.coordinate.latitude;
lon.text = positionSource.position.coordinate.longitude;
mapview.visible = true;
gpsLoadIndicator.stop();
retrieveGpsPosition = false;
_helpme.updateDeviceLocation(positionSource.position.coordinate.latitude, positionSource.position.coordinate.longitude, latitudePOI, longitudePOI);
}
}
]
actions: [
ActionItem {
title: qsTr("Chiudi")
ActionBar.placement: ActionBarPlacement.OnBar
imageSource: "asset:///images/ic_close.png"
onTriggered: {
findMeSheet.close();
}
},
ActionItem {
title: qsTr("Aiuto")
imageSource: "asset:///images/ic_help.png"
ActionBar.placement: ActionBarPlacement.InOverflow
onTriggered: {
helpView.open()
}
},
ActionItem {
title: qsTr("Aggiorna posizione GPS")
imageSource: "asset:///images/gps_fix_81.png"
ActionBar.placement: ActionBarPlacement.InOverflow
onTriggered: {
// impostando a true "retrieveGpsPosition" automaticamente si
// scatena l'evento che attiva il GPS
retrieveGpsPosition = true;
gpsLoadIndicator.start();
}
},
InvokeActionItem {
title: qsTr("Invia la posizione")
ActionBar.placement: ActionBarPlacement.InOverflow
query {
mimeType: "text/plain"
invokeActionId: "bb.action.SHARE"
}
onTriggered: {
// aggiungere il codice necessario per lo share
...
...
data = "[messaggio da inviare]"
...
...
}
}
]
}
Sorgente HelpMe.hpp
/**
* HelpMe.hpp
*
* Summary: header file della classe HelpMe.cpp
*
* Author: Nicola D'Amico
* Italian Developer for BlackBerry® smartphones
* Monza (MB) - Italy
*
* Date: 15.05.2013
*
* Twitter: http://twitter.com/WhiteSharkIT
* Linkedin: http://it.linkedin.com/in/nicoladamico
*
* Copyright © 2013-2018 Nicola D'Amico. All rights reserved.
*/
#ifndef HelpMe_HPP
#define HelpMe_HPP
#include <QtCore/QObject>
class AppConfig;
namespace bb { namespace cascades {class Application; namespace maps {class MapView;}}namespace platform {namespace geo {class GeoLocation;}}}
/*
* classe manager per l'accesso a tutte le informazioni dell'applicazione
* e renderle disponibili nella UI
*/
class HelpMe : public QObject
{
Q_OBJECT
// classe AppConfig
Q_PROPERTY(AppConfig* appConfig READ appConfig CONSTANT);
public:
HelpMe(bb::cascades::Application *app);
virtual ~HelpMe() {}
Q_INVOKABLE void updateDeviceLocation(double lat, double lon);
private:
// Classe che gestisce la configurazione dell'applicazione
AppConfig* appConfig() const;
AppConfig* m_appConfig;
bb::cascades::maps::MapView* mapView;
bb::platform::geo::GeoLocation* deviceLocation;
};
#endif
Sorgente HelpMe.cpp
/**
* HelpMe.cpp
*
* Summary: classe HelpMe start dell'applicazione
*
* Author: Nicola D'Amico
* Italian Developer for BlackBerry® smartphones
* Monza (MB) - Italy
*
* Date: 15.05.2013
*
* Twitter: http://twitter.com/WhiteSharkIT
* Linkedin: http://it.linkedin.com/in/nicoladamico
*
* Copyright © 2013-2018 Nicola D'Amico. All rights reserved.
*/
#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>
#include <bb/cascades/ActionItem>
#include <bb/cascades/Sheet>
#include <bb/cascades/NavigationPane>
#include <bb/cascades/VisualStyle>
#include <bb/cascades/ThemeSupport>
#include <bb/cascades/Theme>
#include <bb/cascades/ColorTheme>
#include <bb/ApplicationInfo>
#include <bb/data/DataSource>
#include <bb/data/SqlConnection>
#include <bb/cascades/maps/MapView>
#include <bb/cascades/maps/MapData>
#include <bb/cascades/maps/DataProvider>
#include <bb/platform/geo/Point>
#include <bb/platform/geo/GeoLocation>
#include <bb/platform/geo/Marker>
#include <bb/UIToolkitSupport>
#include <bb/system/SystemDialog>
#include <bb/system/SystemToast>
#include "HelpMe.hpp"
#include "AppConfig.hpp"
#include "SqlManager.hpp"
using namespace bb;
using namespace bb::cascades;
using namespace bb::cascades::maps;
using namespace bb::platform::geo;
// start applicazione
HelpMe::HelpMe(bb::cascades::Application *app)
: QObject(app)
, m_appConfig(new AppConfig(this))
{
// registro il systemDialog per poterlo utilizzare nell'UI
qmlRegisterType<bb::system::SystemDialog>("bb.system", 1, 0, "SystemDialog");
qmlRegisterType<bb::system::SystemToast>("bb.system", 1, 0, "SystemToast");
// registra le classi per essere utilizzate nei file QML
qmlRegisterType<AppConfig>();
qmlRegisterType<SqlManager>();
// creo il main
QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this);
// Passa le proprietà dell'applicazione alla UI
qml->setContextProperty("_helpme", this);
// inzializzo il sqlHelper per l'accesso al DB sqlite
SqlManager *sqlHelper = new SqlManager();
// Inizializza il database e intercetta lo stato
const bool dbInited = sqlHelper->initDatabase();
// Notifica lo stato alla UI
qml->setContextProperty("_sql", sqlHelper);
// Creo l'oggetto root dell'applicazione
AbstractPane *root = qml->createRootObject<AbstractPane>();
// recupero l'oggetto MapView
QObject* mapViewAsQObject = root->findChild<QObject*>(QString("mapViewPoiPharmacy"));
// se l'oggetto viene trovato, crea l'oggetto che visualizza la posizione del device
if (mapViewAsQObject) {
// cast dell'oggetto al tipo corretto
mapView = qobject_cast<bb::cascades::maps::MapView*>(mapViewAsQObject);
// imposta la visibilità del tasto "Naviga To..."
mapView->setCaptionGoButtonVisible(true);
// se l'oggetto mapView è valido, crea il PIN che identifica
// la posizione del device e lo aggiunge ai dati della mappa
if (mapView) {
// crea l'archivio dei dati della mappa
DataProvider* myDeviceLocDataProv = new DataProvider("my-device-location-data-provider");
// lo aggiunge alla mappa
mapView->mapData()->addProvider(myDeviceLocDataProv);
// crea il bullet
deviceLocation = new GeoLocation("current-position-id");
deviceLocation->setName("Posizione corrente");
deviceLocation->setDescription("Riporta la mia attuale posizione sulla mappa.");
// Per identificare diversamente la nostra posizione
// modifichiamo il simbolo del Marker (PIN del POI)
Marker myPosMarker = Marker(UIToolkitSupport::absolutePathFromUrl(
QUrl("asset:///images/my_position_mark.png")), QSize(60, 60),
QPoint(29, 29), QPoint(29, 1));
deviceLocation->setMarker(myPosMarker);
myDeviceLocDataProv->add(deviceLocation);
}
}
// attiva l'applicazione
app->setScene(root);
}
/*
* ritorna la classe AppConfig
*/
AppConfig* HelpMe::appConfig() const
{
return m_appConfig;
}
/*
* imposta la posizione corrente e quella del poi più vicino
*/
void HelpMe::updateDeviceLocation(double lat, double lon, double poiLat, double poiLon) {
// imposta la mia posizione
if (deviceLocation) {
deviceLocation->setLatitude(lat);
deviceLocation->setLongitude(lon);
}
mapView->setLatitude(lat);
mapView->setLongitude(lon);
// imposta la posizione del POI
GeoLocation *pharmPos = new GeoLocation("pharmacy-position-id");
pharmPos->setLatitude(poiLat);
pharmPos->setLongitude(poiLon);
pharmPos->setName("Posizione farmacia più vicina");
pharmPos->setDescription("Farmacia di test, via della Prova 5 - Monza");
mapView->mapData()->add(pharmPos);
}
Ed ecco il risultato finale:

Per chi desidera approfondire l’argomento, può trovare maggiori dettagli qui.
Nicola D’Amico
Italian Developer for BlackBerry® smartphones





