Как реализовать отслеживание местоположения андроид устройства на своем сайте

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Занимаюсь грузоперевозками на своей газели, и у меня родилась идея сделать функцию отслеживания своего местоположения для всех посетителей своего сайта. Это очень удобно для тех, кто следит за своим грузом или тех, кто ждет машину. У меня получилось. И в этом посте я расскажу вам как реализовать эту функцию, которая, кстати, обойдется совсем недорого. Статья предназначена для людей, которые почти не имеют опыта в сфере создания сайтов и программировании в целом.

Вам понадобится:

  • Редактор Visual Studio Code

  • Среда разработки Android Studio

  • Аккаунт Гугл для API Google Maps

  • Доменное имя и хостинг с базой данных SQL

  • Обычный телефон на андроиде

Для начала рассмотрим схему взаимодействия всех элементов.

После того как пользователь заходит на сайт, активируется подключенный в index.html файл myJsCode.js, в котором каждые 2 секунды идет обращение в google maps. В google maps передаются координаты текущего местоположения, которые хранятся в базе данных sql. Google maps возвращает карту с маркером, установленным в точке, соответствующей переданным координатам. Считывание новых координат из базы данных осуществляется в myJsCode.js через coordinatesToBrowser.php также каждые 2 секунды. Запись координат в базу данных осуществляет Android приложение через coordinatesFromAndroid.php каждые 2 секунды при условии движения андроид устройства. Пользователь приложения может включать и выключать определение координат. Далее соберем эту схему.

1. Для инициализации google maps потребуются API ключ. Для его получения переходим на https://cloud.google.com/maps-platform

Нажимаем Get started.

Создаем новый проект.

В созданном проекте выбираем Maps JavaScript API.

Нажимаем Enable.

Жмем на гамбургер -> APIs & Services -> Credentials.

Нажимаем на +Create Credentials

И мы получили Api key

2. Создаем файл index.html и style.css и myJsCode.js. Писать код будем в редакторе Visual Studio Code, скачиваем его по ссылке https://code.visualstudio.com/

index.html В 71 строчке меняете API key на свой. В 69 строчке подключается файл myJsCode.js, который мы напишем ниже. В 53 строчке в блоке div будет располагаться карта с маркером.

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" , href="style.css">
    <title>Название сайта</title>
    <meta name="description"
        content="Описание " />
    <meta name="Keywords" content="Ключевые слова" />

</head>

<body>
    <div class="box">
        <header >
            <a class="logo" href="index.html"><img src="images/logo.jpg" width="40" height="40" alt="logo"></a>
            <h1 class="logoTitle">Заголовок 1</h1>
        </header>

        <div class="content">
            <p class="phoneAndName">
                <a class="imgphone" href="tel: 811111111">
                    <img src="images/phone.jpg" width="30" height="30" alt="">
                </a>
                <b><a class="telephone" href="tel: 811111111">8-111-11-11 </a></b> <b><span class="yourName">
                        Ваше имя</span></b>
            </p>
        
            <p class="descriptionYourBuisless">Описание вашей деятельности </p>
            <div class="descriptionHeader2">
                <h2 class="Header2">Заголовок 2:</h2>
                <span class="Header2Text"> Описание </span>
            </div>

            <div class="adPointers">
                <ul class="row1">
                    <li>Пункт1</li>
                    <li>Пункт2</li>  
                </ul>
                <ul class="row2">
                    <li>Пункт3</li>
                    <li>Пункт4</li>
                </ul>
            </div>

        </div>

       
        <span></span>
        <div class="photoCargo">
            <div id="map-canvas"></div>
        </div>

        <div class="descriptionHeader3">
            <h3 class="Header3">Заголовок 3:</h2>
            <span class="Header3Text"> Описание </span>
        </div>
        <footer>
            <hr>
            <p>Контакты: г. Ваш город <br />
                Email: <a class="foot" href="mailto:yourMail@yandex.ru">yourMail@yandex.ru</a> <br />телефон: <a
                    class="foot" href="tel: 8111111111">8-111-11-11-11</a>
            </p>
        </footer>
    </div>

    <script src="myJsCode.js"></script>
    <script
        src="https://maps.googleapis.com/maps/api/js?v=3.exp&key=AIzaSyBPV_qSO1VI11pXLJuvQtXzVh1pTQjFkC1&callback=initialize">
        </script> 
