16 มิถุนายน 2558

[Android Code] การใช้งาน Google Maps Android API บน Android Studio เบื้องต้น



        ในการทำแอปพลิเคชันเกี่ยวกับแผนที่ ถ้าจะให้นักพัฒนาเขียนเองทั้งหมดก็คงไม่ใช่เรื่องง่าย แถมเสียเวลาในการพัฒนาไปอีกมาก ดังนั้นวิธียอดนิยมก็คือการใช้ API ของ Map Engine  ที่มีอยู่แล้วของทาง Google ที่เปิดให้นักพัฒนาสามารถเรียกใช้งานได้ เพื่อย่นระยะเวลาในการพัฒนาให้ไวขึ้น สะดวกมากขึ้น ซึ่ง API ตัวนี้จะมีชื่อเรียกว่า Google Maps Android API

        Google Maps Android API ได้มีการอัพเดทเปลี่ยนแปลงมาเรื่อยๆจนล่าสุดเป็นเวอร์ชัน 2 แล้ว โดยจะรวมอยู่ใน Google Play Services ที่เป็นศูนย์กลางทำงานของ Google Services ทั้งหลายบนแอนดรอยด์ ดังนั้นแอปพลิเคชันจะเรียกใช้งาน Google Maps ได้ เครื่องนั้นๆก็จะต้องมี Google Apps ติดตั้งอยู่

        และในบทความนี้จะเป็นวิธีเรียกใช้งาน Google Maps อย่างง่ายบน Android Studio

        Google Maps ไม่สามารถทำงานบน Emulator AVD ได้ เพราะไม่มี Google Apps ดังนั้นควรทดสอบบนเครื่องจริงหรือ Genymotion ที่ติดตั้ง Google Apps ไว้แล้ว

        สิ่งที่จะต้องทำเพื่อเรียกใช้งาน Google Maps จะมีดังนี้

        • นำรหัส SHA1 จาก Keystore ไปขอ API Key สำหรับ Google Maps ที่ Google Developer Console เพื่อกำหนดโปรเจคของแอปพลิเคชัน

        • เพิ่ม Dependencies ของ Google Play Services ลงในโปรเจคของแอปพลิเคชัน

        • กำหนด Layout XML สำหรับแสดง Google Maps

        • เรียกใช้งานด้วยคำสั่งสำหรับ Google Maps เพื่อใช้งานตามต้องการ

การขอ API Key สำหรับ Google Maps

        การขอ API Key นั้นอาจจะมีขั้นตอนยุ่งยากเล็กน้อย แต่ก็ต้องทำ เพราะว่า API Key เป็นสิ่งที่ทาง Google ใช้ระบุว่าแอปของนักพัฒนาคนไหนมีการเรียกใช้งาน Google Maps บ้าง ถึงแม้ว่า Google Maps จะให้ใช้งานฟรีสำหรับฟีเจอร์เบื้องต้น (ฟีเจอร์พิเศษถึงจะต้องเสียเงิน)

        โดย API Key นั้นจะสัมพันธ์กับชุดรหัส SHA1 ใน Keystore ที่ผู้ที่หลงเข้ามาอ่านใช้ Build แอปพลิเคชันตัวนั้นๆและสัมพันธ์กับ Package ของแอปพลิเคชันที่เรียกใช้งาน ดังนั้น API Key นี้จะผูกกับแอปพลิเคชันตัวเดียวเท่านั้น ไม่สามารถนำไปใช้กับแอปตัวอื่นได้ (ทำหลายแอปก็ต้องขอทุกตัว)

ชุดรหัส SHA1 จาก Keystore

        ชุดรหัส SHA1 จาก Keystore ที่ใช้เพื่อขอ API Key นั้นจะมีอยู่สองแบบด้วยกันคือ SHA1 ของ Debug Keystore และ Signed Keystore โดยมีเงื่อนไขอยู่ว่า

        • ใช้ SHA1 จาก Debug Keystore ในขณะที่กำลังพัฒนาแอปพลิเคชันอยู่ ยังไม่ได้ Public ขึ้น Google Play Store หรือ 3rd Party App Store

        • ใช้ SHA1 จาก Signed Keystore เมื่อพัฒนาแอปพลิเคชันเสร็จแล้ว และพร้อมจะ Public ขึ้น Google Play Store หรือ 3rd Party App Store

        ตรงนี้โปรดจำให้ขึ้นใจนะครับ เนื่องจากมีนักพัฒนามือใหม่หลายๆคนชอบมาถามเจ้าของบล็อก เพราะไม่รู้ว่า API Key ต้องใช้คนละตัวกันเวลาทดสอบแอปกับตอน Public ขึ้น Google Play Store (ขี้เกียจตอบบ่อยๆ)

