уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Первоначально этот пост задумывался как статья про работу с датчиком местоположения в Android, но по мере написания текста оказалось, что здесь собраны несколько моментов по взаимодействию с Android в Delphi XE5, которые не столь очевидны как, например, определение широты/долготы при использовании готового компонента TLocationSensor или получение списка всех доступных датчиков в устройстве, однако могут быть полезны при работе над проектом. Поэтому я и решил сменить название и представить вам несколько, на мой взгляд, полезных примеров по работе с Android, которые были частично написаны мной, а частично, собраны из разных уголков в Сети. Вполне возможно, что какая-то часть примеров может оказаться полезной и для участников конкурса мобильных приложений на Delphi.

Пример №1. Как получить список доступных поставщиков местоположения устройства?

В Android координаты местоположения (широта/долгота) могут определяться следующими способами:

  1. С использованием служб Google для определения координат по Wi-fi и мобильным сетям
  2. С использованием данных со спутников GPS
  3. В Delphi — с использованием компонента TLocationSensor

Настройка сервиса определения местоположения в Android выглядит следующим образом:

Screenshot_2013-12-19-21-50-18

 

Чтобы определить поставщиков местоположения (gps, сеть и т.д.) необходимо получить доступ к объекту LocationManager и  запросить список поставщиков, используя методы getAllProviders или getProviders. Первый метод вернет перечень всех поставщиков,. второй — только доступных для использования.

Пример получения всех провайдеров выглядит следующим образом:

uses FMX.Helpers.Android,
     Androidapi.JNI.Location, Androidapi.JNIBridge,
     Androidapi.JNI.GraphicsContentViewText,
     Androidapi.JNI.JavaTypes;
 
....
 
var LocManagerObj: JObject;
    LocationManager: JLocationManager;
    AllProviders: JList;
  I: Integer;
begin
  //запрашиваем сервис Location
  LocManagerObj:=SharedActivityContext.getSystemService(TJContext.JavaClass.LOCATION_SERVICE);
  if not Assigned(LocManagerObj) then
    raise Exception.Create('Could not locate Location Service');
  //получаем LocationManager
  LocationManager:=TJLocationManager.Wrap((LocManagerObj as ILocalObject).GetObjectID);
  if not Assigned(LocationManager) then
    raise Exception.Create('Could not access Location Manager');
  //запрашиваем список всех провайдеров
  AllProviders:=LocationManager.getAllProviders;
  //выводим список
  if Assigned(AllProviders) then
    begin
      for I := 0 to AllProviders.size-1 do
        Memo1.Lines.Add(JStringToString(AllProviders.get(i).toString));
    end;
end;

Пример №2. Как получить сведения о текущем местоположении устройства (город, улица, дом и т.д.)

Пример использования готовых классов в Delphi XE5 вы можете изучить на сайте Embarcadero — здесь. Если же вам хочется воспользоваться для этой цели Android API, то, опять же, потребуется получить доступ к LocationManager (как в первом примере) и выполнить следующие операции:

var LocManagerObj: JObject;
    LocationManager: JLocationManager;
    LastLocation: JLocation;
    Geocoder: JGeocoder;
    Address: JAddress;
    AddressList: JList;
begin
  //запрашиваем сервис Location
  LocManagerObj:=SharedActivityContext.getSystemService(TJContext.JavaClass.LOCATION_SERVICE);
  if not Assigned(LocManagerObj) then
    raise Exception.Create('Could not locate Location Service');
  //получаем LocationManager
  LocationManager:=TJLocationManager.Wrap((LocManagerObj as ILocalObject).GetObjectID);
  if not Assigned(LocationManager) then
    raise Exception.Create('Could not access Location Manager');
  //получаем последнее местоположение зафиксированное с помощью координат wi-fi и мобильных сетей
  LastLocation:=LocationManager.getLastKnownLocation(TJLocationManager.JavaClass.NETWORK_PROVIDER);
  if Assigned(LastLocation) then
    begin
      geocoder:= TJGeocoder.JavaClass.init(SharedActivityContext);
      if not Assigned(geocoder) then
         raise Exception.Create('Could not access Geocoder');
      //пробуем определить 1 возможный адрес местоположения
      AddressList:=geocoder.getFromLocation(LastLocation.getLatitude, LastLocation.getLongitude,1);
     if AddressList.size>0 then
     begin
       Address:=TJAddress.Wrap((AddressList.get(0) as ILocalObject).GetObjectID);
       if not Assigned(Address) then
         raise Exception.Create('Could not access Address');
       //выводим данные в memo
       Memo1.Lines.Add('City: '+JStringToString(Address.getAddressLine(1)));
       Memo1.Lines.Add('Street: '+JStringToString(Address.getAddressLine(0)));
       Memo1.Lines.Add('PostalCode: '+JStringToString(Address.getAddressLine(4)));
     end;
    end;