</body>

</html>

Далее пишем style.css В этом файле оставляем все как есть. Здесь уже предусмотрена адаптация под мобильные устройства с помощью media запросов.

* 
{
  margin: 0;
  padding: 0;
}

.box{
    max-width:1560px; 
    margin: 0px auto;
    padding: 0px 0px;
}

header{ 
  position: fixed; 
  background-color: white; 
  padding-top: 10px; 
  height:60px; 
  width: 100%;
  box-shadow: 7px 7px 5px rgba(63, 62, 62, 0.6); /* Тень */
}

.content{ 
  padding-top: 100px;
}   

.logo{
  float:left;
  margin-left: 10px;
}

.logoTitle{    
  float:left;
  margin-top: 10px; 
  margin-left: 10px;
  text-decoration: none;
  font-family: sans-serif;
  font-size: 20px;
  color: #000;    
} 

.phoneAndName{
  text-align: center;
  color: #000; 
  margin-bottom: 15px; 
}

.imgphone{
  text-decoration: none; 
}

.telephone{
  text-decoration: none;
  font-family: sans-serif;
  font-size: 30px;
  color: #000; 
}

.yourName{
  color: #030c01; 
  font-size: 30px;
}

.descriptionYourBuisless{
  text-align: center;
  font-size: 20px;
  color: #000;
   margin-bottom: 20px;  
  padding: 0px 10px;    
} 

.descriptionHeader2{
  justify-content: center;
  display:flex; 
}

.Header2{
  color: #000; 
  font-size: 20px;
  padding-right: 10px;
  padding-left: 40px;
}

.Header2Text{
  padding-right: 20px;
  color: #000; 
  font-size: 20px;
  margin-bottom: 20px;
} 

.photoCargo{
  margin: auto; 
  width:55%;
  height:100%;
  color: #000; 
}

.row1{
  padding-left: 20px;
  padding-right: 20px;
  padding-bottom: 20px;
  margin-right: 20px;
}

.row2{
   padding-left: 20px;
   padding-right: 20px;
   padding-bottom: 20px;
}

li{
   font-size: 20px;
   color: #000;  
}

#map-canvas{
   height:600px; 
   width: 100%;
   margin-top: 20px;
}

.descriptionHeader3{
  margin-top: 20px;
  justify-content: center;
  display:flex; 
}

.Header3{
  color: #000; 
  font-size: 20px;
  padding-right: 10px;
  padding-left: 40px;
}

 .Header3Text{
  padding-right: 20px;
  color: #000; 
  font-size: 20px;
  margin-bottom: 20px;
} 

footer{
   text-align: center;
   font-size: 14px;
   color: #000; 
   margin-top: 20px;
   margin-bottom: 20px; 
   padding-left: 5px;
   padding-right: 5px;
} 

@media(min-width: 1560px){
  .adPointers{
    justify-content: center;
    display:flex;    
  } 
}
@media(max-width: 1560px){
  .adPointers{
    justify-content: center;
     display:flex; 
  }
    .box{
      max-width:1460px; 
    }
}
@media(max-width: 1400px){
    .box{
      max-width:1360px; 
    }
    .photoCargo{
      width:60%;
    }
}
@media(max-width: 1200px){
    .box{
      max-width:970px; 
    }
    .photoCargo{
      width:65%;
    }
}
@media(max-width: 992px){
    .box{
        max-width:850px; 
    }
    .photoCargo{
      width:80%;
    }
}
@media(max-width: 767px){
    .box{
      max-width:none; 
    } 
    .photoCargo{
      width:90%;
    }
}
@media(max-width: 695px){

    .photoCargo{
      width:95%;
    }  
}
@media(max-width: 450px){
    .adPointers{        
      flex-direction: column;  
      margin-left: 100px; 
    }
}