แล้ว Debug Keystore กับ Signed Keystore มันอยู่ที่ไหนล่ะ?

        สำหรับ Debug Keystore จะอยู่ที่

        OS X หรือ Linux
        ~/.android/debug.keystore

        Windows
        C:\Users\<your_user_name>\.android\debug.keystore

        ส่วน Signed Keystore ไม่มีกำหนดที่อยู่ตายตัว เพราะมันคือไฟล์ Keystore ที่ผู้ที่หลงเข้ามาอ่านต้องสร้างเพื่อใช้ Export แอปพลิเคชันเป็น APK ดังนั้นสร้างไฟล์ขึ้นมาแล้วเก็บไว้ที่ไหน ก็อยู่ตรงนั้นน่ะแหละ

การอ่านชุดรหัส SHA1 จาก Keystore

        จะต้องทำผ่าน Terminal (OS X หรือ Linux) หรือ Command Prompt (Windows) ดังนี้

keytool -list -v -keystore <keystore_file_path> -alias <alias_name> -storepass <alias_pass> -keypass <keystore_pass>

        • keystore_file_path คือที่อยู่ของไฟล์ Keystore ที่ต้องการอ่าน SHA1

        • alias_name Alias Name ของ Keystore นั้นๆ

        • alias_pass รหัสผ่านสำหรับ Alias Name

        • keystore_pass รหัสผ่านสำหรับ Keystore


        ถ้าเป็น Debug Keystore ทาง Google ก็ได้กำหนดตายตัวไว้ตั้งแต่แรกแล้ว

        • Alias Name คือ androiddebugkey

        • Alias Password คือ android

        • Keystore Password คือ android

        ยกตัวอย่างเช่น เจ้าของบล็อกใช้ OS X และต้องการ SHA1 ของ Debug Keystore ก็จะต้องใช้คำสั่งดังนี้

keytool -list -v -keystore ~/.android/ -alias androiddebugkey -storepass android -keypass android

        ผลที่ได้จะเป็นดังนี้

      
        จะเห็นตรงแถว SHA1 มีชุดรหัสแสดงอยู่ 20 ชุดด้วยกัน ให้เอา SHA1 ที่ได้จากตรงนี้นี่แหละไปขอ API Key จาก Google Developer Console

        ในกรณีที่ต้องการอ่าน SHA1 จาก Signed Keystore ก็อย่าลืมนะครับว่าผู้ที่หลงเข้ามาอ่านกำหนด Alias Name และรหัสผ่านไว้ว่าอะไร เพราะผู้ที่หลงเข้ามาอ่านเป็นคนกำหนดเองตอนสร้างไฟล์ Keystore

