יצירת בוחר משלך למקום נוכחי ל-Android (Java)

1. לפני שמתחילים

ניתן ללמוד איך להשתמש ב-SDK של מפות Google וב-SDK ל-Android כדי להציג למשתמשים רשימה של מקומות כדי לזהות את המיקומים הנוכחיים שלהם.

bd07a9ad2cb27a06.png

דרישות מוקדמות

  • מיומנויות Java בסיסיות

הפעולות שתבצעו:

  • הוספת מפה לאפליקציה ל-Android.
  • השתמשו בהרשאות המיקום כדי למקם את המשתמש במיקום גיאוגרפי.
  • אחזור מקומות ליד המיקום הנוכחי של המשתמש.
  • להציג למשתמש כנראה את 'מקומות' כדי לזהות את המיקום הנוכחי שלו.

מה תפתחו

אתם בונים את אפליקציית Android מההתחלה, אבל אפשר להוריד את הקוד לדוגמה להשוואה במהלך ניפוי באגים. מורידים את הקוד לדוגמה מ-GitHub. אם GitHub מוגדר לשימוש בשורת הפקודה, מזינים את הפרטים הבאים:

git clone https://github.com/googlecodelabs/current-place-picker-android.git

אם תיתקלו בבעיות (באגים בקוד, שגיאות דקדוק, ניסוח לא ברור או משהו אחר) כשתתבצעו באמצעות קוד Lab זה, דווחו על הבעיה באמצעות הקישור דיווח על שגיאה בפינה הימנית התחתונה של שיעור הקוד.

2. שנתחיל?

לפני שמתחילים במעבדה זו, צריך להגדיר את הדברים הבאים:

Android Studio

מורידים את Android Studio מהכתובת https://developer.android.com/studio.

אם כבר יש לכם Android Studio, מוודאים שיש לכם את הגרסה העדכנית ביותר. לשם כך, לוחצים על Android Studio > בודקים אם יש עדכונים....

1f36bae83b64e33.png

שיעור ה-Lab הזה נכתב באמצעות Android Studio 3.4.

Android SDK

ב-Android Studio, אפשר להגדיר את ערכות ה-SDK הרצויות באמצעות מנהל ה-SDK. בשיעור Lab זה נעשה שימוש ב-Android Q SDK.

  1. במסך הפתיחה של Android Studio, לוחצים על הגדרה > מנהל SDK.

d3fa03c269ec231c.png

  1. מסמנים את תיבת הסימון הרצויה ל-SDK ולוחצים על אישור.

אם עדיין אין לכם את ה-SDK, הפעולה הזו תתחיל להוריד את ה-SDK למכשיר.

884e0aa1314f70d.png

שירותי Google Play

מתוך מנהל ה-SDK, צריך גם להתקין את שירותי Google Play.

  1. לוחצים על הכרטיסייה SDK SDK ובוחרים בתיבת הסימון Google Play Services.

מעדכנים אם הסטטוס הוא עדכון זמין.

ad6211fd78f3b629.png

3. הכנת האמולטור

כדי להפעיל את האפליקציה, יש לך אפשרות לחבר מכשיר משלך או להשתמש באמולטור של Android.

אם אתם משתמשים במכשיר משלכם, דלגו אל הוראות למכשיר המציאותי: מעדכנים את שירותי Google Play בסוף הדף הזה.

הוספת אמולטור

  1. במסך הפתיחה של Android Studio, לוחצים על הגדרה &ניהול AVD.

5dd2d14c9c56d3f9.png

פעולה זו תפתח את תיבת הדו-שיח של ניהול מכשיר וירטואלי של Android.

  1. לוחצים על יצירת מכשיר וירטואלי... כדי לפתוח רשימה של מכשירים לבחירה.

2d44eada384f8b35.png

  1. בוחרים מכשיר עם סמל Play d5722488d80cd6be.png בעמודה חנות Play ולוחצים על הבא.

e0248f1c6e85ab7c.png