myJsCode.js В 1 и 2 строчке задаются координаты по умолчанию. В 6 строчке функция инициализации google maps. Внутри функции setTimeout каждые 2 секунды идет считывание координат из coordinatesToBrowser.php и передача новых координат в google maps. Файл coordinatesToBrowser.php напишем ниже.

window.lat = 37.7850;
window.lng = -122.4383;
var map;
var mark;

var initialize = function () {
    map = new google.maps.Map(document.getElementById('map-canvas'), { center: { lat: lat, lng: lng }, zoom: 12 });
    mark = new google.maps.Marker({ position: { lat: lat, lng: lng }, map: map });
};

var compare=0;

let timerId = setTimeout(function tick() {
 var xhr = new XMLHttpRequest();
     xhr.open('GET', 'coordinatesToBrowser.php', true);
     xhr.onreadystatechange = function() {
         if (xhr.readyState == 4 && xhr.status == 200) {
          var jsonObj=JSON.parse(xhr.responseText);
          const arr = Object.keys(jsonObj).map((key) => [key, jsonObj[key]]);
        
         lat= parseFloat(arr[0][1]);
         lng= parseFloat(arr[1][1]);
         if(compare!=lat){
          map.setCenter({ lat: lat, lng: lng, alt: 0 });
          mark.setPosition({ lat: lat, lng: lng, alt: 0 });
         }
         compare=lat;
        }
     }
     xhr.send(null);
       
  
timerId = setTimeout(tick, 2000);
}, 2000);

3. Все файлы заливаете на свой хост. Далее переходим в php MyAdmin. Создаете базу данных или используете уже созданную автоматически. В ней создаете таблицу под названием coordinates. В этой таблице создаете 3 столбца: id, latitude и longitude как на изображении.

4. Далее в папку сайта на хостинг помещаете два php файла, которые будут взаимодействовать с базой данных, а именно таблицей coordinates. Файл coordinatesToBrowser.php будет считывать координаты из базы, а coordinatesFromAndroid.php будет записывать переданные android устройством координаты в базу данных.

coordinatesToBrowser.php В 15 строчке происходит выборка из созданной нами таблицы coordinates, а именно из столбцов latitude и longitude. Подключение к самой базе данных прокомментировано в коде.

<?php
 $host = 'localhost';  // Хост, у нас все локально
 $user = 'u1111111111';    // Имя созданного вами пользователя
 $pass = '22222222'; // Установленный вами пароль пользователю
 $db_name = 'u11111111111';   // Имя базы данных
 $link = mysqli_connect($host, $user, $pass, $db_name); // Соединяемся с базой

// Ругаемся, если соединение установить не удалось
 if (!$link) {
    // echo 'Не могу соединиться с БД. Код ошибки: ' . mysqli_connect_errno() . ', ошибка: ' . mysqli_connect_error();
     exit;
 }
 else{}
    
 $sql = mysqli_query($link, "SELECT * FROM coordinates");

 if ($sql) {
    $row = $sql->fetch_assoc();
    $lat=$row['latitude'];
    $lon=$row['<?php
 $host = 'localhost';  // Хост, у нас все локально
 $user = 'u1111111111';    // Имя созданного вами пользователя
 $pass = '22222222'; // Установленный вами пароль пользователю
 $db_name = 'u11111111111';   // Имя базы данных
 $link = mysqli_connect($host, $user, $pass, $db_name); // Соединяемся с базой

// Ругаемся, если соединение установить не удалось
 if (!$link) {
    // echo 'Не могу соединиться с БД. Код ошибки: ' . mysqli_connect_errno() . ', ошибка: ' . mysqli_connect_error();
     exit;
 }
 else{}
    
 $sql = mysqli_query($link, "SELECT * FROM coordinates");

 if ($sql) {
    $row = $sql->fetch_assoc();
    $lat=$row['latitude'];
    $lon=$row['longitude'];
  
    $cart = array(
      "latitude" => $lat,
      "longitude" => $lon,
   );
 
   echo json_encode( $cart );
    
   } else {
    // echo '<p>Произошла ошибка: ' . mysqli_error($link) . '</p>';
   }
?>];
  
    $cart = array(
      "latitude" => $lat,
      "longitude" => $lon,
   );
 
   echo json_encode( $cart );
    
   } else {
    // echo '<p>Произошла ошибка: ' . mysqli_error($link) . '</p>';
   }