ขอ API Key จาก Google Developer Console

        เข้าหน้าเว็ป Google Developer Console แล้วทำการ Login ด้วย Google Account ให้เรียบร้อยซะ จากนั้นก็จะเข้าสู่หน้าแรกของเว็ป



        ถ้าพึ่งเคยเข้ามาครั้งแรกจะยังไม่มีโปรเจค (พอดีเจ้าของบล็อกเคยทำมาก่อนแล้ว) ให้กดปุ่ม Create Project เพื่อทำการสร้างโปรเจค

        ตั้งชื่อโปรเจคให้เรียบร้อย ชื่ออะไรก็ได้ขอให้จำได้เป็นพอ เสร็จแล้วกดปุ่ม Create



        เมื่อสร้างเสร็จแล้วก็จะเข้าสู่หน้า Overview ของโปรเจคทันที ให้กดเลือกที่ APIs & auth > APIs ที่อยู่ฝั่งซ้ายมือของหน้าเว็ป



         ที่หน้านี้จะเป็นการเลือก API ของ Google ว่าจะต้องการใช้ Google Services ตัวไหน ให้เลือก Google Maps Android API



        กดที่ปุ่ม Enable API เพื่อเปิดใช้งาน Google Maps Android API



        เมื่อเปิดใช้งานเรียบร้อยแล้ว ก็พร้อมใช้งานแล้ว แต่ทว่ายังต้องขอ API Key ก่อนนะ



        ให้เลือกไปที่ APIs & auth > Credentials แล้วกดที่ปุ่ม Create new Key ที่ Public API access เพื่อขอ API Key



        จะมีหน้าต่างเล็กๆแสดงขึ้นมาว่าจะขอ Key สำหรับอะไร ให้กดเลือกที่ปุ่ม Android Key


     
        จะมีหน้าต่างให้ใส่ SHA1 กับ Package Name ของแอปพลิเคชันลงในช่องว่าง



        ยกตัวอย่างว่าแอปของเจ้าของบล็อกกำหนด Package Name ไว้ว่า com.akexorcist.awesomeapp เวลากรอกลงไปในช่องว่างจะต้องใส่ SHA1 ตามด้วย Package Name โดยมีเครื่องหมาย ; เป็นตัวคั่น

        <sha1_key>;<package_name>

        ดังนั้นของเจ้าของบล็อกก็จะใส่ลงไปแปปนี้


        และ API Key สามารถใช้ร่วมกันกับหลายๆแอป โดยใส่หลายๆบรรทัดแบบนี้


        เมื่อเสร็จแล้วก็กดปุ่ม Create ได้เลย

        ให้ดูที่ Public API Access จะมี API Key แสดงอยู่ พร้อมกับบอก Android applications ที่กรอกลงไปเมื่อครูด้วย ให้เอา API Key ไปใช้งานในแอปได้เลย


นำ API Key ไปใช้ในแอปพลิเคชัน

        แน่นอนว่าโปรเจคนั้นต้องสร้างก่อนที่จะขอ API Key ล่ะเนอะ ดังนั้นจึงไม่จำเป็นต้องอธิบายขั้นตอนการสร้างโปรเจค แต่ถ้าอยากจะให้ชีวิตสะดวกสบายขึ้น ตอนสร้างโปรเจคก็จะมี Google Maps Activity ให้เลือกอยู่แล้ว



        แต่เจ้าของบล็อกขอสร้างโปรเจคจาก Blank Activity แทนนะ เพื่ออธิบายวิธีการใช้งาน Google Maps ในแอปพลิเคชัน

        สมมติว่าสร้างโปรเจคเสร็จเรียบร้อยแล้ว (Package Name ให้ตรงกับที่ขอ API Key ด้วยนะ)

เพิ่ม Dependencies ของ Google Play Services ลงในโปรเจค

        ในกรณีที่พึ่งสร้างโปรเจคขึ้นมาจาก Android Studio ก็ให้เปิด build.gradle ของโมดูลที่ชื่อว่า app ขึ้นมาได้เลย แต่ถ้า Import มาจาก Eclipse อีกทีก็ให้ดูว่าโมดูลตัวไหนคือโมดูลหลักของแอพ แล้วจึงเปิด build.gradle ของโมดูลตัวนั้นๆขึ้นมา

        จากนั้นก็เพิ่ม Dependencies เข้าไปดังนี้

compile 'com.google.android.gms:play-services-maps:7.5.0'


        คำสั่งข้างบนเป็นการเพิ่ม Google Maps อย่างเดียวเท่านั้น ซึ่งใน Google Play Services จะมี API หลายๆตัวให้ใช้งาน สามารถดูเพิ่มเติมได้ที่ Setting Up Google Play Services

        แล้วก็ Sync Gradle ให้เรียบร้อยซะ

        หมายเหตุ ตรวจสอบเวอร์ชันของ Dependencies ด้วย เนื่องจาก Google Play Services มีการอัพเดทใหม่อยู่เสมอ และถ้าใช้แค่ Google Maps ก็ใช้เพิ่มแค่ Dependencies ของ Google Maps API เท่านั้น เพราะการเพิ่ม Google Play Services เข้าไปเกินจำเป็นจะทำให้แอพมีขนาดใหญ่โดยไม่จำเป็น และที่สำคัญอาจจะทำให้เจอปัญหา DEX with Over 65K Methods

กำหนดค่าใน Android Manifest

        อย่างแรกสุดคือการกำหนด Meta Data สำหรับเวอร์ชันของ Google Play Services ใน Tag ของ <application> ของ AndroidManifest.xml ดังนี้