end;

Для того, чтобы использовать Geocoder приложение должно иметь доступ в интернет и доступ к данным о местоположении. Для работы с разрешениями для приложения необходимо воспользоваться следующими настройками в IDE: Project -> Options -> Uses Permissions

uses_permissionsПример №3.  Как узнать имеется ли доступ в интернет (включен ли wi-fi или мобильный интернет)

За эту информацию в Android отвечает объект ConnectivityManager. К сожалению готовых оберток для этого менеджера я в Delphi не нашел, поэтому пришлось воспользоваться чужим кодом, в котором разрабатываются собственные интерфейсы для доступа к ConnectivityManager и функции для получения сведений о состоянии подключений к интернету:

unit Network;
 
interface
 
function IsConnected: Boolean;
 
function IsWiFiConnected: Boolean;
 
function IsMobileConnected: Boolean;
 
implementation
 
uses
  System.SysUtils,
  Androidapi.JNIBridge,
  Androidapi.JNI.GraphicsContentViewText,
  Androidapi.JNI.JavaTypes,
  FMX.Helpers.Android, Misc;
 
type
  JConnectivityManager = interface;
  JNetworkInfo = interface;
 
  JNetworkInfoClass = interface(JObjectClass)
  ['{E92E86E8-0BDE-4D5F-B44E-3148BD63A14C}']
  end;
 
  [JavaSignature('android/net/NetworkInfo')]
  JNetworkInfo = interface(JObject)
  ['{6DF61A40-8D17-4E51-8EF2-32CDC81AC372}']
    {Methods}
    function isAvailable: Boolean; cdecl;
    function isConnected: Boolean; cdecl;
    function isConnectedOrConnecting: Boolean; cdecl;
  end;
  TJNetworkInfo = class(TJavaGenericImport<JNetworkInfoClass, JNetworkInfo>) end;
 
  JConnectivityManagerClass = interface(JObjectClass)
  ['{E03A261F-59A4-4236-8CDF-0068FC6C5FA1}']
    {Property methods}
    function _GetTYPE_WIFI: Integer; cdecl;
    function _GetTYPE_WIMAX: Integer; cdecl;
    function _GetTYPE_MOBILE: Integer; cdecl;
    {Properties}
    property TYPE_WIFI: Integer read _GetTYPE_WIFI;
    property TYPE_WIMAX: Integer read _GetTYPE_WIMAX;
    property TYPE_MOBILE: Integer read _GetTYPE_MOBILE;
  end;
 
  [JavaSignature('android/net/ConnectivityManager')]
  JConnectivityManager = interface(JObject)
  ['{1C4C1873-65AE-4722-8EEF-36BBF423C9C5}']
    {Methods}
    function getActiveNetworkInfo: JNetworkInfo; cdecl;
    function getNetworkInfo(networkType: Integer): JNetworkInfo; cdecl;
  end;
  TJConnectivityManager = class(TJavaGenericImport<JConnectivityManagerClass, JConnectivityManager>) end;
 
function GetConnectivityManager: JConnectivityManager;
var
  ConnectivityServiceNative: JObject;
begin
  ConnectivityServiceNative := SharedActivityContext.getSystemService(TJContext.JavaClass.CONNECTIVITY_SERVICE);
  if not Assigned(ConnectivityServiceNative) then
    raise Exception.Create('Could not locate Connectivity Service');
  Result := TJConnectivityManager.Wrap(
    (ConnectivityServiceNative as ILocalObject).GetObjectID);
  if not Assigned(Result) then
    raise Exception.Create('Could not access Connectivity Manager');
end;
 
function IsConnected: Boolean;
var
  ConnectivityManager: JConnectivityManager;
  ActiveNetwork: JNetworkInfo;
begin
  ConnectivityManager := GetConnectivityManager;
  ActiveNetwork := ConnectivityManager.getActiveNetworkInfo;
  Result := Assigned(ActiveNetwork) and ActiveNetwork.isConnected;
end;
 
function IsWiFiConnected: Boolean;
var
  ConnectivityManager: JConnectivityManager;
  WiFiNetwork: JNetworkInfo;
begin
  ConnectivityManager := GetConnectivityManager;
  WiFiNetwork := ConnectivityManager.getNetworkInfo(TJConnectivityManager.JavaClass.TYPE_WIFI);
  Result := WiFiNetwork.isConnected;