?>

coordinatesFromAndroid.php. В 22 строчке идет перезапись столбцов новыми значениями.

<?php
 $Latitude=37.7850;
 $Longitude=-122.4383;

 $host = 'localhost';  // Хост, у нас все локально
 $user = 'u1111111';    // Имя созданного вами пользователя
 $pass = 'f2222222'; // Установленный вами пароль пользователю
 $db_name = 'u1111111';   // Имя базы данных
 $link = mysqli_connect($host, $user, $pass, $db_name); // Соединяемся с базой

// Ругаемся, если соединение установить не удалось
 if (!$link) {
   //  echo 'Не могу соединиться с БД. Код ошибки: ' . mysqli_connect_errno() . ', ошибка: ' . mysqli_connect_error();
     exit;
 }
 else{
     if (!empty($_POST["Latitude"]&&!empty($_POST["Longitude"]))){
     $Latitude=$_POST["Latitude"];
     $Longitude=$_POST["Longitude"];
    }
    
  $sql = mysqli_query($link, "UPDATE coordinates SET latitude='$Latitude', longitude='$Longitude' WHERE id='1'");

  if ($sql) {
   // echo '<p>Данные успешно добавлены в таблицу.</p>';
   } else {
    // echo '<p>Произошла ошибка: ' . mysqli_error($link) . '</p>';
    }
  }
?>

5. Заключительным этапом мы создадим андроид приложение, которое будет передавать координаты каждые 2 секунды во время движения. Приложение запускает сервис, который запрашивает текущие координаты у встроенного gps приемника. Для работы в фоновом режиме необходимо стороннее приложение, например такси или карты, при работе которых в верхней панели отображается 'самолетик' (геолокация). Несмотря на то, что сервис очень живучий в приложении предусмотрен менеджер, перезапускающий сервис каждые 30 секунд на случай, если андроид очистит от него память.

Итак скачиваем и устанавливаем среду разработки приложений Android Studio.

Создаете новый проект, выбрав empty Activity

Называете приложение и выбираете язык Java

В баре слева выбираете App -> res -> layout открываете файл activity_main.xml и меняете его содержимое на:

activity_main.xml Файл представляет собой внешний вид страницы приложения. На нем расположены кнопки Получить координаты и Сбросить координаты, а также текстовые поля для отображения координат и региона.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#ffffff"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/col"
        android:gravity="center"
        android:text="GPS"
        android:textColor="#ffffff"
        android:textSize="20dp" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:layout_height="50dp">
            <TextView
                android:layout_width="150dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:text="Широта"
                android:textColor="#000000"
                android:textSize="20dp" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:id="@+id/tv_latitude"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:layout_height="50dp">
            <TextView
                android:layout_width="150dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:text="Долгота"
                android:textColor="#000000"
                android:textSize="20dp" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:id="@+id/tv_longitude"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:layout_height="50dp">
            <TextView
                android:layout_width="150dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:text="Адрес"
                android:textColor="#000000"
                android:textSize="20dp" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:id="@+id/tv_address"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:layout_height="50dp">

            <TextView
                android:layout_width="150dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:text="Область"
                android:textColor="#000000"
                android:textSize="20dp" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:id="@+id/tv_area"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:layout_height="50dp">

            <TextView
                android:layout_width="150dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:text="Локация"
                android:textColor="#000000"
                android:textSize="20dp" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text=""
                android:id="@+id/tv_locality"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:textColor="#000000"
                android:textSize="20dp"/>
        </LinearLayout>
    </LinearLayout>
    <Button
        android:id="@+id/btn_start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="false"
        android:layout_marginTop="121dp"
        android:layout_marginBottom="12dp"
        android:text="Получить координаты" />
    <Button
        android:id="@+id/btn_finish"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="55dp"
        android:text="сбросить координаты" />