<meta-data
    android:name="com.google.android.gms.version"
    android:value="@integer/google_play_services_version" />


        Meta Data ตัวนี้เป็นการกำหนดให้รู้ว่า Google Play Services ที่ใช้งานอยู่เป็นเวอร์ชันอะไร เพราะถ้าเวอร์ชันของแอปเราใหม่กว่าที่มีอยู่ในเครื่อง ระบบก็จะให้ผู้ใช้อัพเดท Google Apps ในเครื่องแทน

        ต่อไปก็กำหนด API Key สำหรับใช้งาน Google Maps โดยจะใส่เป็น Meta Data ใน Tag ของ <application> เช่นเดิม

<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="your_api_key"/>

        ตรง your_api_key ให้ใส่ API Key ที่ได้จาก Google Developer Console



        ต่อไปเพิ่ม Permission เข้าไปดังนี้

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


        • INTERNET ดาวน์โหลดแผนที่จาก Server

        • ACCESS_NETWORK_STATE ตรวจสอบสถานะการเชื่อมต่อของ Cellular Data ก่อนจะดาวน์โหลดแผนที่

        • ACCESS_WIFI_STATE ตรวจสอบสถานะการเชื่อมต่อของ WIFi ก่อนจะดาวน์โหลดแผนที่

        • WRITE_EXTERNAL_STORAGE เพื่อทำ Cache สำหรับข้อมูลแผนที่


        และจะมีเพิ่มอีกสองตัวเมื่อผู้ที่หลงเข้ามาอ่านเรียกใช้งานคำสั่งแสดงตำแหน่งปัจจุบันของผู้ใช้บน Google Maps แต่ถ้าไม่ได้ใช้งานก็ไม่จำเป็นต้องใส่ก็ได้ โดยให้เลือกอย่างใดอย่างหนึ่งก็พอ ขึ้นอยู่กับผู้ที่หลงเข้ามาอ่านว่าต้องการความแม่นยำในการระบุตำแหน่งของผู้ใช้มากน้อยแค่ไหน

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>


        • ACCESS_COARSE_LOCATION ใช้ Cellular Data หรือ WiFi เพื่อหาตำแหน่งของผู้ใช้แบบคร่าวๆ ตำแหน่งที่ได้จะไม่มีความแม่นยำมากนัก

        • ACCESS_FINE_LOCATION ใช้ GPS เพื่อหาตำแหน่งของผู้ใช้ให้แม่นยำที่สุดเท่าที่ทำได้


        เนื่องจาก Google Maps ใช้ OpenGL ES 2.0 ในการแสดงผลแผนที่ ดังนั้นจะต้องเพิ่ม Tag เพื่อใช้งาน OpenGL ES 2.0 ดังนี้

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



        สรุปคำสั่งที่เพิ่มใน AndroidManifest.xml

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.akexorcist.awesomeapp" >

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

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

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="AIzaSyATpwzatTxul5iuHePBDKbOngxGg2F8Y"/>

    </application>

</manifest>