תופיע קבוצה של תמונות מערכת שניתן להתקין. אם המילה Q מטרגטת ל-Android 9.+ (Google Play) ולצידה יש המילה הורדה, לוחצים על הורדה.

316d0d1efabd9f24.png

  1. לוחצים על הבא כדי לתת שם למכשיר הווירטואלי, ולאחר מכן לוחצים על סיום.

חוזרים לרשימה של המכשירים הווירטואליים.

  1. לוחצים על 'התחלה' ba8adffe56d3b678.png לצד המכשיר החדש:

7605864ed27f77ea.png

אחרי כמה דקות, האמולטור ייפתח.

הוראות אמולטור – עדכון שירותי Google Play

  1. לאחר האמולטור מופעל, לוחצים על ... בסרגל הניווט שמופיע**.**

2e1156e02643d018.png

תיפתח תיבת דו-שיח של פקדים מורחבים.

  1. לוחצים על Google Play בתפריט.

אם יש עדכון זמין, לוחצים על עדכון.

5afd2686c5cad0e5.png

  1. יש להיכנס לאמולטור באמצעות חשבון Google.

אתם יכולים להשתמש בחשבון משלכם או ליצור חשבון חדש בחינם כדי להפריד בין הבדיקות שלכם לבין המידע האישי.

לאחר מכן Google Play נפתחת לשירותי Google Play.

  1. לוחצים על עדכון כדי להוריד את הגרסה האחרונה של שירותי Google Play.

f4bc067e80630b9c.png

אם מתבקשים להשלים את הגדרת החשבון ולהוסיף אפשרות תשלום, לוחצים על דילוג.

הגדרת מיקום באמולטור

  1. אחרי האמולטור, מקלידים "maps" בסרגל החיפוש שבמסך הבית כדי להציג את הסמל של אפליקציית מפות Google.

2d996aadd53685a6.png

  1. יש ללחוץ על הסמל כדי להפעיל.

תופיע מפת ברירת המחדל.

  1. בפינה השמאלית התחתונה של המפה, לוחצים על המיקום שלך c5b4e2fda57a7e71.png.

עליך להעניק לטלפון הרשאות לשימוש במיקום.

f2b68044eabca151.png

  1. לוחצים על ... כדי לפתוח את תפריט פקדים מורחבים.
  2. לחץ על הכרטיסייה מיקום.
  3. מזינים קו אורך וקו רוחב.

כאן מזינים את כל מה שרוצים, אבל כדאי להקפיד למקם אותו באזור שיש בו הרבה מקומות.

(השתמשו ב-Latitude 20.7818 ובקו האורך -156.4624 עבור העיר Kihei במאוואי בהוואי כדי לשכפל את התוצאות ממעבדה זו.)

  1. לוחצים על שליחה והמפה מתעדכנת עם המיקום הזה.

f9576b35218f4187.png

אתם מוכנים להריץ את האפליקציה ולבדוק אותה עם מיקום.

הוראות למכשירים אמיתיים – עדכון השירותים של Google Play

אם אתם משתמשים במכשיר Android אמיתי, יש לבצע את הפעולות הבאות:

  1. בסרגל החיפוש שבמסך הבית, מחפשים את שירותי Google Play ופותחים אותם.
  2. לוחצים על פרטים נוספים.

אם האפשרות זמינה, לוחצים על עדכון.

ad16cdb975b5c3f7.png baf0379ef8a9c88c.png

4. יצירת מעטפת אפליקציה באמצעות פעילות במפות Google

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

c9c80aa8211a8761.png

תיבת הדו-שיח הגדרת הפרויקט שלך תיפתח. כאן נותנים שם לאפליקציה ויוצרים את החבילה על סמך הדומיין שלכם.

אלה ההגדרות של אפליקציה בשם 'מקום נוכחי', שתואמת לחבילה com.google.codelab.currentplace.

37f5b93b94ee118c.png

  1. בוחרים באפשרות Java בתור השפה ובוחרים באפשרות שימוש באובייקטים מסוג androidx.*