</RelativeLayout>        

Далее App ->manifest открываете файл AndroidManifest.xml и меняете его содержимое на:

AndroidManifest.xml Файл несет в себе информацию о приложении для операционной системы. В него включены данные об активити, сервисах, разрешениях и другом. Оставляете свой package="yourpackage" строчка 3.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="yourpackage">
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    <application

        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:theme="@android:style/Theme.Translucent.NoTitleBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <uses-library android:name="org.apache.http.legacy" android:required="false"/>
        <service android:enabled="true" android:name=".GoogleService" />

        <receiver android:name=".MyAlarmReceiver" />
    </application>
</manifest>

Далее снова App -> res -> values открываете файл colors.xml и меняете его содержимое на:

colors.xml В файле задаются цвета элементов.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#6200EE</color>
    <color name="colorPrimaryDark">#3700B3</color>
    <color name="colorAccent">#03DAC5</color>
    <color name="colorTitle">#808040</color>
    <color name="col">#868602</color>
</resources>

Далее Gradle Scripts открываете файл build.grande(Module app) и меняете его содержимое на:

build.grande(Module app) В файле информация о сборке проекта и его зависимостях. В строчке 5 оставляете свой applicationId.

apply plugin: 'com.android.application'

android {     compileSdkVersion 30     buildToolsVersion "30.0.2"
defaultConfig {
    applicationId "yourPackage"
    minSdkVersion 16
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    multiDexEnabled true
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    useLibrary 'org.apache.http.legacy' // Библиотека для HTTP Client
}

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

Далее снова App -> Java -> YourPackage открываете файл MainActivity.java и меняете его содержимое на:

MainActivity.java В этом файле код основного активити. Строку 1 оставляете свою. В файле проходит инициализация кнопок, текстовых полей. Инициализация AlarmManager, который 'пробуждает' основной сервис. Обработка нажатия кнопок. Обработка разрешений от пользователя. Прием и отображение координат и региона. Запуск сервиса GoogleService , который запрашивает gps координаты осуществляется в обработчике нажатия кнопки btn_start. Сброс координат в значение по умолчанию осуществляется в обработчике кнопки btn_finish. Сам GoogleService и AlarmManager опишем ниже.

package yourpackage;
import android.Manifest;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.preference.PreferenceManager; 
import android.view.View;
import android.widget.Button; 
import android.widget.TextView; 
import android.widget.Toast; 
import androidx.core.app.ActivityCompat; 
import androidx.core.content.ContextCompat;

import java.io.IOException;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;

public class MainActivity extends Activity  {    
public static boolean stsrtFinish = true; 
Button btn_start;
Button btn_finish; 
private static final int REQUEST_PERMISSIONS = 100; 
boolean boolean_permission; 
TextView tv_latitude, tv_longitude, tv_address, tv_area, tv_locality;  
SharedPreferences mPref; 
SharedPreferences.Editor medit;  
Double latitude, longitude;
Geocoder geocoder;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final AlarmManager alarmMgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
    final Intent intent = new Intent(this, MyAlarmReceiver.class);
    final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
    Calendar time = Calendar.getInstance();
    time.setTimeInMillis(System.currentTimeMillis());
    time.add(Calendar.SECOND, 5);
    alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(),3000, pendingIntent);

    btn_start = (Button) findViewById(R.id.btn_start);
    btn_finish = (Button) findViewById(R.id.btn_finish);
    tv_address = (TextView) findViewById(R.id.tv_address);
    tv_latitude = (TextView) findViewById(R.id.tv_latitude);
    tv_longitude = (TextView) findViewById(R.id.tv_longitude);
    tv_area = (TextView) findViewById(R.id.tv_area);
    tv_locality = (TextView) findViewById(R.id.tv_locality);
    geocoder = new Geocoder(this, Locale.getDefault());
    mPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    medit = mPref.edit();

    btn_finish.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            stsrtFinish = false;
            alarmMgr.cancel(pendingIntent);
        }
    });
    btn_start.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (boolean_permission) {
                medit.putString("service", "service").commit();
                Intent intent = new Intent(getApplicationContext(), GoogleService.class);
                startService(intent);
            } else {
                Toast.makeText(getApplicationContext(), "Please enable the gps", Toast.LENGTH_SHORT).show();
            }
        }
    });
    fn_permission();
}