เพิ่ม Google Maps ในแอปพลิเคชัน

        การเพิ่ม Google Maps ลงในแอปจะมีด้วยกันสองวิธี ขึ้นอยู่กับความต้องการของผู้ที่หลงเข้ามาอ่าน โดย Google Maps จะแสดงผลอยู่บน Fragment อีกทีหนึ่ง นั่นก็หมายความว่าการแสดงผล Google Maps เป็นการเรียกใช้งาน Fragment สำหรับ Google Maps นั่นเอง

        เมื่อพูดถึงเรื่อง Fragment ก็จะมี Fragment อยู่สองแบบด้วยกัน คือ

        • android.app.Fragment (> API 11) ขอเรียกว่า Fragment ปกติ

        • android.support.v4.app.Fragment (> API 4) ขอเรียกว่า Support Fragment

        ในกรณีที่สร้างแอปสำหรับ API 11 ขึ้นไปก็ใช้ Fragment ปกติก็เพียงพอแล้ว แต่ถ้าอยากให้รองรับในเวอร์ชันก่อนหน้าด้วยก็จะต้องใช้ Support Fragment

        ซึ่ง Google Maps ก็เช่นกัน เพราะสร้างอยู่บน Fragment อีกที ดังนั้นคลาส Fragment สำหรับ Google Maps ก็จะมีด้วยกันสองแบบ

        • com.google.android.gms.maps.MapFragment (> API 11)

        • com.google.android.gms.maps.SupportMapFragment (> API 4)

        ถ้าใช้กับ API 11 ขึ้นไปก็สามารถเรียกใช้งานผ่านคลาส MapFragment ได้ทันที แต่ถ้าแอปรองรับกับเวอร์ชันเก่าๆด้วยก็จะต้องเรียกใช้งานผ่าน SupportMapFragment แทน

        แต่ทว่าเวลาเรียกใช้งาน Google Maps ผ่านโค๊ดนั้นไม่ได้เรียกสั่งงานจาก MapFragment หรือ SupportMapFragment แต่อย่างใด แต่จะมีคลาสที่ชื่อว่า GoogleMap ให้เรียกใช้งานแทน ส่วน MapFragment กับ SupportMapFragment จะมีไว้ตอนที่เพิ่ม Google Maps ลงในแอปพลิเคชันเท่านั้น

        กลับมาที่สองวิธีในการเพิ่ม Google Maps ลงในแอปพลิเคชัน จะมีดังนี้

วิธีที่ 1 เพิ่ม Google Maps ลงไปโดยตรงใน Layout XML

        วิธีนี้ค่อนข้างง่าย เพราะเป็นการประกาศลงไปตรงๆใน Layout XML และยุ่งกับ Fragment ในโค๊ดแค่นิดเดียว

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:name="com.google.android.gms.maps.MapFragment"
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

        อย่าลืมว่านี่คือ MapFragment เพราะฉะนั้นถ้าจะใช้ SupportMapFragment ก็แก้ไขให้ถูกต้องด้วย

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

        และเวลาเรียกใช้งานในโค๊ดก็จะเรียกใช้งานแบบนี้

MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);

        ถ้าเป็น SupportMapFragment ก็จะเป็นแบบนี้

SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);


        ให้สังเกตที่คำสั่ง getMapAync คำสั่งนี้ใช้สำหรับเตรียม Google Maps ให้พร้อมใช้งาน โดยจะทำงานแบบ Asynchronous ที่จะมี Callback ให้ด้วย ซึ่งมีรูปแบบคำสั่งดังนี้

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {

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

        MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        // Do something with Google Map
    }
}

        Callback ที่ว่าก็คือ OnMapReadyCallback ที่จะทำงานเมื่อ Google Maps พร้อมใช้งานแล้ว โดยจะส่ง Instance ของ Google Maps มาให้ใช้งานได้เลย ดังนั้นผู้ที่หลงเข้ามาอ่านก็กำหนดค่าให้กับ Google Maps ที่ตรงนี้ได้เลย

        แนะนำเพิ่มเติม สำหรับผู้ที่หลงเข้ามาอ่านคนใดที่ต้องการให้มี View อื่นๆอยู่บน Layout หน้านั้นด้วย ก็ให้ย้าย <fragment> ไปไว้อยู่ใน View Group ตัวไหนก็ได้อีกทีหนึ่ง

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

        ถ้าอยากให้มี View ซ้อนอยู่บน Google Maps ก็ใช้เป็น Relative Layout ได้เลย

วิธีที่ 2 เพิ่ม Google Maps แบบเดียวกับ Fragment ทั่วไป

        วิธีนี้จะเป็นการเรียก MapFragment หรือ SupportMapFragment ขึ้นมาแล้วยัดลงใน View Group ใดๆก็ตามผ่านโค๊ดคำสั่ง ดังนั้นจึงสามารถเพิ่ม Google Maps ลงไปใน View Group ใดๆก็ได้ ซึ่งจะต่างจากวิธีแรกที่ใช้วิธีการประกาศเป็น Fragment ไว้ตั้งแต่แรกใน Layout XML

        เจ้าของบล็อกก็ลองสร้าง Frame Layout ขึ้นมาเพื่อใช้แสดง Google Maps โดยตั้งชื่อ ID ว่า fragment_map_container

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/fragment_map_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

        จากนั้นก็ใช้คำสั่งเพิ่ม MapFragment หรือ SupportMapFragment ลงใน Frame Layout ตัวนี้ซะ

