יום שישי, 12 באפריל 2013

Google Maps Android



מפות רבותי, מפות, אז אחרי ש Google עשתה את כל העבודה כשמיפתה את העולם ופתחה אותו לכל מי שרק חופץ, העסק נהפך להרבה יותר פשוט, אם תשאלו אותי לפני ש Google החליטה לבצע כזה צעד נועז בתור מפתח לא חשבתי שבכלל תהיה לי היכולת להשתמש במערכות מיפוי, העסק תמיד היה נראה לי מסובך ומצריך משאבים רבים,  Google החליטה לתת השירות באופן חופשי עבור משתמשי Android ולאפשר למפתחים לשלב שירותי מיפוי באפליקציות שלהם ללא תשלום, ובשילוב ה Gps שבמכשירים ניתן לפתח אפליקציות מיקום מתקדמות.

במאמר זה אני יעבור על תהליך ההתממשקות ושלב כתיבת האפליקציה ב Android.

שימו לב! - המאמר עובר על תהליך ההתממשקות בגרסת  Google Maps Api 2 בשילוב גרסת Api 10 של Android.


התממשקות לשירותי Google

תחילה יש להירשם ל Google (מי שעוד לא הספיק) יש להיכנס לאתר API Console ואח"כ לבחור את ה Api המתאים ברשימת ה Services.



לאחר מכן  נגדיר את המפתח עבור האפליקציה, נלחץ על Create New Android Key:


במקרה של עבודה של Debug ניתן להכניס את המפתח ה Default ולהוסיף את שם ה Package שלנו כפי שניתן לראות בדוגמה:

45:B5:E4:6F:36:AD:0A:98:94:B4:02:66:2B:12:17:F2:56:26:A0:E0;com.example

במקרה של Release צריך לייצר מפתח חדש בעזרת הכלי Keytool, את מחרוזת ה SHA1 נטען בתור המפתח ולאחר מכן נרשום אותו ב Manifest כפי שמוצג בהמשך.

יצירת פרויקט:

לפני שניצור פרוייקט חדש חשוב לוודא ש Google Services Api מותקן כחלק מ Android Api 10, בנוסף יש להתקין את הדוגמאות עבור ה SDK.




ניצור פרוייקט חדש ב Eclipse של Android,   ונשנה את ה Android Build Target ל Google Api, נוסיף פרויקט נוסף  ב Workspace שנקרא google_play_services_lib  הוא נמצא בתיקיית ה Extra של ה SDK ונוסיף אותו ב Library בפרויקט כפי שניתן לראות בדוגמה:



קוד:

הקוד עצמו יחסית פשוט , ניצור מחלקה שיורשת FragmentActivity  ונחבר Interface מסוג LocationListener, נממש מספר פונקציות ונגדיר את ה Service Provider ע"פ החומרה הקיימת במכשיר על מנת לקבל את המיקום, נסמן את עצמנו במפה ונדאג לעדכן את המיקום בכל פרק זמן או מרחק שעברנו.

Activity

package com.example.urban;

import com.google.android.gms.maps.*;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.content.Context;
import android.graphics.Color;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
import android.support.v4.app.FragmentActivity;


public class GoogleMapActivity2 extends FragmentActivity implements LocationListener {

private GoogleMap mymap;

   private LocationManager locationManager;
   private String provider;
   private Marker locationMarker;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_google_map_activity2);

set_titlecolor();

//get map component from activity
   mymap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
   //map.setMyLocationEnabled(true);
 
   //set location manager and start active and checking availability of location service
   LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
     
   //check for GPS
   boolean enabledGPS = service
                .isProviderEnabled(LocationManager.GPS_PROVIDER);
   //check for WIFI
   boolean enabledWiFi = service
                .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

       //Check if GPS enable throw error
        if (!enabledGPS) {
            Toast.makeText(this, "GPS signal not found", Toast.LENGTH_LONG).show();
        }

       Location location = get_location();

        // Initialize the location fields
        if (location != null) {
            Toast.makeText(this, "Selected Provider " + provider,
                    Toast.LENGTH_SHORT).show();
            onLocationChanged(location);
         
        }

}

private void set_titlecolor()
{
                //just for fun change title color
View title = getWindow().findViewById(android.R.id.title);
View titleBar = (View) title.getParent();
titleBar.setBackgroundColor(Color.argb(100, 58, 58, 58));
}

private Location get_location()
{
//getting the location manager
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
       //define new Criteria for location service
       Criteria criteria = new Criteria();
       //request accuracy fine => GPS provider
       criteria.setAccuracy(Criteria.ACCURACY_FINE);
   
       provider = locationManager.getBestProvider(criteria, false);
       Location location = locationManager.getLastKnownLocation(provider);
       return location;
}

@Override
    protected void onResume() {
        super.onResume();
        //request to update location every 200 millisecond, and every 1 meter
        locationManager.requestLocationUpdates(provider,200, 1, this);
    }

    /* Remove the locationlistener updates when Activity is paused */
    @Override
    protected void onPause() {
        super.onPause();
        locationManager.removeUpdates(this);
    }

@Override
   public void onLocationChanged(Location location) {
       double lat =  location.getLatitude();
       double lng = location.getLongitude();
   
       Toast.makeText(this, "Location " + lat+","+lng,
               Toast.LENGTH_LONG).show();
     
       LatLng coordinate = new LatLng(lat, lng);
       Toast.makeText(this, "Location " + coordinate.latitude+","+coordinate.longitude,
               Toast.LENGTH_LONG).show();
     
       //remove the marker if exists
       if(locationMarker != null)
        locationMarker.remove();
     
       //add marker to map
       locationMarker = mymap.addMarker(new MarkerOptions()
       .position(coordinate)
       .title("Are You Spy On Me?")
       .snippet("don't expose your position!")
       .icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher)));
     
   
       //going to update the camera with the new coordinates
       CameraUpdate center=
                    CameraUpdateFactory.newLatLng(new LatLng(coordinate.latitude,
                    coordinate.longitude));
                 //set camera zoom
CameraUpdate zoom=CameraUpdateFactory.zoomTo(17);

//move camera to location
mymap.moveCamera(center);
mymap.animateCamera(zoom);
   }

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.google_map_activity2, menu);
return true;
}


@Override
public void onProviderDisabled(String arg0) {
  Toast.makeText(this, "Enabled new provider " + provider,
               Toast.LENGTH_SHORT).show();

}


@Override
public void onProviderEnabled(String arg0) {
Toast.makeText(this, "Disabled provider " + provider,
               Toast.LENGTH_SHORT).show();

}


@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
// TODO Auto-generated method stub

}

}

Layout

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:map="http://schemas.android.com/apk/res-auto"
  android:id="@+id/map"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  class="com.google.android.gms.maps.SupportMapFragment"
  map:cameraTilt="30"
  map:cameraZoom="13"
  map:mapType="normal"
  map:uiCompass="false"
  map:uiRotateGestures="true"
  map:uiScrollGestures="true"
  map:uiTiltGestures="true"
  map:uiZoomControls="false"
  map:uiZoomGestures="true"/>

Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.urban"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="10"
        android:targetSdkVersion="10" />

    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

    <permission
        android:name="com.example.urban.permission.MAPS_RECEIVE"
        android:protectionLevel="signature" />

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="com.example.urban.permission.MAPS_RECEIVE" />
    <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="com.google.android.providers.gsf.permission.READ_GSERVICES" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="your google api key!" />

        <uses-library
            android:name="com.google.android.maps"
            android:required="true" />

        <activity
            android:name="com.example.urban.GoogleMapActivity2"
            android:label="Google Maps Api 2" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


תוצאה סופית:




סיכום:

עכשיו העולם נראה קטן מתמיד ובעזרת שירותי Google העסק נהפך לפשוט יותר ולא פחות חשוב בחינם, אני לא יודע כמה זמן Google יחליטו להשאיר את השירות חינם עבור משתמשי Android אבל כנראה שכבר לא נלך לאיבוד.

תפסו כיוון!