להשאיר את ברירות המחדל בשאר ההגדרות.

  1. לוחצים על סיום.

5. הוספת יחסי תלות של שירותי Google לקובץ ה-build של Gradle

כדי לגשת להרשאות מיקום ב-Android, צריך ממשק API של Google לזיהוי מיקום ופעילות ב-Google Play. מידע נוסף על הוספת ה-API הזה ועוד ממשקי API של שירותי Google Play זמין במאמר הגדרת Google Play Services.

פרויקטים ב-Android Studio כוללים בדרך כלל שני קובצי build.gradle. אחד מהם מיועד לפרויקט בסך הכול ואחד מיועד לאפליקציה. אם כלי המחקר של Android Studio מוצג בתצוגת Android, שניהם יוצגו בתיקייה Gradle Scripts. כדי להוסיף את שירותי Google צריך לערוך את הקובץ build.gradle (Module: app).

f3043429cf719c47.png

  1. מוסיפים שתי שורות לקטע dependencies כדי להוסיף את שירותי Google למיקום ואת ממשק ה-API של 'מקומות' (בקוד לדוגמה בהקשר).

build.gradle (מודול: 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 ואת Place API.

הגדרת מפות Google

אם עדיין אין לכם חשבון Google Cloud Platform ופרויקט שבו מופעל חיוב, כדאי לעיין במדריך תחילת העבודה עם הפלטפורמה של מפות Google ליצירת חשבון לחיוב ופרויקט.

  1. ב-Cloud Console, לוחצים על התפריט הנפתח של הפרויקט ובוחרים את הפרויקט שבו רוצים להשתמש ב-Codelab הזה.

  1. מפעילים את ממשקי ה-API ואת ערכות ה-SDK של מפות Google הנדרשים למעבדת קוד זו ב-Google Cloud Marketplace. כדי לעשות זאת, יש לבצע את השלבים המפורטים בסרטון הזה או בתיעוד הזה.
  2. יוצרים מפתח API בדף פרטי הכניסה ב-Cloud Console. ניתן לבצע את השלבים המפורטים בסרטון הזה או בתיעוד הזה. לכל הבקשות שנשלחות לפלטפורמה של מפות Google נדרש מפתח API.

מעתיקים את מפתח ה-API שיצרתם. חוזרים אל Android Studio ומחפשים את הקובץ google_maps_api.xml בקטע Android > app > re; g;

יש להחליף את YOUR_KEY_HERE במפתח ה-API שהעתקת.

aa576e551a7a1009.png

האפליקציה שלך מוגדרת עכשיו.

7. עריכה של קובץ הפריסה

  1. בסייר הפרויקטים שלך, פתח את הקובץ activity_maps.xml ב-Android & gt; app> res > layout.

4e0d986480c57efa.png

  1. ממשק המשתמש הבסיסי ייפתח בצד שמאל של המסך, עם כרטיסיות בחלק התחתון שמאפשרות לך לבחור את עורך העיצוב או את הטקסט לפריסה שלך. בוחרים באפשרות טקסט ומחליפים את כל התוכן של קובץ הפריסה בתווים הבאים:

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>

כך תקבלו ממשק משתמש שנראה כך:

1bf786808a4697ce.png

8. הגדרה של סרגל האפליקציות

כדי לתת למשתמש לחצן בלחיצה כשהוא רוצה לבחור את המקום הנוכחי שלו, יש להוסיף סרגל אפליקציות עם סמל שימצא את המקום הנוכחי של המשתמש ויציג את המקומות שקרובים אליו. הממשק אמור להיראות כך:

3a17c92b613a26c5.png

בטלפון, רק הסמל מוצג. בטאבלט עם יותר מקום, הטקסט כלול גם הוא.

יצירת הסמל

  1. בסייר הפרויקט, לוחצים על Android &gt. אפליקציה, לוחצים לחיצה ימנית על התיקייה res ובוחרים באפשרות חדש &gt. נכס תמונה.

Studio Studio ייפתח.

  1. בתפריט סוג סמל, לוחצים על סמלים של סרגל הפעולות והכרטיסיות.
  2. נותנים שם לנכס ic_geolocate.
  3. בוחרים באפשרות קליפ ארט כסוג הנכס**.**
  4. לוחצים על הגרפיקה לצד קליפ ארט.

פעולה זו תפתח את החלון Select Icon.

  1. בוחרים סמל.

אתם יכולים להשתמש בסרגל החיפוש כדי למצוא סמלים הקשורים לכוונה שלכם.

  1. חפשו את location ובחרו סמל הקשור למיקום.

הסמל המיקום שלי זהה לסמל שבו נעשה שימוש באפליקציית מפות Google כשמשתמש רוצה להצמיד את המצלמה למיקום הנוכחי שלו.

  1. לוחצים על אישור > הבא > סיום ומוודאים שיש תיקייה חדשה בשם drawable שמכילה את קובצי הסמל החדשים.

b9e0196137ed18ae.png

הוספה של משאבי מחרוזת

  1. בסייר הפרויקטים, לוחצים על Android > app > res > ערכים ופותחים את הקובץ strings.xml.
  2. יש להוסיף את השורות הבאות אחרי <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>

הוספה של סרגל האפליקציות

  1. בסייר הפרויקט, לוחצים על Android > אפליקציה, לוחצים לחיצה ימנית על התיקייה res ובוחרים באפשרות חדש &gt. ספרייה כדי ליצור ספריית משנה חדשה בקטע app/src/main/res.
  2. יש לתת שם לספרייה menu.
  3. לחץ לחיצה ימנית על התיקייה menu ובחר חדש > קובץ.
  4. שם הקובץ menu.xml.
  5. מדביקים את הקוד הבא:
<?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>

עדכון הסגנון של סרגל האפליקציות

  1. בסייר הפרויקטים, הרחיבו את Android > app > res > values ופתחו את הקובץ styles.xml בפנים.
  2. בתג <style>, עורכים את נכס ההורה כך: "Theme.AppCompat.NoActionBar".
  3. שימו לב לנכס name שבו תשתמשו בשלב הבא.

styles.xml

<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">

עדכון העיצוב של האפליקציה ב-AndroidManifest.xml

  1. לוחצים על Android ; > app> manifests ופותחים את הקובץ AndroidManifest.xml.
  2. מאתרים את השורה 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. אתחול האפליקציה

  1. בסייר הפרויקטים שלכם, מאתרים את הקובץ MapsActivity.java.

היא תופיע בתיקייה המתאימה לחבילה שיצרת לאפליקציה בשלב 1.

8b0fa27d417f5f55.png

  1. פותחים את הקובץ &בעורך הקוד של Java.

ייבוא של SDK ותלויים אחרים של מקומות

יש להוסיף את השורות האלה בחלק העליון של MapsActivity.java, ולהחליף את הצהרות הייבוא הקיימות.

הם כוללים את הייבוא הקיים ומוסיפים עוד הרבה קוד בקוד במעבדה זו.

MapsActivity.JavaScript

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;

עדכון חתימת הכיתה

ממשק ה-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;

עדכון השיטה onCreate

יש לעדכן את השיטה onCreate כדי לטפל בהרשאות המשתמש בזמן ריצה עבור שירותי מיקום, להגדיר את רכיבי ממשק המשתמש וליצור לקוח API של מקומות.

מוסיפים את שורות הקוד הבאות לגבי סרגל הכלים של הפעולה, הגדרת הצפיות והלקוח של מקומות עד סוף השיטה הקיימת של onCreate().

MapsActivity.JavaScript 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.

MapsActivity.JavaScript ב-CreateOptionsMenu() ו-onOptionsItemSelected()

    @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);

        }
    }