MapFragment mapFragment = MapFragment.newInstance();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.my_container, mapFragment);
fragmentTransaction.commit();

        ในการสร้าง Instance ของ MapFragment หรือ SupportMapFragment ขึ้นมา โดยที่ไม่ได้เตรียมไว้ใน Layout XML จะใช้คำสั่ง newInstances ได้เลย จากนั้นก็เอาไปเพิ่มลงใน Frame Layout จะใช้คำสั่ง add หรือ replace  ก็แล้วแต่ผู้ที่หลงเข้ามาอ่าน

        และการสร้าง Instance ของ Google Maps ก็จะทำแบบเดียวกับวิธีแรกเลย นั่นก็คือใช้คำสั่ง getMapAsync แบบนี้

import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;


public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {

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

        MapFragment mapFragment = MapFragment.newInstance();
        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        fragmentTransaction.add(R.id.fragment_map_container, mapFragment);
        fragmentTransaction.commit();
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        // Do something with Google Map
    }
}

        เพียงเท่านี้ก็สามารถเรียกใช้งาน Google Maps ได้ตามใจชอบแล้ว

ปัญหา Google Maps ไม่แสดง

        เจ้าของบล็อกเชื่อว่าคงมีผู้ที่หลงเข้ามาอ่านบางท่านที่ทำตามแล้วเจอปัญหา Google Maps ไม่แสดง โดยส่วนใหญ่แล้วจะเป็นปัญหาจาก API Key ที่ไม่ถูกต้อง และถ้าสังเกตดีๆใน LogCat เวลาที่ Google Maps มีปัญหาก็จะมีข้อความแจ้งเตือนใน LogCat ให้เห็นด้วย เช่น การใส่ API Key ไม่ถูกต้องก็จะขึ้น Authorization failure แบบนี้


        ก็ให้ไปเช็ค API Key ดีๆว่าตอนกำหนด SHA1 เป็นของ Keystore ตัวที่ใช้ Build Project หรือป่าว หรือถ้ามั่นใจว่าถูกแล้วจริงๆ ก็ให้ลง Regenerate Key ดูใหม่ก็ได้ โดยเปิดไปที่ Google Developer Console แล้วจะมีปุ่ม Regenerate key เพื่อสร้าง API Key ใหม่


        ระบบจะสร้าง API Key ตัวใหม่มาให้ และตัวเก่าจะถูกยกเลิกใน 24 ชั่วโมง


        จากนั้นก็รอซัก 2 นาที แล้วค่อยเอาไปกำหนดใหม่ในแอปพลิเคชันของผู้ที่หลงเข้ามาอ่าน แต่ถ้า Google Maps ยังไม่แสดงก็ให้ลองเช็คให้ดีๆนะครับว่ากำหนดค่า SHA1 กับ Package Name ถูกแล้วแน่นะ?

คนอื่นแอบเอา API Key ไปใช้ได้หรือไม่?

        จะเห็นว่าในการใช้ Google Maps นั้นต้องขอ API Key แล้วเอาไปใส่ใน Android Manifest นั่นก็หมายความว่าตัวแอปพลิเคชันนั้นจะถูก Decompile เพื่อล้วงเอา API Key ได้อย่างง่าย

        แต่ก็ไม่ต้องกังวลไป เพราะอย่าลืมว่า

        • API Key ได้มาจาก SHA1 ของ Keystore ที่ใช้ Export เป็น APK (ไม่ว่าจะ Debug หรือ Signed Keybstore)

        • API Key ได้มาจาก Package Name ของแอปพลิเคชัน

        ด้วยสองข้อนี้ ต่อให้เอา API Key ไปได้ แต่ถ้าไม่มี Keystore ของผู้ที่หลงเข้ามาอ่าน และ Package Name ของแอปพลิเคชันไม่เหมือนกัน ก็ใช้ไม่ได้อยู่ดี

        ดังนั้น Keystore จึงเป็นสิ่งสำคัญครับ รักษาไว้ให้ดี (Google Account ที่ใช้ Login ใน Google Developer Console ด้วย)


        สำหรับผู้ที่หลงเข้ามาอ่านคนใดต้องการโปรเจคตัวอย่างสามารถดาวน์โหลดได้จาก

        • Google Maps Simple [Google Drive]

        • Google Maps Simple [Sleeping For Less]




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium