1. לפני שמתחילים
כאן מוסבר איך להשתמש בפלטפורמה של מפות Google וב-Places SDK ל-Android כדי להציג למשתמשים רשימה של מקומות ולזהות את המיקום הנוכחי שלהם.
דרישות מוקדמות
- מיומנויות בסיסיות ב-Java
הפעולות שתבצעו:
- הוספת מפה לאפליקציית Android.
- שימוש בהרשאות מיקום כדי לאתר את המיקום הגיאוגרפי של המשתמש.
- אחזור מקומות שקרובים למיקום הנוכחי של המשתמש.
- הצגת מקומות סבירים למשתמש כדי לזהות את המיקום הנוכחי שלו.
מה תפַתחו
אתם בונים את אפליקציית Android מאפס, אבל אתם יכולים להוריד את קוד הדוגמה לצורך השוואה כשמנפים באגים. מורידים את קוד הדוגמה מ-GitHub, או, אם הגדרתם את Git לשימוש בשורת הפקודה, מזינים את הפקודה הבאה:
git clone https://github.com/googlecodelabs/current-place-picker-android.git
אם נתקלתם בבעיות כלשהן (באגים בקוד, שגיאות דקדוק, ניסוח לא ברור או משהו אחר) במהלך העבודה עם ה-codelab הזה, אתם יכולים לדווח על הבעיה באמצעות הקישור דיווח על טעות בפינה הימנית התחתונה של ה-codelab.
2. שנתחיל?
לפני שמתחילים את ה-codelab הזה, צריך להגדיר את הדברים הבאים:
Android Studio
מורידים את Android Studio מהכתובת https://developer.android.com/studio.
אם כבר יש לכם Android Studio, אתם צריכים לוודא שיש לכם את הגרסה העדכנית ביותר. כדי לעשות את זה, לוחצים על Android Studio > Check for Updates....
ה-Lab הזה נכתב באמצעות Android Studio 3.4.
Android SDK
ב-Android Studio, אפשר להגדיר את ערכות ה-SDK הרצויות באמצעות SDK Manager. בשיעור ה-Lab הזה נשתמש ב-Android Q SDK.
- במסך הפתיחה של Android Studio, לוחצים על Configure (הגדרה) > SDK Manager (כלי לניהול ערכות SDK).
- מסמנים את התיבה של ה-SDK הרצוי ולוחצים על אישור.
אם עדיין לא התקנתם את ה-SDK, הפעולה הזו תתחיל את ההורדה של ה-SDK למחשב שלכם.
שירותי Google Play
בנוסף, צריך להתקין את Google Play Services דרך הכלי לניהול ערכות SDK.
- לוחצים על הכרטיסייה SDK Tools ומסמנים את תיבת הסימון Google Play services.
אם הסטטוס הוא יש עדכון זמין, מעדכנים.
3. הכנת האמולטור
כדי להפעיל את האפליקציה, אפשר לחבר מכשיר משלכם או להשתמש באמולטור Android.
אם אתם משתמשים במכשיר שלכם, דלגו אל ההוראות למכשיר אמיתי: עדכון Google Play Services בסוף הדף הזה.
הוספת אמולטור
- במסך הפתיחה של Android Studio, לוחצים על Configure (הגדרה) > AVD Manager (מנהל מכשירים וירטואליים).
תיבת הדו-שיח Android Virtual Device Manager תיפתח.
- לוחצים על יצירת מכשיר וירטואלי... כדי לפתוח רשימה של מכשירים שאפשר לבחור מתוכה.
- בוחרים מכשיר עם הסמל של Play
בעמודה Play Store ולוחצים על הבא.
יוצג לכם אוסף של תמונות מערכת שתוכלו להתקין. אם לצד Q לטירגוט Android 9.+ (Google Play) מופיעה המילה הורדה, לוחצים על הורדה.
- לוחצים על הבא כדי לתת שם למכשיר הווירטואלי, ואז לוחצים על סיום.
חוזרים לרשימה של המכשירים הווירטואליים שלכם.
- לוחצים על סמל ההתחלה
לצד המכשיר החדש:
אחרי כמה רגעים, האמולטור ייפתח.
הוראות לאמולטור – עדכון של Google Play Services
- אחרי שהאמולטור מופעל, לוחצים על ... בסרגל הניווט שמופיע**.**
תיבת הדו-שיח פקדים מתקדמים תיפתח.
- בתפריט, לוחצים על Google Play.
אם יש עדכון, לוחצים על עדכון.
- נכנסים לאמולטור באמצעות חשבון Google.
אתם יכולים להשתמש בחשבון קיים או ליצור חשבון חדש בחינם כדי להפריד בין הבדיקות לבין המידע האישי שלכם.
אחרי זה, Google Play נפתחת אל Google Play Services.
- לוחצים על עדכון כדי לקבל את הגרסה האחרונה של Google Play Services.
אם תתבקשו להשלים את הגדרת החשבון ולהוסיף אמצעי תשלום, לחצו על דילוג.
הגדרת מיקום באמולטור
- אחרי שהאמולטור מופעל, מקלידים 'מפות' בסרגל החיפוש במסך הבית כדי להציג את הסמל של אפליקציית מפות Google.
- לוחצים על הסמל כדי להפעיל את האפליקציה.
מוצגת מפת ברירת המחדל.
- בפינה השמאלית התחתונה של המפה, לוחצים על המיקום שלך
.
מתבקשים לתת לטלפון הרשאות להשתמש במיקום.
- לוחצים על ... כדי לפתוח את התפריט אמצעי בקרה מתקדמים.
- לחץ על הכרטיסייה מיקום.
- מזינים קו רוחב וקו אורך.
אפשר להזין כאן כל דבר שרוצים, אבל חשוב לוודא שזהו אזור עם הרבה מקומות.
(כדי לשחזר את התוצאות מ-codelab הזה, צריך להשתמש בקו הרוחב 20.7818 ובקו האורך -156.4624 של העיירה קיחיי במאווי שבהוואי).
- לוחצים על שליחה והמיקום הזה יתווסף למפה.
האפליקציה מוכנה להפעלה ולבדיקה עם מיקום.
הוראות למכשיר אמיתי – עדכון של Google Play Services
אם משתמשים במכשיר Android אמיתי, צריך לבצע את הפעולות הבאות:
- משתמשים בסרגל החיפוש במסך הבית כדי לחפש את Google Play Services ולפתוח אותו.
- לוחצים על פרטים נוספים.
אם האפשרות זמינה, לוחצים על עדכון.
4. יצירת מעטפת האפליקציה באמצעות פעילות במפות Google
- במסך הפתיחה של Android Studio, בוחרים באפשרות Start a new Android Studio project (התחלת פרויקט חדש ב-Android Studio).
- בכרטיסייה טלפון וטאבלט, בוחרים באפשרות פעילות במפות Google.
נפתחת תיבת הדו-שיח הגדרת הפרויקט. כאן נותנים שם לאפליקציה ויוצרים את החבילה על סמך הדומיין.
אלה ההגדרות של אפליקציה בשם Current Place, שמתאימה לחבילה com.google.codelab.currentplace
.
- בוחרים באפשרות Java כשפה ובוחרים באפשרות Use androidx. artifacts*.
משאירים את הגדרות ברירת המחדל בשאר ההגדרות.
- לוחצים על סיום.
5. הוספת תלויות של שירותי Google לקובץ ה-build של Gradle
כדי לגשת להרשאות מיקום ב-Android, צריך את Google Location and Activity Recognition API מ-Google Play Services. למידע נוסף על הוספה של ממשקי ה-API האלה ושל ממשקי API אחרים של Google Play Services, אפשר לעיין במאמר בנושא הגדרת Google Play Services.
בדרך כלל יש שני קובצי build.gradle
בפרויקטים של Android Studio. אחד מהם הוא לפרויקט כולו והשני הוא לאפליקציה. אם אתם משתמשים בסייר הפרויקטים של Android Studio בתצוגה Android, תוכלו לראות את שניהם בתיקייה Gradle Scripts
. צריך לערוך את קובץ build.gradle (Module: app)
כדי להוסיף שירותי Google.
- מוסיפים שני קווים לקטע
dependencies
כדי להוסיף את שירותי Google למיקום ואת Places API ( קוד לדוגמה בהקשר).
build.gradle (Module: app)
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.google.codelab.currentplace"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.google.android.gms:play-services-maps:16.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
implementation 'com.google.android.gms:play-services-location:16.0.0'
implementation 'com.google.android.libraries.places:places:1.1.0'
}
6. הפעלת ממשקי API של הפלטפורמה של מפות Google וקבלת מפתח API
בשלב הבא בהפעלה , צריך להפעיל את Maps SDK ל-Android ואת Places API.
הגדרת הפלטפורמה של מפות Google
אם עדיין אין לכם חשבון ב-Google Cloud Platform ופרויקט עם חיוב מופעל, תוכלו לעיין במדריך תחילת העבודה עם הפלטפורמה של מפות Google כדי ליצור חשבון לחיוב ופרויקט.
- בCloud Console, לוחצים על התפריט הנפתח של הפרויקט ובוחרים את הפרויקט שבו רוצים להשתמש ב-codelab הזה.
- מפעילים ב-Google Cloud Marketplace את ממשקי ה-API וערכות ה-SDK של הפלטפורמה של מפות Google שנדרשים ל-codelab הזה. כדי לעשות זאת, פועלים לפי השלבים בסרטון הזה או בתיעוד הזה.
- יוצרים מפתח API בדף Credentials במסוף Cloud. אפשר לפעול לפי השלבים שמפורטים בסרטון הזה או בתיעוד הזה. כל הבקשות אל הפלטפורמה של מפות Google מחייבות מפתח API.
מעתיקים את מפתח ה-API שיצרתם. חוזרים ל-Android Studio ומחפשים את הקובץ google_maps_api.xml
בקטע Android > app > res > values.
מחליפים את הערך YOUR_KEY_HERE
במפתח ה-API שהעתקתם.
האפליקציה מוגדרת עכשיו.
7. עריכת קובץ הפריסה
- בסייר הפרויקטים, פותחים את הקובץ
activity_maps.xml
בתיקייה Android >app
>res
>layout
.
- ממשק המשתמש הבסיסי ייפתח בצד שמאל של המסך, עם כרטיסיות בתחתית שמאפשרות לבחור את עורך העיצוב או את עורך הטקסט של הפריסה. בוחרים באפשרות טקסט ומחליפים את כל התוכן של קובץ הפריסה בתוכן הבא:
activity_maps.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:minHeight="?attr/actionBarSize"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:titleTextColor="@android:color/white"
android:background="@color/colorPrimary" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="349dp"
tools:context=".MapsActivity" />
<ListView
android:id="@+id/listPlaces"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
יוצג לכם ממשק משתמש שנראה כך:
8. הגדרת סרגל האפליקציות
כדי לתת למשתמש לחצן ללחיצה כשהוא רוצה לבחור את המקום הנוכחי שלו, מוסיפים סרגל אפליקציות עם סמל שמאתר את המקום הנוכחי של המשתמש ומציג מקומות סבירים בקרבת מקום. הממשק אמור להיראות כך:
בטלפון, מוצג רק הסמל. בטאבלט עם יותר מקום, הטקסט גם נכלל.
יצירת הסמל
- בסייר הפרויקטים, לוחצים על Android (אנדרואיד) > app (אפליקציה), ואז לוחצים לחיצה ימנית על התיקייה res (משאבים) ובוחרים באפשרות New (חדש) > Image Asset (נכס תמונה).
Asset Studio ייפתח.
- בתפריט סוג הסמל, לוחצים על סמלים של סרגל פעולות וכרטיסיות.
- נותנים שם לנכס
ic_geolocate
. - בוחרים באפשרות Clip Art בתור סוג הנכס**.**
- לוחצים על הגרפיקה לצד Clip Art (אוסף תמונות).
ייפתח החלון בחירת סמל.
- בוחרים סמל.
אפשר להשתמש בסרגל החיפוש כדי למצוא סמלים שקשורים לכוונת החיפוש.
- מחפשים את
location
ובוחרים סמל שקשור למיקום.
סמל המיקום שלי זהה לסמל שמופיע באפליקציית מפות Google כשמשתמש רוצה להעביר את המצלמה למיקום הנוכחי שלו.
- לוחצים על אישור > הבא > סיום,ומוודאים שיש תיקייה חדשה בשם
drawable
שמכילה את קובצי הסמלים החדשים.
הוספת משאבי מחרוזות
- בסייר הפרויקטים, לוחצים על Android (אנדרואיד) > app (אפליקציה) > res (משאבים) > values (ערכים) ופותחים את הקובץ
strings.xml
. - מוסיפים את השורות הבאות אחרי
<string name="title_activity_maps">Map</string>
:
strings.xml
<string name="action_geolocate">Pick Place</string>
<string name="default_info_title">Default Location</string>
<string name="default_info_snippet">No places found, because location permission is disabled.</string>
השורה הראשונה משמשת בסרגל האפליקציות כשיש מקום לכלול תווית טקסט לצד הסמל. הסמלים האחרים משמשים לסמנים שאתם מוסיפים למפה.
עכשיו הקוד בקובץ נראה כך:
<resources>
<string name="app_name">Current Place</string>
<string name="title_activity_maps">Map</string>
<string name="action_geolocate">Pick Place</string>
<string name="default_info_title">Default Location</string>
<string name="default_info_snippet">No places found, because location permission is disabled.</string>
</resources>
הוספת סרגל האפליקציות
- בסייר הפרויקטים, לוחצים על Android (אנדרואיד) > app (אפליקציה), ואז לוחצים לחיצה ימנית על התיקייה
res
ובוחרים באפשרות New (חדש) > Directory (ספרייה) כדי ליצור ספריית משנה חדשה מתחת לתיקייהapp/src/main/res
. - נותנים לספרייה את השם
menu
. - לוחצים לחיצה ימנית על התיקייה
menu
ובוחרים באפשרות חדש > קובץ. - נותנים לקובץ את השם
menu.xml
. - מדביקים את הקוד הבא:
menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- "Locate me", should appear as action button if possible -->
<item
android:id="@+id/action_geolocate"
android:icon="@drawable/ic_geolocate"
android:title="@string/action_geolocate"
app:showAsAction="always|withText" />
</menu>
עדכון הסגנון של סרגל האפליקציה
- בסייר הפרויקטים, מרחיבים את Android >
app
>res
>values
ופותחים את הקובץstyles.xml
שבתוכו. - בתג
<style>
, עורכים את מאפיין ההורה לערך"Theme.AppCompat.NoActionBar"
. - שימו לב לנכס
name
שבו תשתמשו בשלב הבא.
styles.xml
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
עדכון ערכת הנושא של האפליקציה בקובץ AndroidManifest.xml
- לוחצים על Android (אנדרואיד) >
app
>manifests
ופותחים את הקובץAndroidManifest.xml
. - מחפשים את השורה
android:theme
ועורכים או מאשרים את הערך@style/AppTheme
.
AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
עכשיו אפשר להתחיל לכתוב קוד.
9. הפעלת האפליקציה
- בסייר הפרויקטים, מאתרים את הקובץ
MapsActivity.java
.
הוא נמצא בתיקייה שמתאימה לחבילה שיצרתם לאפליקציה בשלב 1.
- פותחים את הקובץ ועוברים לכלי לעריכת קוד Java.
ייבוא של Places SDK ויחסי תלות אחרים
מוסיפים את השורות האלה לחלק העליון של MapsActivity.java
, ומחליפים את הצהרות הייבוא הקיימות.
הם כוללים את הייבוא הקיים ומוסיפים עוד הרבה ייבואים שמשמשים בקוד במעבדת הקוד הזו.
MapsActivity.java
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.libraries.places.api.Places;
import com.google.android.libraries.places.api.model.Place;
import com.google.android.libraries.places.api.model.PlaceLikelihood;
import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest;
import com.google.android.libraries.places.api.net.FindCurrentPlaceResponse;
import com.google.android.libraries.places.api.net.PlacesClient;
import java.util.Arrays;
import java.util.List;
עדכון החתימה של הכיתה
Places API משתמש ברכיבי AndroidX לתמיכה בתאימות לאחור, ולכן צריך להגדיר אותו כך שירחיב את AppCompatActivity
. היא מחליפה את התוסף FragmentActivity
שמוגדר כברירת מחדל לפעילות במפות.
public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {
הוספת משתנים לכיתה
לאחר מכן, מצהירים על משתני המחלקה השונים שמשמשים בשיטות שונות של המחלקה. הם כוללים את רכיבי ממשק המשתמש ואת קודי הסטטוס. הם צריכים להופיע מיד מתחת להצהרת המשתנה GoogleMap mMap
.
// New variables for Current Place picker
private static final String TAG = "MapsActivity";
ListView lstPlaces;
private PlacesClient mPlacesClient;
private FusedLocationProviderClient mFusedLocationProviderClient;
// The geographical location where the device is currently located. That is, the last-known
// location retrieved by the Fused Location Provider.
private Location mLastKnownLocation;
// A default location (Sydney, Australia) and default zoom to use when location permission is
// not granted.
private final LatLng mDefaultLocation = new LatLng(-33.8523341, 151.2106085);
private static final int DEFAULT_ZOOM = 15;
private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
private boolean mLocationPermissionGranted;
// Used for selecting the Current Place.
private static final int M_MAX_ENTRIES = 5;
private String[] mLikelyPlaceNames;
private String[] mLikelyPlaceAddresses;
private String[] mLikelyPlaceAttributions;
private LatLng[] mLikelyPlaceLatLngs;
עדכון ה-method onCreate
תצטרכו לעדכן את השיטה onCreate
כדי לטפל בהרשאות משתמש בזמן ריצה לשירותי מיקום, להגדיר את רכיבי ממשק המשתמש וליצור את לקוח Places API.
מוסיפים את שורות הקוד הבאות לגבי סרגל הכלים של הפעולות, הגדרת התצוגות ולקוח Places בסוף השיטה הקיימת onCreate()
.
MapsActivity.java onCreate()
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
//
// PASTE THE LINES BELOW THIS COMMENT
//
// Set up the action toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Set up the views
lstPlaces = (ListView) findViewById(R.id.listPlaces);
// Initialize the Places client
String apiKey = getString(R.string.google_maps_key);
Places.initialize(getApplicationContext(), apiKey);
mPlacesClient = Places.createClient(this);
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
}
הוספת קוד לתפריט של סרגל האפליקציות
שתי השיטות האלה מוסיפות את תפריט סרגל האפליקציות (עם פריט אחד, הסמל של בחירת מקום) ומטפלות בקליק של המשתמש על הסמל.
מעתיקים את שתי השיטות האלה לקובץ אחרי השיטה onCreate
.
onCreateOptionsMenu() ו-onOptionsItemSelected() ב-MapsActivity.java
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_geolocate:
// COMMENTED OUT UNTIL WE DEFINE THE METHOD
// Present the current place picker
// pickCurrentPlace();
return true;
default:
// If we got here, the user's action was not recognized.
// Invoke the superclass to handle it.
return super.onOptionsItemSelected(item);
}
}
רוצים לנסות?
- ב-Android Studio, לוחצים על Run או על Run menu > Run ‘app'.
- תתבקשו לבחור את יעד הפריסה. האמולטור הפועל אמור להופיע ברשימה הזו. בוחרים אותו, ו-Android Studio פורס את האפליקציה באמולטור בשבילכם.
אחרי כמה רגעים, האפליקציה תופעל. המפה מוצגת כשהיא ממוקדת בסידני, אוסטרליה, עם לחצן אחד ורשימת מקומות ריקה.
המיקוד של המפה לא עובר למיקום של המשתמש אלא אם מבקשים הרשאה לגשת למיקום של המכשיר.
10. שליחת בקשה להרשאות מיקום וטיפול בהן
שליחת בקשה להרשאות מיקום אחרי שהמפה מוכנה
- מגדירים שיטה בשם
getLocationPermission
שמבקשת הרשאות מהמשתמש.
מדביקים את הקוד הזה מתחת לשיטה onOptionsSelected
שיצרתם.
MapsActivity.java getLocationPermission()
private void getLocationPermission() {
/*
* Request location permission, so that we can get the location of the
* device. The result of the permission request is handled by a callback,
* onRequestPermissionsResult.
*/
mLocationPermissionGranted = false;
if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mLocationPermissionGranted = true;
} else {
ActivityCompat.requestPermissions(this,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
}
}
- מוסיפים שתי שורות לסוף השיטה הקיימת
onMapReady
כדי להפעיל את אמצעי הבקרה של הזום ולבקש מהמשתמש הרשאות גישה למיקום.
MapsActivity.java onMapReady()
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Add a marker in Sydney and move the camera
LatLng sydney = new LatLng(-34, 151);
mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
//
// PASTE THE LINES BELOW THIS COMMENT
//
// Enable the zoom controls for the map
mMap.getUiSettings().setZoomControlsEnabled(true);
// Prompt the user for permission.
getLocationPermission();
}
טיפול בתוצאה של בקשות להרשאות
כשמשתמש מגיב לתיבת הדו-שיח של בקשת ההרשאה, מערכת Android קוראת לפונקציית ה-callback הזו.
מדביקים את הקוד הזה אחרי השיטה getLocationPermission()
:
MapsActivity.java onRequestPermissionsResult()
/**
* Handles the result of the request for location permissions
*/
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String permissions[],
@NonNull int[] grantResults) {
mLocationPermissionGranted = false;
switch (requestCode) {
case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mLocationPermissionGranted = true;
}
}
}
}
11. קבלת המיקום הנוכחי ואחזור של מקומות סבירים
כשהמשתמש לוחץ על בחירת מקום בסרגל האפליקציות, האפליקציה קוראת לשיטה pickCurrentPlace()
, שקוראת לשיטה getDeviceLocation()
שהגדרתם קודם. השיטה getDeviceLocation
קוראת לשיטה אחרת, getCurrentPlaceLikelihoods,
, אחרי אחזור המיקום האחרון של המכשיר.
שליחת קריאה ל-API של findCurrentPlace וטיפול בתגובה
getCurrentPlaceLikelihoods
יוצר findCurrentPlaceRequest
וקורא למשימה Places API findCurrentPlace
. אם המשימה מצליחה, היא מחזירה findCurrentPlaceResponse
, שמכיל רשימה של אובייקטים מסוג placeLikelihood
. לכל אחד מהם יש מספר מאפיינים, כולל השם והכתובת של המקום, וההסתברות שאתם נמצאים במקום הזה (ערך כפול מ-0 עד 1). השיטה הזו מטפלת בתגובה על ידי בניית רשימות של פרטי מקומות מתוך placeLikelihoods
.
הקוד הזה מבצע איטרציה על חמשת המקומות הסבירים ביותר ומוסיף לרשימה את המקומות עם סבירות גבוהה מ-0, ואז מעבד את הרשימה. אם רוצים להציג יותר או פחות מחמש, צריך לערוך את הקבוע M_MAX_ENTRIES
.
מדביקים את הקוד הזה אחרי השיטה onMapReady
.
MapsActivity.java getCurrentPlaceLikelihoods()
private void getCurrentPlaceLikelihoods() {
// Use fields to define the data types to return.
List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS,
Place.Field.LAT_LNG);
// Get the likely places - that is, the businesses and other points of interest that
// are the best match for the device's current location.
@SuppressWarnings("MissingPermission") final FindCurrentPlaceRequest request =
FindCurrentPlaceRequest.builder(placeFields).build();
Task<FindCurrentPlaceResponse> placeResponse = mPlacesClient.findCurrentPlace(request);
placeResponse.addOnCompleteListener(this,
new OnCompleteListener<FindCurrentPlaceResponse>() {
@Override
public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
if (task.isSuccessful()) {
FindCurrentPlaceResponse response = task.getResult();
// Set the count, handling cases where less than 5 entries are returned.
int count;
if (response.getPlaceLikelihoods().size() < M_MAX_ENTRIES) {
count = response.getPlaceLikelihoods().size();
} else {
count = M_MAX_ENTRIES;
}
int i = 0;
mLikelyPlaceNames = new String[count];
mLikelyPlaceAddresses = new String[count];
mLikelyPlaceAttributions = new String[count];
mLikelyPlaceLatLngs = new LatLng[count];
for (PlaceLikelihood placeLikelihood : response.getPlaceLikelihoods()) {
Place currPlace = placeLikelihood.getPlace();
mLikelyPlaceNames[i] = currPlace.getName();
mLikelyPlaceAddresses[i] = currPlace.getAddress();
mLikelyPlaceAttributions[i] = (currPlace.getAttributions() == null) ?
null : TextUtils.join(" ", currPlace.getAttributions());
mLikelyPlaceLatLngs[i] = currPlace.getLatLng();
String currLatLng = (mLikelyPlaceLatLngs[i] == null) ?
"" : mLikelyPlaceLatLngs[i].toString();
Log.i(TAG, String.format("Place " + currPlace.getName()
+ " has likelihood: " + placeLikelihood.getLikelihood()
+ " at " + currLatLng));
i++;
if (i > (count - 1)) {
break;
}
}
// COMMENTED OUT UNTIL WE DEFINE THE METHOD
// Populate the ListView
// fillPlacesList();
} else {
Exception exception = task.getException();
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
Log.e(TAG, "Place not found: " + apiException.getStatusCode());
}
}
}
});
}
הזזת המצלמה במפה למיקום הנוכחי של המכשיר
אם המשתמש מעניק הרשאה, האפליקציה מאחזרת את המיקום האחרון של המשתמש ומזיזה את המצלמה כך שהמיקום הזה יהיה במרכז.
אם המשתמש דוחה את ההרשאה, האפליקציה פשוט מעבירה את המצלמה למיקום ברירת המחדל שמוגדר בין הקבועים בתחילת הדף הזה (בדוגמת הקוד, זהו סידני, אוסטרליה).
מדביקים את הקוד הזה אחרי השיטה getPlaceLikelihoods()
:
MapsActivity.java getDeviceLocation()
private void getDeviceLocation() {
/*
* Get the best and most recent location of the device, which may be null in rare
* cases when a location is not available.
*/
try {
if (mLocationPermissionGranted) {
Task<Location> locationResult = mFusedLocationProviderClient.getLastLocation();
locationResult.addOnCompleteListener(this, new OnCompleteListener<Location>() {
@Override
public void onComplete(@NonNull Task<Location> task) {
if (task.isSuccessful()) {
// Set the map's camera position to the current location of the device.
mLastKnownLocation = task.getResult();
Log.d(TAG, "Latitude: " + mLastKnownLocation.getLatitude());
Log.d(TAG, "Longitude: " + mLastKnownLocation.getLongitude());
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(mLastKnownLocation.getLatitude(),
mLastKnownLocation.getLongitude()), DEFAULT_ZOOM));
} else {
Log.d(TAG, "Current location is null. Using defaults.");
Log.e(TAG, "Exception: %s", task.getException());
mMap.moveCamera(CameraUpdateFactory
.newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
}
getCurrentPlaceLikelihoods();
}
});
}
} catch (SecurityException e) {
Log.e("Exception: %s", e.getMessage());
}
}
בדיקה של הרשאות המיקום כשהמשתמש לוחץ על 'בחירת מקום'
כשמשתמש מקיש על בחירת מקום, השיטה הזו בודקת אם יש הרשאות מיקום ומבקשת מהמשתמש הרשאה אם היא לא ניתנה.
אם המשתמש העניק הרשאה, הפונקציה קוראת ל-getDeviceLocation
כדי להתחיל את התהליך של קבלת המיקומים הנוכחיים הסבירים.
- הוספת השיטה הזו אחרי
getDeviceLocation()
:
MapsActivity.java pickCurrentPlace()
private void pickCurrentPlace() {
if (mMap == null) {
return;
}
if (mLocationPermissionGranted) {
getDeviceLocation();
} else {
// The user has not granted permission.
Log.i(TAG, "The user did not grant location permission.");
// Add a default marker, because the user hasn't selected a place.
mMap.addMarker(new MarkerOptions()
.title(getString(R.string.default_info_title))
.position(mDefaultLocation)
.snippet(getString(R.string.default_info_snippet)));
// Prompt the user for permission.
getLocationPermission();
}
}
- אחרי שמגדירים את
pickCurrentPlace
, מאתרים את השורה ב-onOptionsItemSelected()
שקוראת ל-pickCurrentPlace
ומבטלים את ההערה שלה.
MapsActivity.java onOptionItemSelected()
case R.id.action_geolocate:
// COMMENTED OUT UNTIL WE DEFINE THE METHOD
// Present the Current Place picker
pickCurrentPlace();
return true;
רוצים לנסות?
אם מפעילים את האפליקציה עכשיו ומקישים על בחירת מקום, אמורה להופיע בקשה להרשאות מיקום.
- אם תאשרו את ההרשאה, ההעדפה הזו תישמר ולא תוצג לכם בקשה לאישור. אם תסרבו לתת הרשאה, תופיע בקשה בפעם הבאה שתקישו על הכפתור.
- למרות ש-
getPlaceLikelihoods
אחזר את המקומות הנוכחיים האפשריים, הם עדיין לא מוצגים ב-ListView
. ב-Android Studio, אפשר ללחוץ על ⌘6 כדי לבדוק את היומנים ב-Logcat לגבי הצהרות שתויגו בתג MapsActivity, וכך לוודא שהשיטות החדשות פועלות בצורה תקינה. - אם הענקתם הרשאה, היומנים יכללו הצהרה לגבי
Latitude:
והצהרה לגביLongitude:
שבהן מוצג המיקום המזוהה של המכשיר. אם השתמשתם במפות Google ובתפריט המורחב של האמולטור כדי לציין מיקום לאמולטור, המיקום הזה יופיע בהצהרות האלה. - אם הקריאה אל
findCurrentPlace
הצליחה, היומנים יכללו חמש הצהרות שמדפיסות את השמות והמיקומים של חמשת המקומות הסבירים ביותר.
12. איכלוס הכלי לבחירת המקום הנוכחי
הגדרת handler למקומות שנבחרו
בואו נחשוב מה אנחנו רוצים שיקרה כשהמשתמש ילחץ על פריט ב-ListView
. כדי לאשר את בחירת המשתמש לגבי המקום שבו הוא נמצא כרגע, אפשר להוסיף סמן למפה במיקום הזה. אם המשתמש לוחץ על הסמן הזה, מופיע חלון מידע עם שם המקום והכתובת שלו.
מדביקים את הפונקציה לטיפול בקליקים אחרי השיטה pickCurrentPlace
.
MapsActivity.java listClickedHandler
private AdapterView.OnItemClickListener listClickedHandler = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
// position will give us the index of which place was selected in the array
LatLng markerLatLng = mLikelyPlaceLatLngs[position];
String markerSnippet = mLikelyPlaceAddresses[position];
if (mLikelyPlaceAttributions[position] != null) {
markerSnippet = markerSnippet + "\n" + mLikelyPlaceAttributions[position];
}
// Add a marker for the selected place, with an info window
// showing information about that place.
mMap.addMarker(new MarkerOptions()
.title(mLikelyPlaceNames[position])
.position(markerLatLng)
.snippet(markerSnippet));
// Position the map's camera at the location of the marker.
mMap.moveCamera(CameraUpdateFactory.newLatLng(markerLatLng));
}
};
איכלוס של ListView
אחרי שיש לכם רשימה של המקומות שסביר להניח שהמשתמש מבקר בהם כרגע, אתם יכולים להציג את האפשרויות האלה למשתמש בListView
. אפשר גם להגדיר את ListView
click listener כך שישתמש ב-click handler שהגדרתם זה עתה.
מדביקים את השיטה הזו אחרי click handler:
MapsActivity.java fillPlacesList()
private void fillPlacesList() {
// Set up an ArrayAdapter to convert likely places into TextViews to populate the ListView
ArrayAdapter<String> placesAdapter =
new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mLikelyPlaceNames);
lstPlaces.setAdapter(placesAdapter);
lstPlaces.setOnItemClickListener(listClickedHandler);
}
אחרי שמגדירים את fillPlacesList
, מחפשים את השורה לקראת סוף findPlaceLikelihoods
שקוראת ל-fillPlacesList
ומבטלים את ההערה שלה.
MapsActivity.java fillPlaceLikelihoods()
// COMMENTED OUT UNTIL WE DEFINE THE METHOD
// Populate the ListView
fillPlacesList();
זה כל הקוד שצריך בשביל הכלי לבחירת המיקום הנוכחי.
13. הפעלת האפליקציה
בדיקת בחירת מקום
- מריצים את האפליקציה שוב.
הפעם, כשתקישו על בחירת מקום, האפליקציה תמלא את הרשימה במקומות עם שמות שנמצאים קרוב למיקום. בקרבת המיקום הזה במאווי נמצאים מקומות כמו Ululani's Hawaiian Shave Ice ו-Sugar Beach Bake Shop. הרשימה הזו כוללת מקומות שסביר להניח שאתם נמצאים בהם, כי הם קרובים מאוד לקואורדינטות של המיקום.
- לוחצים על שם של מקום ב
ListView
.
סמן יתווסף למפה.
- מקישים על הסמן.
תוכלו לראות את פרטי המקום.
בדיקת מיקום אחר
אם אתם רוצים לשנות את המיקום ואתם משתמשים באמולטור, מיקום המכשיר לא מתעדכן אוטומטית כשאתם מעדכנים את קואורדינטות המיקום בתפריט המורחב של האמולטור.
כדי לעקוף את הבעיה הזו, צריך לפעול לפי השלבים הבאים כדי להשתמש באפליקציית מפות Google המקורית כדי לכפות עדכונים למיקום של האמולטור:
- פתח את מפות Google.
- מקישים על ... > מיקום כדי לשנות את קו האורך וקו הרוחב לקואורדינטות חדשות, ואז מקישים על שליחה.
- לדוגמה, אפשר להשתמש בקו הרוחב: 49.2768 ובקו האורך: -123.1142 כדי להגדיר את המיקום למרכז העיר ונקובר, קנדה.
- מוודאים שמפות Google התמקדה מחדש בקואורדינטות החדשות. יכול להיות שתצטרכו להקיש על הלחצן המיקום שלי באפליקציית מפות Google כדי לבקש את המיקום המרכזי.
- חוזרים לאפליקציה 'המקום הנוכחי שלי' ומקישים על בחירת מקום כדי לראות את המפה עם הקואורדינטות החדשות ואת הרשימה החדשה של המקומות הנוכחיים האפשריים.
זה הכול! יצרתם אפליקציה פשוטה שבודקת את המקומות במיקום הנוכחי ומציגה את הסבירות שאתם נמצאים במקום מסוים. תיהנו!
עכשיו אפשר להפעיל את האפליקציה עם השינויים שביצעת כדי להשלים את שלב הבונוס הזה.
14. השלבים הבאים
כדי למנוע גניבה של מפתח ה-API, צריך לאבטח אותו כך שרק אפליקציית Android שלכם תוכל להשתמש במפתח. אם לא מגבילים את השימוש במפתח, כל מי שמחזיק במפתח יכול להשתמש בו כדי לקרוא לממשקי Google Maps Platform API ולגרום לחיוב שלכם.
קבלת אישור SHA-1
תצטרכו את זה בהמשך כשתגבילו את מפתחות ה-API. בהמשך מפורטות הוראות לקבלת אישור ניפוי הבאגים.
ב-Linux או ב-macOS, פותחים חלון טרמינל ומזינים את הפקודה הבאה:
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
ב-Windows Vista וב-Windows 7, מריצים את הפקודה הבאה:
keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
הפלט אמור להיראות כך:
Alias name: androiddebugkey Creation date: Jan 01, 2013 Entry type: PrivateKeyEntry Certificate chain length: 1 Certificate[1]: Owner: CN=Android Debug, O=Android, C=US Issuer: CN=Android Debug, O=Android, C=US Serial number: 4aa9b300 Valid from: Mon Jan 01 08:04:04 UTC 2013 until: Mon Jan 01 18:04:04 PST 2033 Certificate fingerprints: MD5: AE:9F:95:D0:A6:86:89:BC:A8:70:BA:34:FF:6A:AC:F9 SHA1: BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75 Signature algorithm name: SHA1withRSA Version: 3
השורה שמתחילה ב-SHA1 מכילה את טביעת האצבע של האישור מסוג SHA-1. טביעת האצבע היא רצף של 20 מספרים הקסדצימליים דו-ספרתיים שמופרדים באמצעות נקודתיים.
כשמוכנים לפרסם אפליקציה, משתמשים בהוראות שבמסמכי התיעוד האלה כדי לאחזר את אישור הפרסום.
הוספת הגבלות למפתח ה-API
- ב-Cloud Console, עוברים אל APIs & Services (ממשקי API ושירותים) > Credentials (אמצעי אימות).
המפתח שבו השתמשתם לאפליקציה הזו אמור להופיע בקטע 'מפתחות API'.
- לוחצים על
כדי לערוך את הגדרות המקשים.
- בדף של מפתח ה-API, אחרי Key restrictions, מגדירים את Application restrictions באופן הבא:
- בוחרים באפשרות אפליקציות ל-Android ופועלים לפי ההוראות.
- לוחצים על הוספת פריט.
- מזינים את שם החבילה ואת טביעת האצבע של אישור SHA-1 (שנמצאו בקטע הקודם).
לדוגמה:
com.google.codelab.currentplace
BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75s
- כדי להוסיף הגנה, מגדירים את ההגבלות על ממשקי API באופן הבא.
- אחרי ההגבלות על ה-API, בוחרים באפשרות Restrict key.
- בוחרים באפשרות Maps SDK for Android (SDK של מפות ל-Android) וב-Places API (Places API).
- לוחצים על סיום ואז על שמירה.
15. מזל טוב
יצרתם אפליקציה פשוטה שבודקת מהם המקומות הסבירים ביותר במיקום הנוכחי ומוסיפה סמן למפה עבור המקום שהמשתמש בוחר.
מידע נוסף
- כדי לפתח מהר יותר, כדאי להשתמש ב-Maps SDK for Android Utility Library. הכלים האלה מבצעים את העבודה הקשה במשימות הפופולריות ביותר באפליקציות שמשתמשות בפלטפורמה של מפות Google.
- כדי לראות דוגמאות נוספות לקוד שמדגימות את רוב התכונות של ערכות ה-SDK של הפלטפורמה של מפות Google ל-Android, אפשר לשכפל מאגרי מידע של דוגמאות ל-Maps SDK ל-Android ושל הדגמות של Places SDK ל-Android.
- כדי ללמוד איך לטפל בהרשאות מיקום עם שלושה מצבים ב-Android Q, כדאי להשלים את ה-codelab קבלת עדכוני מיקום ב-Android עם Kotlin.