לבדיקה

  1. ב-Android Studio, לוחצים על הפעלה או על הפעלת התפריט > הפעלת 'app'.

28bea91c68c36fb2.png

  1. אתם מתבקשים לבחור את יעד הפריסה. האמולטור הפעיל אמור להופיע ברשימה הזו. בוחרים אותו, ו-Android Studio יפרס עבורכם את האפליקציה לאמולטור.

f44658ca91f6f41a.png

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

68eb8c70f4748350.png

המיקוד של המפה לא עובר למיקום של המשתמש אלא אם ביקשת הרשאת גישה למיקום של המכשיר.

10. בקשת הרשאות מיקום וטיפול בהן

בקשת הרשאות מיקום אחרי שהמפה מוכנה

  1. יש להגדיר שיטה בשם getLocationPermission שמבקשת הרשאות משתמש.

יש להדביק את הקוד הזה מתחת לשיטה onOptionsSelected שיצרת עכשיו.

MapsActivity.JavaScript 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);
        }
    }
  1. יש להוסיף שתי שורות לסוף של השיטה onMapReady הקיימת כדי להפעיל פקדי זום ולבקש הרשאות מיקום מהמשתמש.

MapsActivity.JavaScript ב-MapReady()

   @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.

יש להדביק את הקוד הזה אחרי השיטה getLocationPermission():