private void fn_permission() {
    if ((ContextCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
        if ((ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, android.Manifest.permission.ACCESS_FINE_LOCATION))) {
        } else {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION
                    },
                    REQUEST_PERMISSIONS);
        }
    } else {
        boolean_permission = true;
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    switch (requestCode) {
        case REQUEST_PERMISSIONS: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                boolean_permission = true;

            } else {
                Toast.makeText(getApplicationContext(), "Please allow the permission", Toast.LENGTH_LONG).show();
            }
        }
    }
}

private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        latitude = Double.valueOf(intent.getStringExtra("latutide"));
        longitude = Double.valueOf(intent.getStringExtra("longitude"));
        List addresses = null;
        try {
            addresses = geocoder.getFromLocation(latitude, longitude, 1);
            String cityName = addresses.get(0).getAddressLine(0);
            String stateName = addresses.get(0).getAddressLine(1);
            String countryName = addresses.get(0).getAddressLine(2);

            tv_area.setText(addresses.get(0).getAdminArea());
            tv_locality.setText(stateName);
            tv_address.setText(countryName);
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        tv_latitude.setText(latitude + "");
        tv_longitude.setText(longitude + "");
        tv_address.getText();
    }
};

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(broadcastReceiver, new IntentFilter(GoogleService.str_receiver));
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
}
@Override
protected void onStart() {
    super.onStart();
}
@Override
protected void onPause() {
    super.onPause();
}
@Override
protected void onStop() {
    super.onStop();
}
@Override
protected void onDestroy() {
    super.onDestroy();
    unregisterReceiver(broadcastReceiver);
}
}

Далее Далее снова App -> Java -> YourPackage нажимаете правую кнопку мыши, во всплывающем меню создаете новый Java class и называете его GoogleService.java.

GoogleService.java Строку 1 оставляете свою. Файл представляет собой сервис, работающий в фоновом режиме, который принимает gps координаты с помощью LocationManager. В методе onLocationChanged идет передача координат на ваш сервер HttpPost post = new HttpPost("https://yourSite.ru/coordinatesFromAndroid.php") Адрес сайта поменяйте на свой строка 90.

package yourpackage;
import android.Manifest;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable; 
import androidx.core.app.ActivityCompat; 
import org.apache.http.util.EntityUtils;
import com.google.gson.JsonObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse; 
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient; 
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient; 
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams; 
import org.apache.http.params.HttpParams; 
import org.apache.http.protocol.HTTP; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.List;

public class GoogleService extends Service implements LocationListener {   
private JsonObject message; 
boolean isGPSEnable = false;
double latitude, longitude; 
LocationManager locationManager; 
public static String str_receiver = "servicetutorial.service.receiver"; 
Intent intent; 
List params;
public GoogleService() {
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    super.onCreate();
    intent = new Intent(str_receiver);
    message = new JsonObject();
    params = new ArrayList();
    locationManager = (LocationManager) getApplicationContext().getSystemService(LOCATION_SERVICE);
    isGPSEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2000, 10, this);
}

@Override
public void onLocationChanged(Location location) {
    params = new ArrayList();
    if (isGPSEnable) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        if (location!=null) {
            Log.e("location!=null", "location!=null");
            message.addProperty("lat", location.getLatitude());
            message.addProperty("lng", location.getLongitude());
              if(MainActivity.stsrtFinish) {
                  params.add(new BasicNameValuePair("Latitude", String.valueOf(location.getLatitude())));
                  params.add(new BasicNameValuePair("Longitude", String.valueOf(location.getLongitude())));
              }
              else{
                  params.add(new BasicNameValuePair("Latitude", "37.7850"));
                  params.add(new BasicNameValuePair("Longitude", "-122.4383"));
              }
            new Thread(new Runnable() {
                        public void run() {
                            try {
                                HttpParams httpParameters = new BasicHttpParams();
                                HttpConnectionParams.setConnectionTimeout(httpParameters, 10000);
                                HttpConnectionParams.setSoTimeout(httpParameters, 10000);
                                HttpClient httpClientpost = new DefaultHttpClient(httpParameters);
                                HttpPost post = new HttpPost("https://yourSite.ru/coordinatesFromAndroid.php");

                                UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params, HTTP.UTF_8);
                                post.setEntity(ent);
                                HttpResponse responsePOST = httpClientpost.execute(post);
                                HttpEntity resEntity = responsePOST.getEntity();
                                String getresponse = EntityUtils.toString(resEntity);
                                //Response from the server
                                Log.e("response",getresponse);
                            }
                            catch (IOException e) {
                                e.printStackTrace();
                                Log.e("catch","catch");
                            }
                        }
                    }).start();

                    latitude = location.getLatitude();
                    longitude = location.getLongitude();
                    fn_update(location);
        }
    }
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override
public void onProviderEnabled(String provider) { }
@Override
public void onProviderDisabled(String provider) { }

private void fn_update(Location location){
    intent.putExtra("latutide",location.getLatitude()+"");
    intent.putExtra("longitude",location.getLongitude()+"");
    sendBroadcast(intent);
}
}

Далее Далее снова App -> Java -> YourPackage нажимаете правую кнопку мыши, во всплывающем меню создаете новый Java class и называете его MyAlarmReceiver.java.

MyAlarmReceiver.java Строку 1 оставляете свою. Код в этом файле запускается каждые 30 секунд. Таким образом происходит перезапуск GoogleService, в случае если сервис перестал работать.

package yourpackage;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyAlarmReceiver extends BroadcastReceiver { 
  @Override  
  public void onReceive(Context context, Intent intent){ 
    context.startService(new Intent(context, GoogleService.class));
  }
}

Далее включаете на своем андроид телефоне режим разработчика, подключаетесь через usb к компьютеру, в окошке Devices отобразится название вашего телефона. Нажимаете кнопку пуск. Начнется сборка и установка приложения на телефон. Если все прошло без ошибок, значит ваш сервис работает так же как и мой. Работу сервиса можете увидеть на сайте https://gaselka71.ru

Для тех, кому нравится видеоформат можете посмотреть плейлист по этой теме на моем канале:

Всем спасибо за внимание. Желаю удачи!

Источник: https://habr.com/ru/post/546286/


Интересные статьи

Интересные статьи

Все «за» и «против» 1С-Битрикс, какие есть альтернативы и что выгоднее знать разработчику? Читать далее
Flipper — проект карманного мультитула для хакеров в формфакторе тамагочи, который я разрабатываю с друзьями. Предыдущие посты [1],[2]. Сайт проекта: flipperzero.one Пока мы работали ...
Если вы последние лет десять следите за обновлениями «коробочной версии» Битрикса (не 24), то давно уже заметили, что обновляется только модуль магазина и его окружение. Все остальные модули как ...
Изображение: Unsplash Современный фондовый рынок – это масштабная и довольно сложная область знаний. Сходу разобраться в том, «как здесь все устроено» бывает непросто. И несмотря на развит...
Это циничная, клиническая коллекция того, чему я научился за 30 лет работы в разработке программного обеспечения. Повторюсь, некоторые вещи весьма циничны, а остальное — результат долгих наблюд...