end;
 
function IsMobileConnected: Boolean;
var
  ConnectivityManager: JConnectivityManager;
  MobileNetwork: JNetworkInfo;
begin
  ConnectivityManager := GetConnectivityManager;
  MobileNetwork := ConnectivityManager.getNetworkInfo(TJConnectivityManager.JavaClass.TYPE_MOBILE);
  Result := MobileNetwork.isConnected;
end;
 
end.
Источник информации: StackOverflow

Пример №4. Как открыть ссылку или документ в приложении по умолчанию?

В Windows для этой цели имеется ShellExecute. В Android можно написать свой аналог, используя следующий код:

Открытие URL в браузере по умолчанию:

var
  Intent: JIntent;
begin
  Intent := TJIntent.Create;
  Intent.setAction(TJIntent.JavaClass.ACTION_VIEW);
  Intent.setData(StrToJURI('http://www.google.com'));
  SharedActivity.startActivity(Intent);
end;

И в заключении, на мой взгляд, довольно интересный пост в Google+ от нашего зарубежного коллеги о том как использовать библиотеки Java при работе в XE5.

По мере возможностей буду этот список примеров расширять, так что, как говориться — оставайтесь с нами :)

Книжная полка

Описание Подробно рассматривается библиотека FM, позволяющая создавать полнофункциональное программное обеспечение для операционных систем Windows и OS X, а также для смартфонов и планшетных компьютеров, работающих под управлением Android и iOS
купить книгу delphi на ЛитРес
Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
16 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
kdv
kdv
21/12/2013 01:40

А зачем понадобилось какое-то JNI? Ведь TLocationSensor и так есть — пример в папке MobileCodeSnippets.

kdv
kdv
21/12/2013 03:07

понял. Но я бы упомянул в посте. Потому что многие (и даже я) не в курсе штатного метода, пока носом не ткнут :-)
А так они будут считать, что для LocationService надо обязательно подключать JNI (кстати, что это, я вообще не в курсе), и т.п.

kdv
kdv
21/12/2013 03:50

спасибо, значит я по диагонали читал…

MNV
MNV
09/01/2014 05:54

А сколько весят результирующие apk? Также как на десктопе?

PeHa
PeHa
29/01/2014 15:06

В примере-2 вы использовали:LastLocation:=LocationManager.getLastKnownLocation(TJLocationManager.JavaClass.NETWORK_PROVIDER);
а если написать:LastLocation:=LocationManager.getLastKnownLocation(TJLocationManager.JavaClass.GPS_PROVIDER);
GPS всетаки GPS сработает? Я хочу узнать точное местоположения!! заранее спасибо!!!

PeHa
PeHa
30/01/2014 16:01
Ответить на  Vlad

LocManagerObj:=SharedActivityContext.getSystemService(TJContext.JavaClass.LOCATION_SERVICE);
LocationManager:=TJLocationManager.Wrap((LocManagerObj as ILocalObject).GetObjectID);
LastLocation:=LocationManager.getLastKnownLocation(TJLocationManager.JavaClass.GPS_PROVIDER);
memo1.Lines.Add(‘lat=’+floattostr(Lastlocation.getLatitude));
memo1.Lines.Add(‘lon=’+floattostr(Lastlocation.getLongitude));
Андроид выдает ошибку «Access Violation at address 42AA2F4E….»
GPS датчик влючен!!!
Или я неправильно сделал??

seka
seka
01/09/2014 03:07

Не подскажете как пример №2 (там где получение координат) переписать для C++? Пробую на XE6. Спасибо.

Евгений
Евгений
03/12/2014 02:13

Пытаюсь откомпилировать Ваш проект, но не получается, выдает 10 ошибок. Что не так делаю? Все вставляю тупо копи пастом.

Сергей Плахов
01/02/2015 01:26

Пример №3. Как узнать имеется ли доступ в интернет

НЕ РАБОЧИЙ!!!

1. Буржуйский автор вставил какой-то модуль Misc, но это пол беды и без него компилится.
2. При вызове любой из ф-ций программа зависает. Где-то в дебрях кода выполнение уходит в бесконечный цикл по ассемблерным инструкциям.

Vlad вы же программист! Бросьте эти блогерские повадки накопипастить материала не заботясь о его содержании.
К тому же dfit Ctrl+C — Ctrl+V вас подвели:
ваша строка: TJNetworkInfo = class(TJavaGenericImport<JNetworkInfoClass, JNetworkInfo>) end;
строка автора TJNetworkInfo = class(TJavaGenericImport) end;
Хорошо хоть ссылку на оригинал привели.