MapsActivity.JavaScript onRequestRequestResult()

   /**
     * 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, אחרי אחזור של מיקום המכשיר האחרון.

התקשרו ל-FindCurrentPlace API וטיפול בתגובה

האפליקציה getCurrentPlaceLikelihoods יוצרת את findCurrentPlaceRequest ומגדירה את משימת API של מקומות findCurrentPlace. אם המשימה מצליחה, היא מחזירה findCurrentPlaceResponse, שמכיל רשימה של אובייקטים מסוג placeLikelihood. לכל אחד מהם יש מספר מאפיינים, כולל השם והכתובת של המקום, והסבירות שאתם נמצאים באותו מקום (ערך כפול מ-0 עד 1). שיטה זו מטפלת בתגובה על ידי יצירת רשימות של פרטי מקומות מה-placeLikelihoods.

קוד זה חוזר על פני חמשת המקומות בעלי הסבירות הגבוהה ביותר ומוסיף מקומות עם סבירות גבוהה המגרדת מ-0 לרשימה שלאחר מכן מתבצע רינדור. אם ברצונך להציג יותר או פחות מ-5, עליך לערוך את הקבוע של M_MAX_ENTRIES.

יש להדביק את הקוד הזה אחרי השיטה onMapReady.

MapsActivity.JavaScript getCurrentPlaceLikeliities()

   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.JavaScript 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 כדי להתחיל בתהליך קבלה של המקומות שבהם סביר להניח שאתם נמצאים.

  1. הוספת השיטה הזו אחרי getDeviceLocation():

MapsActivity.JavaScript selectCurrentPlace()

   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();
        }
    }
  1. סיימת להגדיר את pickCurrentPlace, ועכשיו עליך למצוא את השורה ב-onOptionsItemSelected() שמתקשרת אל pickCurrentPlace ולבטל את ההערה.

MapsActivity.JavaScript 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 עבור דוחות שתויגו במפות פעילות כדי לוודא שהשיטות החדשות פועלות כראוי.
  • אם הענקת הרשאה, היומנים כוללים הצהרה עבור Latitude: והצהרה עבור Longitude: שבה מופיע המיקום של המכשיר. אם השתמשתם במפות Google ובאמולטור המורחב של התפריט לאמולטור כדי לציין מיקום לאמולטור, הביטויים האלה מציגים את המיקום.
  • אם הקריאה אל findCurrentPlace בוצעה בהצלחה, היומנים מכילים חמישה הצהרות מודפסות עם השמות והמיקומים של חמשת המקומות בעלי הסיכוי הגבוה ביותר.

d9896a245b81bf3.png

12. אכלס את בוחר המקום הנוכחי

הגדרת handler של מקומות נבחרים

יש לנו שאלה לגבי מה שאנחנו רוצים לעשות כשהמשתמש לוחץ על פריט ב-ListView. כדי לאשר את בחירת המשתמש לגבי המקום שבו הוא נמצא כעת, ניתן להוסיף סמן למפה במקום זה. אם המשתמש לוחץ על הסמן הזה, ייפתח חלון מידע שמציג את שם הכתובת ואת הכתובת.

יש להדביק את ה-handler של הקליק אחרי השיטה pickCurrentPlace.

MapsActivity.JavaScript 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. אפשר גם להגדיר את event listener של ListView לשימוש ב-handler של הקליקים שהגדרת עכשיו.

יש להדביק את השיטה הזו אחרי רכיב ה-handler של קליקים:

MapsActivity.JavaScriptfillplacesList()

    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.JavaScript

               // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Populate the ListView
                fillPlacesList();

זה כל הקוד הדרוש לבוחר המקום הנוכחי!

13. הפעלת האפליקציה

בדיקה של בחירת מקום

  1. מפעילים שוב את האפליקציה.

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

  1. יש ללחוץ על שם של מקום בListView.

אמור להופיע סמן שנוסף למפה.

  1. מקישים על הסמן.

ניתן לראות פרטי מקום.

e52303cc0de6a513.png 864c74342fb52a01.png

בדיקת מיקום אחר

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

כדי לעקוף את הבעיה, צריך לבצע את השלבים הבאים כדי להשתמש באפליקציית 'מפות Google' המקורית כדי לאלץ עדכונים במיקום של האמולטור:

  1. פתח את 'מפות Google'.
  2. מקישים על ... > מיקום כדי לשנות את קווי הרוחב והאורך לקואורדינטות חדשות, ואז מקישים על שליחה.
  3. לדוגמה, ניתן להשתמש בקווי רוחב: 49.2768 וקו אורך: -123.1142 כדי להגדיר את המיקום בדאונטאון של ונקובר, קנדה.
  4. מוודאים שהאפליקציה מפות Google עברה לאחרונה את הקואורדינטות החדשות שלכם. ייתכן שיהיה צורך להקיש על הלחצן המיקום שלי באפליקציה מפות Google כדי לבקש מרכוז.
  5. חוזרים לאפליקציה 'מקום נוכחי' ומקישים על בחירת מקום כדי לקבל את המפה בקואורדינטות החדשות ולהציג רשימה חדשה של מקומות שקרובים כרגע.

9adb99d1ce25c184.png

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

עכשיו הגיע הזמן להפעיל את אפליקציית ההרצה עם השינויים שביצעת כדי להשלים את שלב הבונוס הזה!

14. השלבים הבאים

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

קבלת אישור 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

  1. ב-Cloud Console, עוברים אל APIs & Services > Credentials (פרטי כניסה).

המפתח שבו השתמשת באפליקציה הזו צריך להיות מופיע בקטע 'מפתחות API'.

  1. לוחצים על 6454a04865d551e6.png כדי לערוך את הגדרות המפתח.

316b052c621ee91c.png

  1. בדף מפתח ה-API, אחרי המגבלות העיקריות, מגדירים את ההגבלות על האפליקציות כך:
  2. בוחרים באפשרות אפליקציות ל-Android ופועלים לפי ההוראות.
  3. לוחצים על הוספת פריט.
  4. יש להזין את שם החבילה ואת טביעת האצבע של אישור 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
  1. כדי להוסיף שכבת אבטחה, מגדירים את ההגבלות על ה-API.
  2. אחרי ההגבלות על ה-API, בוחרים באפשרות הגבלת מפתח.
  3. בוחרים ב-SDK של מפות Google ל-Android ול-places API.
  4. לוחצים על סיום ועל שמירה.

15. מזל טוב

בניית אפליקציה פשוטה שבודקת את המקומות בעלי הסיכוי הגבוה ביותר להופיע במיקום הנוכחי ומוסיפה מפה למיקום שבו המשתמש בוחר.

מידע נוסף