آموزش کار با نقشه OSM در اپلیکیشن اندروید

آبان 9, 1398| سنا عبادی
آموزش گام به گام افزودن نقشه osm به اپلیکیشن اندروید | وبلاگ مارکت اندروید ریور

آموزش گام به گام افزودن و کار با نقشه OSM در برنامه نویسی اندروید در این مقاله از وبلاگ مارکت اندروید ریور توضیح داده شده ، محکم روی صندلی خود بشینید و با من در ادامه این مقاله همراه باشید..

openStreetMap یا به اختصار OSM نوع دیگری از نقشه های موجود برای توسعه دهندگان اندروید جهت استفاده در برنامه های خود است .

حتما مطلع هستید که از استفاده از Google Map یک روش معمول و بسیار کاربردی برای استفاده از نقشه و امکانات ان هست ولی به دلایل محدودیت های اخیری که از سمت گوگل برای توسعه دهندگان در نظر گرفته شد فقط نشان دادن خود نقشه رایگان هست ولی در مواردی مانند تعیین لوکیشن و تعیین مسیرو امکانات دیگر به طور تقریبی حدود 25000 یوزر رایگان هست ولی پس از آن به ازای هر 1000 هزار کاربر باید حدود 50 سنت پرداخت شود .

خب به نظر کمی دشوار هست به این دلیل که خیلی از برنامه نویسان ایرانی ممکن است حساب بین المللی و قابل استفاده ایی نداشته باشند و از جهت دیگر نیز غیر رایگان بودنش کمی باعث این شده که برنامه نویسان به فکر استفاده از نقشه های رایگان مانند OSM بیافتند که البته اوپن سورس بودن این نقشه به خودی خود سبب همکاری خیلی از توسعه دهندگان با یکدیگر شده است و تمایل به استفاده از آن رو هم دوچندان کرده.

آموزش افزودن نقشه OSM به اپلیکیشن اندروید

خب در این مقاله قرار هست که نحوه ی پیاده سازی نقشه ی OSM و هم چنین نشان دادن یک فایل KML صحبت شود پس بیاید شروع کنیم :

نحوه نمایش Google Maps در مقایسه با OpenStreetMap
نمایی از نحوه نمایش Google Maps در مقایسه با OpenStreetMap

در ابتدا باید وابستگی های مورد نیاز رو در buil.gradle سطح اپلیکیشنتون اضافه کنید :

implementation 'org.osmdroid:osmdroid-android:6.1.2'
     implementation 'com.github.MKergall:osmbonuspack:6.4'

هم چنین در repository سطح پروژتون در فایل buil.gradle این رو اضافه کنید :

allprojects {
    repositories {
        google()
        jcenter()

        mavenCentral()
        mavenLocal()

        maven { url "https://jitpack.io" }
    }
}

حالا فایل Manifest.xml ‌ پروژه را باز کنید و مجوزهای لازم را به برنامه اضافه کنید :

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

سپس به سراغ layout مد نظر برای نشان دادن نقشه مراجعه کنید و این تگ مختص نقشه را پیاده کنید :

    <org.osmdroid.views.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true"
        android:focusable="true" />

خب در آخر به سراغ کلاس جاوای خود بروید و کد های زیر را در آن اضافه کنید :

public class OsmActivity extends AppCompatActivity {
    private MapView map;
    private IMapController mapController;

    private static final String TAG = "OsmActivity";


    private static final int PERMISSION_REQUEST_CODE = 1;


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //handle permissions first, before map is created. not depicted here


        //load/initialize the osmdroid configuration, this can be done
        Context ctx = getApplicationContext();
        Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx));
        //setting this before the layout is inflated is a good idea
        //it 'should' ensure that the map has a writable location for the map cache, even without permissions
        //if no tiles are displayed, you can try overriding the cache path using Configuration.getInstance().setCachePath
        //see also StorageUtils
        //note, the load method also sets the HTTP User Agent to your application's package name, abusing osm's tile servers will get you banned based on this string

        //inflate and create the map

        setContentView(R.layout.activity_main);


        if (Build.VERSION.SDK_INT >= 23) {
            if (isStoragePermissionGranted()){

            }
        }


        map = findViewById(R.id.mapView);
        map.setTileSource(TileSourceFactory.MAPNIK);
        map.setBuiltInZoomControls(true);
        map.setMultiTouchControls(true);
        mapController = map.getController();
        mapController.setZoom(15);
        GeoPoint startPoint = new GeoPoint(51496994, -134733);
        mapController.setCenter(startPoint);
}

 public void onResume() {
        super.onResume();
        //this will refresh the osmdroid configuration on resuming.
        //if you make changes to the configuration, use
        //SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        //Configuration.getInstance().load(this, PreferenceManager.getDefaultSharedPreferences(this));
        if (map != null)
            map.onResume(); //needed for compass, my location overlays, v6.0.0 and up
    }

    public void onPause() {
        super.onPause();
        //this will refresh the osmdroid configuration on resuming.
        //if you make changes to the configuration, use
        //SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        //Configuration.getInstance().save(this, prefs);
        if (map != null)
            map.onPause();  //needed for compass, my location overlays, v6.0.0 and up
    }


    public boolean isStoragePermissionGranted() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED &amp;&amp; checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED) {
                Log.v(TAG, "Permission is granted");
                return true;
            } else {

                Log.v(TAG, "Permission is revoked");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION}, 1);
                return false;
            }
        } else { //permission is automatically granted on sdk<23 upon installation
            Log.v(TAG, "Permission is granted");
            return true;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (grantResults.length > 0 &amp;&amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Log.v(TAG, "Permission: " + permissions[0] + "was " + grantResults[0]);
            //resume tasks needing this permission
        }
    }

خب در کد های بالا شما شاهد کد های تکراری برای صدور مجوز برای پرمیشن های خطرناک برنامه به صورت ران تایم هستیم و هم چنین در خطوط اولیه نیز نحوه ی پیاده سازی نقشه آورده شده است .میتونید کامنت ها رو دنبال کنید .

همچنین بخوانید :  آموزش طراحی رابط کاربری رسپانسیو برای اپلیکیشن

نحوه نمایش KML روی نقشه OSM در برنامه نویسی اندروید

در ادامه همانطور که در ابتدا اشاره شد قرار بود فایل هایی تحت عنوان KML را در نقشه پیاده و نشان دهیم .برای این کار ابتدا شما فایل مورد نظر رو در پوشه ی raw قرار بدید (روی res راست کلیک کنید و New> Android REsource Dir را انتخاب کنید و دایرکتوری را از جنس raw انتخاب کنید ) پس از این کار کلا مخصوص و کد های آن را مانند زیر پیاده کنید :

public void loadKml() {
        new KmlLoader().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }



    class KmlLoader extends AsyncTask<Void, Void, Void> {
        ProgressDialog progressDialog = new ProgressDialog(OsmActivity.this);
        KmlDocument kmlDocument;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressDialog.setMessage("Loading Project...");
            progressDialog.show();
        }

        @SuppressLint("WrongThread")
        @Override
        protected Void doInBackground(Void... voids) {
            kmlDocument = new KmlDocument();
            kmlDocument.parseKMLStream(getResources().openRawResource(R.raw.study_areas), null);
            FolderOverlay kmlOverlay = (FolderOverlay)kmlDocument.mKmlRoot.buildOverlay(map, null, null,kmlDocument);
            map.getOverlays().add(kmlOverlay);
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            progressDialog.dismiss();
            map.invalidate();
            BoundingBox bb = kmlDocument.mKmlRoot.getBoundingBox();
            map.zoomToBoundingBox(bb, true);
//            mapView.getController().setCenter(bb.getCenter());
            super.onPostExecute(aVoid);
        }
    }

و در onCreate متد مورد نظر را یعنی loadKml را فراخوانی خواهیم کرد و در کل کلاس OsmActivity به صورت زیر خواهد بود :

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.system.Os;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import org.osmdroid.api.IMapController;
import org.osmdroid.bonuspack.kml.KmlDocument;
import org.osmdroid.config.Configuration;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.util.BoundingBox;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.FolderOverlay;

public class OsmActivity extends AppCompatActivity {
    private MapView map;
    private IMapController mapController;

    private static final String TAG = "OsmActivity";


    private static final int PERMISSION_REQUEST_CODE = 1;


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //handle permissions first, before map is created. not depicted here


        //load/initialize the osmdroid configuration, this can be done
        Context ctx = getApplicationContext();
        Configuration.getInstance().load(ctx, PreferenceManager.getDefaultSharedPreferences(ctx));
        //setting this before the layout is inflated is a good idea
        //it 'should' ensure that the map has a writable location for the map cache, even without permissions
        //if no tiles are displayed, you can try overriding the cache path using Configuration.getInstance().setCachePath
        //see also StorageUtils
        //note, the load method also sets the HTTP User Agent to your application's package name, abusing osm's tile servers will get you banned based on this string

        //inflate and create the map

        setContentView(R.layout.activity_main);


        if (Build.VERSION.SDK_INT >= 23) {
            if (isStoragePermissionGranted()){

            }
        }


        map = findViewById(R.id.mapView);
        map.setTileSource(TileSourceFactory.MAPNIK);
        map.setBuiltInZoomControls(true);
        map.setMultiTouchControls(true);
        mapController = map.getController();
        mapController.setZoom(15);
        GeoPoint startPoint = new GeoPoint(51496994, -134733);
        mapController.setCenter(startPoint);

        loadKml();
    }

    public void loadKml() {
        new KmlLoader().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }



    class KmlLoader extends AsyncTask<Void, Void, Void> {
        ProgressDialog progressDialog = new ProgressDialog(OsmActivity.this);
        KmlDocument kmlDocument;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressDialog.setMessage("Loading Project...");
            progressDialog.show();
        }

        @SuppressLint("WrongThread")
        @Override
        protected Void doInBackground(Void... voids) {
            kmlDocument = new KmlDocument();
            kmlDocument.parseKMLStream(getResources().openRawResource(R.raw.study_areas), null);
            FolderOverlay kmlOverlay = (FolderOverlay)kmlDocument.mKmlRoot.buildOverlay(map, null, null,kmlDocument);
            map.getOverlays().add(kmlOverlay);
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            progressDialog.dismiss();
            map.invalidate();
            BoundingBox bb = kmlDocument.mKmlRoot.getBoundingBox();
            map.zoomToBoundingBox(bb, true);
//            mapView.getController().setCenter(bb.getCenter());
            super.onPostExecute(aVoid);
        }
    }

    public void onResume() {
        super.onResume();
        //this will refresh the osmdroid configuration on resuming.
        //if you make changes to the configuration, use
        //SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        //Configuration.getInstance().load(this, PreferenceManager.getDefaultSharedPreferences(this));
        if (map != null)
            map.onResume(); //needed for compass, my location overlays, v6.0.0 and up
    }

    public void onPause() {
        super.onPause();
        //this will refresh the osmdroid configuration on resuming.
        //if you make changes to the configuration, use
        //SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        //Configuration.getInstance().save(this, prefs);
        if (map != null)
            map.onPause();  //needed for compass, my location overlays, v6.0.0 and up
    }


    public boolean isStoragePermissionGranted() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED &amp;&amp; checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
                    == PackageManager.PERMISSION_GRANTED) {
                Log.v(TAG, "Permission is granted");
                return true;
            } else {

                Log.v(TAG, "Permission is revoked");
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION}, 1);
                return false;
            }
        } else { //permission is automatically granted on sdk<23 upon installation
            Log.v(TAG, "Permission is granted");
            return true;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (grantResults.length > 0 &amp;&amp; grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Log.v(TAG, "Permission: " + permissions[0] + "was " + grantResults[0]);
            //resume tasks needing this permission
        }
    }
}

و در مرحله اجرا شما باید شاهد تصویر زیر باشید (برای نشان دادن فایل kml روی نقشه کلیک کنید.) :

نقشه تولید شده نهایی

امکان دیگری به اسم utm نیز داریم که در مقاله های بعدی به شرح آن خواهیم پرداخت . برای مشاهده و دریافت این سورس کد هم می تونید به این لینک گیت هاب مراجعه کنید.

همچنین بخوانید :  آموزش ساخت صفحه اسپلش در اندروید استدیو

نظراتتون رو حتما در ادامه این مقاله با ما به اشتراک بگزارید.

5/5 (2 Reviews)
سنا عبادی CO-Founder نویسنده مقاله

توسعه دهنده موبایل به ویژه سیستم عامل اندروید ، هم بنیانگذار اندروید ریور و در تلاش برای تحقق یک رویا..



می تونی سنا عبادی رو توی شبکه های اجتماعی هم دنبال کنی ...

مقالات مرتبط را بخوانید :


سورس های اندروید شامل تخفیف رو ببین !


  تخفیف ها و اخبار ویژه رو در تلگراممون دنبال کن :)
به این مقاله امتیاز دهید :
5/5 (2 Reviews)
  خرید سورس های حرفه ای بازی و اپلیکیشن اندروید

دسته‌ها: آموزش برنامه نویسی اندروید

دیدگاه

  • Nima Azhdari
    اسفند 2, 1398

    سلام. شما چقدر به این کتابخونه اشنا هستید ؟ من چند تا کار میخوام بکنم . 1- مقادیر خونده شده طول و عرض جغرافیایی رو override کنم و بعد نمایش بدم. یعنی یه تغییراتی مثل فیلتر زدن یا تغییر موقعیت رو انجام بدم. 2- امکانش هست مثل گوگل مپ اون روونی و جهت رو داشته باشیم تو این مپ . چون برای نمایش یه خورده پرش داره.

  • Yazdan Qm
    اسفند 11, 1398

    سلام . تو کدهاتون && این کلمات ارور میده و درست نیست ، میشه حلشون کنید ؟

    و اینکه آیا این نقشه امکان این رو داره ک ما لوکیشن کاربری ک توی مپ هست رو نشون بدیم ؟ و یا حتی خاصیت مسیر دادن و این چیزارو داره ؟

دیدگاهتان را بنویسید

راهنما : برای نوشتن موارد مختلف در دیدگاه می توانید از راهنمای نگارش اندروید ریور استفاده کنید : نگارش کد کوتاه `your code`
نگارش کد بلند یا نگارش بخش عمده یک سورس کد :
[sourcecode lang="your code language"] your code here [/sourcecode]